diff --git a/src/audio.c b/src/audio.c index 4bdc5089..923ed9a2 100644 --- a/src/audio.c +++ b/src/audio.c @@ -80,7 +80,7 @@ #endif #include "external/mini_al.h" // mini_al audio library - // NOTE: Cannot be implement here because it conflicts with + // NOTE: Cannot be implement here because it conflicts with // Win32 APIs: Rectangle, CloseWindow(), ShowCursor(), PlaySoundA() #include // Required for: malloc(), free() @@ -132,12 +132,12 @@ // Types and Structures Definition //---------------------------------------------------------------------------------- -typedef enum { - MUSIC_AUDIO_OGG = 0, - MUSIC_AUDIO_FLAC, - MUSIC_AUDIO_MP3, - MUSIC_MODULE_XM, - MUSIC_MODULE_MOD +typedef enum { + MUSIC_AUDIO_OGG = 0, + MUSIC_AUDIO_FLAC, + MUSIC_AUDIO_MP3, + MUSIC_MODULE_XM, + MUSIC_MODULE_MOD } MusicContextType; // Music type (file streaming from memory) @@ -167,12 +167,12 @@ typedef struct MusicData { } MusicData; #if defined(AUDIO_STANDALONE) -typedef enum { - LOG_INFO = 0, - LOG_ERROR, - LOG_WARNING, - LOG_DEBUG, - LOG_OTHER +typedef enum { + LOG_INFO = 0, + LOG_ERROR, + LOG_WARNING, + LOG_DEBUG, + LOG_OTHER } TraceLogType; #endif @@ -214,7 +214,7 @@ typedef enum { AUDIO_BUFFER_USAGE_STATIC = 0, AUDIO_BUFFER_USAGE_STREAM } AudioB // Audio buffer structure // NOTE: Slightly different logic is used when feeding data to the playback device depending on whether or not data is streamed -typedef struct AudioBuffer AudioBuffer; +typedef struct AudioBuffer AudioBuffer; struct AudioBuffer { mal_dsp dsp; // Required for format conversion float volume; @@ -239,7 +239,7 @@ static bool isAudioInitialized = MAL_FALSE; static float masterVolume = 1.0f; // Audio buffers are tracked in a linked list -static AudioBuffer *firstAudioBuffer = NULL; +static AudioBuffer *firstAudioBuffer = NULL; static AudioBuffer *lastAudioBuffer = NULL; // mini_al functions declaration @@ -268,7 +268,7 @@ static void OnLog(mal_context *pContext, mal_device *pDevice, const char *messag { (void)pContext; (void)pDevice; - + TraceLog(LOG_ERROR, message); // All log messages from mini_al are errors } @@ -291,30 +291,30 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device *pDevice, mal_uint32 frameC if (!audioBuffer->playing || audioBuffer->paused) continue; mal_uint32 framesRead = 0; - for (;;) + for (;;) { - if (framesRead > frameCount) + if (framesRead > frameCount) { TraceLog(LOG_DEBUG, "Mixed too many frames from audio buffer"); 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; } mal_uint32 framesJustRead = (mal_uint32)mal_dsp_read(&audioBuffer->dsp, framesToReadRightNow, tempBuffer, audioBuffer->dsp.pUserData); - if (framesJustRead > 0) + if (framesJustRead > 0) { float *framesOut = (float *)pFramesOut + (framesRead*device.channels); float *framesIn = tempBuffer; @@ -325,16 +325,16 @@ 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 (framesJustRead < framesToReadRightNow) { - if (!audioBuffer->looping) + if (!audioBuffer->looping) { StopAudioBuffer(audioBuffer); break; - } - else + } + else { - // Should never get here, but just for safety, + // Should never get here, but just for safety, // move the cursor position back to the start and continue the loop. audioBuffer->frameCursorPos = 0; continue; @@ -342,13 +342,13 @@ 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. + // 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(&audioLock); return frameCount; // We always output the same number of frames that were originally requested. @@ -361,8 +361,8 @@ static mal_uint32 OnAudioBufferDSPRead(mal_dsp *pDSP, mal_uint32 frameCount, voi mal_uint32 subBufferSizeInFrames = audioBuffer->bufferSizeInFrames/2; mal_uint32 currentSubBufferIndex = audioBuffer->frameCursorPos/subBufferSizeInFrames; - - if (currentSubBufferIndex > 1) + + if (currentSubBufferIndex > 1) { TraceLog(LOG_DEBUG, "Frame cursor position moved too far forward in audio stream"); return 0; @@ -381,11 +381,11 @@ static mal_uint32 OnAudioBufferDSPRead(mal_dsp *pDSP, mal_uint32 frameCount, voi { // 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 (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC) { if (framesRead >= frameCount) break; - } - else + } + else { if (isSubBufferProcessed[currentSubBufferIndex]) break; } @@ -394,11 +394,11 @@ static mal_uint32 OnAudioBufferDSPRead(mal_dsp *pDSP, mal_uint32 frameCount, voi 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); @@ -412,7 +412,7 @@ static mal_uint32 OnAudioBufferDSPRead(mal_dsp *pDSP, mal_uint32 frameCount, voi 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; @@ -420,7 +420,7 @@ static mal_uint32 OnAudioBufferDSPRead(mal_dsp *pDSP, mal_uint32 frameCount, voi 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; @@ -430,7 +430,7 @@ static mal_uint32 OnAudioBufferDSPRead(mal_dsp *pDSP, mal_uint32 frameCount, voi // Zero-fill excess. mal_uint32 totalFramesRemaining = (frameCount - framesRead); - if (totalFramesRemaining > 0) + if (totalFramesRemaining > 0) { memset((unsigned char *)pFramesOut + (framesRead*frameSizeInBytes), 0, totalFramesRemaining*frameSizeInBytes); @@ -447,9 +447,9 @@ static mal_uint32 OnAudioBufferDSPRead(mal_dsp *pDSP, mal_uint32 frameCount, voi // NOTE: framesOut is both an input and an output. It will be initially filled with zeros outside of this function. static void MixAudioFrames(float *framesOut, const float *framesIn, mal_uint32 frameCount, float localVolume) { - for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) + for (mal_uint32 iFrame = 0; iFrame < frameCount; ++iFrame) { - for (mal_uint32 iChannel = 0; iChannel < device.channels; ++iChannel) + for (mal_uint32 iChannel = 0; iChannel < device.channels; ++iChannel) { float *frameOut = framesOut + (iFrame*device.channels); const float *frameIn = framesIn + (iFrame*device.channels); @@ -519,7 +519,7 @@ void InitAudioDevice(void) // Close the audio device for all contexts void CloseAudioDevice(void) { - if (!isAudioInitialized) + if (!isAudioInitialized) { TraceLog(LOG_WARNING, "Could not close audio device because it is not currently initialized"); return; @@ -543,7 +543,7 @@ void SetMasterVolume(float volume) { if (volume < 0.0f) volume = 0.0f; else if (volume > 1.0f) volume = 1.0f; - + masterVolume = volume; } @@ -574,7 +574,7 @@ AudioBuffer *CreateAudioBuffer(mal_format format, mal_uint32 channels, mal_uint3 dspConfig.pUserData = audioBuffer; dspConfig.allowDynamicSampleRate = MAL_TRUE; // <-- Required for pitch shifting. mal_result resultMAL = mal_dsp_init(&dspConfig, &audioBuffer->dsp); - if (resultMAL != MAL_SUCCESS) + if (resultMAL != MAL_SUCCESS) { TraceLog(LOG_ERROR, "CreateAudioBuffer() : Failed to create data conversion pipeline"); free(audioBuffer); @@ -716,10 +716,10 @@ void SetAudioBufferPitch(AudioBuffer *audioBuffer, float pitch) void TrackAudioBuffer(AudioBuffer *audioBuffer) { mal_mutex_lock(&audioLock); - + { if (firstAudioBuffer == NULL) firstAudioBuffer = audioBuffer; - else + else { lastAudioBuffer->next = audioBuffer; audioBuffer->prev = lastAudioBuffer; @@ -727,7 +727,7 @@ void TrackAudioBuffer(AudioBuffer *audioBuffer) lastAudioBuffer = audioBuffer; } - + mal_mutex_unlock(&audioLock); } @@ -735,7 +735,7 @@ void TrackAudioBuffer(AudioBuffer *audioBuffer) void UntrackAudioBuffer(AudioBuffer *audioBuffer) { mal_mutex_lock(&audioLock); - + { if (audioBuffer->prev == NULL) firstAudioBuffer = audioBuffer->next; else audioBuffer->prev->next = audioBuffer->next; @@ -746,7 +746,7 @@ void UntrackAudioBuffer(AudioBuffer *audioBuffer) audioBuffer->prev = NULL; audioBuffer->next = NULL; } - + mal_mutex_unlock(&audioLock); } @@ -816,7 +816,7 @@ Sound LoadSoundFromWave(Wave wave) { // 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. // @@ -861,7 +861,7 @@ void UnloadSound(Sound sound) void UpdateSound(Sound sound, const void *data, int samplesCount) { AudioBuffer *audioBuffer = (AudioBuffer *)sound.audioBuffer; - + if (audioBuffer == NULL) { TraceLog(LOG_ERROR, "UpdateSound() : Invalid sound - no audio buffer"); @@ -878,9 +878,9 @@ void UpdateSound(Sound sound, const void *data, int samplesCount) void ExportWave(Wave wave, const char *fileName) { bool success = false; - + if (IsFileExtension(fileName, ".wav")) success = SaveWAV(wave, fileName); - else if (IsFileExtension(fileName, ".raw")) + else if (IsFileExtension(fileName, ".raw")) { // Export raw sample data (without header) // NOTE: It's up to the user to track wave parameters @@ -888,7 +888,7 @@ void ExportWave(Wave wave, const char *fileName) success = fwrite(wave.data, wave.sampleCount*wave.channels*wave.sampleSize/8, 1, rawFile); fclose(rawFile); } - + if (success) TraceLog(LOG_INFO, "Wave exported successfully: %s", fileName); else TraceLog(LOG_WARNING, "Wave could not be exported."); } @@ -897,12 +897,12 @@ void ExportWave(Wave wave, const char *fileName) void ExportWaveAsCode(Wave wave, const char *fileName) { #define BYTES_TEXT_PER_LINE 20 - + char varFileName[256] = { 0 }; int dataSize = wave.sampleCount*wave.channels*wave.sampleSize/8; - + FILE *txtFile = fopen(fileName, "wt"); - + fprintf(txtFile, "\n//////////////////////////////////////////////////////////////////////////////////\n"); fprintf(txtFile, "// //\n"); fprintf(txtFile, "// WaveAsCode exporter v1.0 - Wave data exported as an array of bytes //\n"); @@ -917,7 +917,7 @@ void ExportWaveAsCode(Wave wave, const char *fileName) // Get file name from path and convert variable name to uppercase strcpy(varFileName, GetFileNameWithoutExt(fileName)); for (int i = 0; varFileName[i] != '\0'; i++) if (varFileName[i] >= 'a' && varFileName[i] <= 'z') { varFileName[i] = varFileName[i] - 32; } - + fprintf(txtFile, "// Wave data information\n"); fprintf(txtFile, "#define %s_SAMPLE_COUNT %i\n", varFileName, wave.sampleCount); fprintf(txtFile, "#define %s_SAMPLE_RATE %i\n", varFileName, wave.sampleRate); @@ -983,7 +983,7 @@ 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_uint32)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; @@ -992,7 +992,7 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) void *data = malloc(frameCount*channels*(sampleSize/8)); frameCount = (mal_uint32)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; @@ -1130,16 +1130,16 @@ Music LoadMusicStream(const char *fileName) TraceLog(LOG_INFO, "[%s] MP3 sample rate: %i", fileName, music->ctxMp3.sampleRate); TraceLog(LOG_INFO, "[%s] MP3 bits per sample: %i", fileName, 32); TraceLog(LOG_INFO, "[%s] MP3 channels: %i", fileName, music->ctxMp3.channels); - + music->stream = InitAudioStream(music->ctxMp3.sampleRate, 32, music->ctxMp3.channels); - + // TODO: There is not an easy way to compute the total number of samples available // in an MP3, frames size could be variable... we tried with a 60 seconds music... but crashes... music->totalSamples = drmp3_get_pcm_frame_count(&music->ctxMp3)*music->ctxMp3.channels; music->samplesLeft = music->totalSamples; music->ctxType = MUSIC_AUDIO_MP3; music->loopCount = -1; // Infinite loop by default - + TraceLog(LOG_INFO, "[%s] MP3 total samples: %i", fileName, music->totalSamples); } } @@ -1186,7 +1186,7 @@ Music LoadMusicStream(const char *fileName) } #endif else musicLoaded = false; - + if (!musicLoaded) { if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close(music->ctxOgg); @@ -1238,7 +1238,7 @@ void UnloadMusicStream(Music music) void PlayMusicStream(Music music) { AudioBuffer *audioBuffer = (AudioBuffer *)music->stream.audioBuffer; - + if (audioBuffer == NULL) { TraceLog(LOG_ERROR, "PlayMusicStream() : No audio buffer"); @@ -1250,7 +1250,7 @@ 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. audioBuffer->frameCursorPos = frameCursorPos; @@ -1273,7 +1273,7 @@ void ResumeMusicStream(Music music) void StopMusicStream(Music music) { StopAudioStream(music->stream); - + // Restart music context switch (music->ctxType) { @@ -1332,18 +1332,18 @@ void UpdateMusicStream(Music music) } break; #endif #if defined(SUPPORT_FILEFORMAT_MP3) - case MUSIC_AUDIO_MP3: + case MUSIC_AUDIO_MP3: { // NOTE: samplesCount, actually refers to framesCount and returns the number of frames processed - unsigned int numFramesMp3 = (unsigned int)drmp3_read_pcm_frames_f32(&music->ctxMp3, samplesCount/music->stream.channels, (float *)pcm); + drmp3_read_pcm_frames_f32(&music->ctxMp3, samplesCount/music->stream.channels, (float *)pcm); } break; #endif #if defined(SUPPORT_FILEFORMAT_XM) - case MUSIC_MODULE_XM: + case MUSIC_MODULE_XM: { // NOTE: Internally this function considers 2 channels generation, so samplesCount/2 --> WEIRD - jar_xm_generate_samples_16bit(music->ctxXm, (short *)pcm, samplesCount/2); + jar_xm_generate_samples_16bit(music->ctxXm, (short *)pcm, samplesCount/2); } break; #endif #if defined(SUPPORT_FILEFORMAT_MOD) @@ -1369,7 +1369,7 @@ void UpdateMusicStream(Music music) if (streamEnding) { StopMusicStream(music); // Stop music (and reset) - + // Decrease loopCount to stop when required if (music->loopCount > 0) { @@ -1475,7 +1475,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un void CloseAudioStream(AudioStream stream) { DeleteAudioBuffer((AudioBuffer *)stream.audioBuffer); - + TraceLog(LOG_INFO, "[AUD ID %i] Unloaded audio stream data", stream.source); } @@ -1494,7 +1494,7 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount) if (audioBuffer->isSubBufferProcessed[0] || audioBuffer->isSubBufferProcessed[1]) { mal_uint32 subBufferToUpdate; - + 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. @@ -1514,7 +1514,7 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount) if (subBufferSizeInFrames >= (mal_uint32)samplesCount/stream.channels) { mal_uint32 framesToWrite = subBufferSizeInFrames; - + if (framesToWrite > ((mal_uint32)samplesCount/stream.channels)) framesToWrite = (mal_uint32)samplesCount/stream.channels; mal_uint32 bytesToWrite = framesToWrite*stream.channels*(stream.sampleSize/8); @@ -1522,8 +1522,8 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount) // Any leftover frames should be filled with zeros. mal_uint32 leftoverFrameCount = subBufferSizeInFrames - framesToWrite; - - if (leftoverFrameCount > 0) + + if (leftoverFrameCount > 0) { memset(subBuffer + bytesToWrite, 0, leftoverFrameCount*stream.channels*(stream.sampleSize/8)); } @@ -1723,7 +1723,7 @@ static int SaveWAV(Wave wave, const char *fileName) { int success = 0; int dataSize = wave.sampleCount*wave.channels*wave.sampleSize/8; - + // Basic WAV headers structs typedef struct { char chunkID[4]; @@ -1748,7 +1748,7 @@ static int SaveWAV(Wave wave, const char *fileName) } WaveData; FILE *wavFile = fopen(fileName, "wb"); - + if (wavFile == NULL) TraceLog(LOG_WARNING, "[%s] WAV audio file could not be created", fileName); else { @@ -1784,7 +1784,7 @@ static int SaveWAV(Wave wave, const char *fileName) waveData.subChunkID[2] = 't'; waveData.subChunkID[3] = 'a'; waveData.subChunkSize = dataSize; - + success = fwrite(&riffHeader, sizeof(RiffHeader), 1, wavFile); success = fwrite(&waveFormat, sizeof(WaveFormat), 1, wavFile); success = fwrite(&waveData, sizeof(WaveData), 1, wavFile); @@ -1793,7 +1793,7 @@ static int SaveWAV(Wave wave, const char *fileName) fclose(wavFile); } - + // If all data has been written correctly to file, success = 1 return success; } @@ -1812,7 +1812,7 @@ static Wave LoadOGG(const char *fileName) else { stb_vorbis_info info = stb_vorbis_get_info(oggFile); - + wave.sampleRate = info.sample_rate; wave.sampleSize = 16; // 16 bit per sample (short) wave.channels = info.channels; @@ -1872,7 +1872,7 @@ static Wave LoadMP3(const char *fileName) uint64_t totalFrameCount = 0; drmp3_config config = { 0 }; wave.data = drmp3_open_file_and_read_f32(fileName, &config, &totalFrameCount); - + wave.channels = config.outputChannels; wave.sampleRate = config.outputSampleRate; wave.sampleCount = (int)totalFrameCount*wave.channels; @@ -1895,7 +1895,7 @@ bool IsFileExtension(const char *fileName, const char *ext) { bool result = false; const char *fileExt; - + if ((fileExt = strrchr(fileName, '.')) != NULL) { if (strcmp(fileExt, ext) == 0) result = true; diff --git a/src/config.h b/src/config.h index 7992f5b3..bec0c5fc 100644 --- a/src/config.h +++ b/src/config.h @@ -45,7 +45,7 @@ // Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used #define SUPPORT_BUSY_WAIT_LOOP 1 // Wait for events passively (sleeping while no events) instead of polling them actively every frame -//SUPPORT_EVENTS_WAITING 1 +//#define SUPPORT_EVENTS_WAITING 1 // Allow automatic screen capture of current screen pressing F12, defined in KeyCallback() #define SUPPORT_SCREEN_CAPTURE 1 // Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback() diff --git a/src/core.c b/src/core.c index b2cb1813..5f12fb72 100644 --- a/src/core.c +++ b/src/core.c @@ -2,12 +2,12 @@ * * raylib.core - Basic functions to manage windows, OpenGL context and input on multiple platforms * -* PLATFORMS SUPPORTED: +* PLATFORMS SUPPORTED: * - PLATFORM_DESKTOP: Windows (Win32, Win64) * - PLATFORM_DESKTOP: Linux (X11 desktop mode) * - PLATFORM_DESKTOP: FreeBSD, OpenBSD, NetBSD, DragonFly (X11 desktop) * - PLATFORM_DESKTOP: OSX/macOS -* - PLATFORM_ANDROID: Android 4.0 (ARM, ARM64) +* - PLATFORM_ANDROID: Android 4.0 (ARM, ARM64) * - PLATFORM_RPI: Raspberry Pi 0,1,2,3 (Raspbian) * - PLATFORM_WEB: HTML5 with asm.js (Chrome, Firefox) * - PLATFORM_UWP: Windows 10 App, Windows Phone, Xbox One @@ -23,7 +23,7 @@ * 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 i native mode (no X.org required, tested on Raspbian), +* 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 @@ -155,7 +155,7 @@ #if defined(_WIN32) #define GLFW_EXPOSE_NATIVE_WIN32 #include // WARNING: It requires customization to avoid windows.h inclusion! - + #if !defined(SUPPORT_BUSY_WAIT_LOOP) // NOTE: Those functions require linking with winmm library unsigned int __stdcall timeBeginPeriod(unsigned int uPeriod); @@ -164,7 +164,7 @@ #elif defined(__linux__) #include // Required for: timespec, nanosleep(), select() - POSIX - + //#define GLFW_EXPOSE_NATIVE_X11 // WARNING: Exposing Xlib.h > X.h results in dup symbols for Font type //#define GLFW_EXPOSE_NATIVE_WAYLAND //#define GLFW_EXPOSE_NATIVE_MIR @@ -172,7 +172,7 @@ #elif defined(__APPLE__) #include // Required for: usleep() #include // Required for: objc_msgsend(), sel_registerName() - + //#define GLFW_EXPOSE_NATIVE_COCOA // WARNING: Fails due to type redefinition #define GLFW_EXPOSE_NATIVE_NSGL #include // Required for: glfwGetCocoaWindow(), glfwGetNSGLContext() @@ -225,7 +225,7 @@ #define GLFW_INCLUDE_ES2 // GLFW3: Enable OpenGL ES 2.0 (translated to WebGL) #include // GLFW3 library: Windows, OpenGL context and Input management #include // Required for: timespec, nanosleep(), select() - POSIX - + #include // Emscripten library - LLVM to JavaScript compiler #include // Emscripten HTML5 library #endif @@ -492,7 +492,7 @@ static void *GamepadThread(void *arg); // Mouse reading thread //---------------------------------------------------------------------------------- #if defined(PLATFORM_ANDROID) -// To allow easier porting to android, we allow the user to define a +// To allow easier porting to android, we allow the user to define a // main function which we call from android_main, defined by ourselves extern int main(int argc, char *argv[]); @@ -596,10 +596,10 @@ void InitWindow(int width, int height, const char *title) #if defined(PLATFORM_WEB) emscripten_set_fullscreenchange_callback(0, 0, 1, EmscriptenFullscreenChangeCallback); - + // Support keyboard events emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback); - + // Support mouse events emscripten_set_click_callback("#canvas", NULL, 1, EmscriptenMouseCallback); @@ -638,7 +638,7 @@ void CloseWindow(void) gifRecording = false; } #endif - + #if defined(SUPPORT_DEFAULT_FONT) UnloadDefaultFont(); #endif @@ -715,7 +715,7 @@ bool WindowShouldClose(void) emscripten_sleep(16); return false; #endif - + #if defined(PLATFORM_DESKTOP) if (windowReady) { @@ -766,7 +766,7 @@ void SetWindowIcon(Image image) ImageFormat(&image, UNCOMPRESSED_R8G8B8A8); GLFWimage icon[1]; - + icon[0].width = image.width; icon[0].height = image.height; icon[0].pixels = (unsigned char *)image.data; @@ -800,8 +800,8 @@ void SetWindowMonitor(int monitor) #if defined(PLATFORM_DESKTOP) int monitorCount; GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); - - if ((monitor >= 0) && (monitor < monitorCount)) + + if ((monitor >= 0) && (monitor < monitorCount)) { //glfwSetWindowMonitor(window, monitors[monitor], 0, 0, screenWidth, screenHeight, GLFW_DONT_CARE); TraceLog(LOG_INFO, "Selected fullscreen monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor])); @@ -873,12 +873,12 @@ int GetMonitorCount(void) // Get primary monitor width int GetMonitorWidth(int monitor) -{ +{ #if defined(PLATFORM_DESKTOP) int monitorCount; GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); - - if ((monitor >= 0) && (monitor < monitorCount)) + + if ((monitor >= 0) && (monitor < monitorCount)) { const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]); return mode->width; @@ -890,12 +890,12 @@ int GetMonitorWidth(int monitor) // Get primary monitor width int GetMonitorHeight(int monitor) -{ +{ #if defined(PLATFORM_DESKTOP) int monitorCount; GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); - - if ((monitor >= 0) && (monitor < monitorCount)) + + if ((monitor >= 0) && (monitor < monitorCount)) { const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]); return mode->height; @@ -911,8 +911,8 @@ int GetMonitorPhysicalWidth(int monitor) #if defined(PLATFORM_DESKTOP) int monitorCount; GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); - - if ((monitor >= 0) && (monitor < monitorCount)) + + if ((monitor >= 0) && (monitor < monitorCount)) { int physicalWidth; glfwGetMonitorPhysicalSize(monitors[monitor], &physicalWidth, NULL); @@ -929,8 +929,8 @@ int GetMonitorPhysicalHeight(int monitor) #if defined(PLATFORM_DESKTOP) int monitorCount; GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); - - if ((monitor >= 0) && (monitor < monitorCount)) + + if ((monitor >= 0) && (monitor < monitorCount)) { int physicalHeight; glfwGetMonitorPhysicalSize(monitors[monitor], NULL, &physicalHeight); @@ -944,11 +944,11 @@ int GetMonitorPhysicalHeight(int monitor) // Get the human-readable, UTF-8 encoded name of the primary monitor const char *GetMonitorName(int monitor) { -#if defined(PLATFORM_DESKTOP) +#if defined(PLATFORM_DESKTOP) int monitorCount; GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); - - if ((monitor >= 0) && (monitor < monitorCount)) + + if ((monitor >= 0) && (monitor < monitorCount)) { return glfwGetMonitorName(monitors[monitor]); } @@ -1038,7 +1038,7 @@ void EndDrawing(void) if (gifRecording) { gifFramesCounter++; - + // NOTE: We record one gif frame every 10 game frames if ((gifFramesCounter%GIF_RECORD_FRAMERATE) == 0) { @@ -1046,20 +1046,20 @@ void EndDrawing(void) // NOTE: This process is very slow... :( unsigned char *screenData = rlReadScreenPixels(screenWidth, screenHeight); GifWriteFrame(screenData, screenWidth, screenHeight, 10, 8, false); - + free(screenData); // Free image data } - + if (((gifFramesCounter/15)%2) == 1) { DrawCircle(30, screenHeight - 20, 10, RED); DrawText("RECORDING", 50, screenHeight - 25, 10, MAROON); } - + rlglDraw(); // Draw RECORDING message } #endif - + SwapBuffers(); // Copy back buffer to front buffer PollInputEvents(); // Poll user events @@ -1067,7 +1067,7 @@ void EndDrawing(void) currentTime = GetTime(); drawTime = currentTime - previousTime; previousTime = currentTime; - + frameTime = updateTime + drawTime; // Wait for some milliseconds... @@ -1113,14 +1113,14 @@ void EndMode2D(void) void BeginMode3D(Camera3D camera) { rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) - + rlMatrixMode(RL_PROJECTION); // Switch to projection matrix rlPushMatrix(); // Save previous matrix, which contains the settings for the 2d ortho projection rlLoadIdentity(); // Reset current matrix (PROJECTION) float aspect = (float)screenWidth/(float)screenHeight; - if (camera.type == CAMERA_PERSPECTIVE) + if (camera.type == CAMERA_PERSPECTIVE) { // Setup perspective projection double top = 0.01*tan(camera.fovy*0.5*DEG2RAD); @@ -1169,7 +1169,7 @@ void BeginTextureMode(RenderTexture2D target) rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) rlEnableRenderTexture(target.id); // Enable render target - + rlClearScreenBuffers(); // Clear render texture buffers // Set viewport to framebuffer size @@ -1230,7 +1230,7 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera) Matrix matProj = MatrixIdentity(); - if (camera.type == CAMERA_PERSPECTIVE) + if (camera.type == CAMERA_PERSPECTIVE) { // Calculate projection matrix from perspective matProj = MatrixPerspective(camera.fovy*DEG2RAD, ((double)GetScreenWidth()/(double)GetScreenHeight()), 0.01, 1000.0); @@ -1240,7 +1240,7 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera) float aspect = (float)screenWidth/(float)screenHeight; double top = camera.fovy/2.0; double right = top*aspect; - + // Calculate projection matrix from orthographic matProj = MatrixOrtho(-right, right, -top, top, 0.01, 1000.0); } @@ -1250,7 +1250,7 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera) Vector3 farPoint = rlUnproject((Vector3){ deviceCoords.x, deviceCoords.y, 1.0f }, matProj, matView); // Unproject the mouse cursor in the near plane. - // We need this as the source position because orthographic projects, compared to perspect doesn't have a + // We need this as the source position because orthographic projects, compared to perspect doesn't have a // convergence point, meaning that the "eye" of the camera is more like a plane than a point. Vector3 cameraPlanePointerPos = rlUnproject((Vector3){ deviceCoords.x, deviceCoords.y, -1.0f }, matProj, matView); @@ -1282,7 +1282,7 @@ Vector2 GetWorldToScreen(Vector3 position, Camera camera) float aspect = (float)screenWidth/(float)screenHeight; double top = camera.fovy/2.0; double right = top*aspect; - + // Calculate projection matrix from orthographic matProj = MatrixOrtho(-right, right, -top, top, 0.01, 1000.0); } @@ -1369,7 +1369,7 @@ Vector4 ColorNormalize(Color color) result.y = (float)color.g/255.0f; result.z = (float)color.b/255.0f; result.w = (float)color.a/255.0f; - + return result; } @@ -1389,27 +1389,27 @@ Vector3 ColorToHSV(Color color) hsv.z = max; // Value delta = max - min; - + if (delta < 0.00001f) { hsv.y = 0.0f; hsv.x = 0.0f; // Undefined, maybe NAN? return hsv; } - - if (max > 0.0f) + + if (max > 0.0f) { // NOTE: If max is 0, this divide would cause a crash hsv.y = (delta/max); // Saturation - } - else + } + else { // NOTE: If max is 0, then r = g = b = 0, s = 0, h is undefined hsv.y = 0.0f; hsv.x = NAN; // Undefined return hsv; } - + // NOTE: Comparing float values could not work properly if (rgb.x >= max) hsv.x = (rgb.y - rgb.z)/delta; // Between yellow & magenta else @@ -1417,7 +1417,7 @@ Vector3 ColorToHSV(Color color) if (rgb.y >= max) hsv.x = 2.0f + (rgb.z - rgb.x)/delta; // Between cyan & yellow else hsv.x = 4.0f + (rgb.x - rgb.y)/delta; // Between magenta & cyan } - + hsv.x *= 60.0f; // Convert to degrees if (hsv.x < 0.0f) hsv.x += 360.0f; @@ -1519,7 +1519,7 @@ bool IsFileExtension(const char *fileName, const char *ext) #if defined(_WIN32) result = true; int extLen = strlen(ext); - + if (strlen(fileExt) == extLen) { for (int i = 0; i < extLen; i++) @@ -1544,9 +1544,9 @@ bool IsFileExtension(const char *fileName, const char *ext) const char *GetExtension(const char *fileName) { const char *dot = strrchr(fileName, '.'); - + if (!dot || dot == fileName) return NULL; - + return (dot + 1); } @@ -1572,19 +1572,19 @@ const char *GetFileName(const char *filePath) const char *GetFileNameWithoutExt(const char *filePath) { char *result, *lastDot, *lastSep; - + char nameDot = '.'; // Default filename to extension separator character char pathSep = '/'; // Default filepath separator character // Error checks and allocate string if (filePath == NULL) return NULL; - + // Try to allocate new string, same size as original // NOTE: By default strlen() does not count the '\0' character if ((result = malloc(strlen(filePath) + 1)) == NULL) return NULL; - + strcpy(result, filePath); // Make a copy of the string - + // NOTE: strrchr() returns a pointer to the last occurrence of character lastDot = strrchr(result, nameDot); lastSep = (pathSep == 0) ? NULL : strrchr(result, pathSep); @@ -1593,11 +1593,11 @@ const char *GetFileNameWithoutExt(const char *filePath) { if (lastSep != NULL) // ...and it's before the extenstion separator... { - if (lastSep < lastDot) + if (lastSep < lastDot) { *lastDot = '\0'; // ...then remove it } - } + } else *lastDot = '\0'; // Has extension separator with no path separator } @@ -1626,9 +1626,9 @@ const char *GetWorkingDirectory(void) { static char currentDir[MAX_FILEPATH_LENGTH]; memset(currentDir, 0, MAX_FILEPATH_LENGTH); - + GETCWD(currentDir, MAX_FILEPATH_LENGTH - 1); - + return currentDir; } @@ -1637,36 +1637,36 @@ const char *GetWorkingDirectory(void) char **GetDirectoryFiles(const char *dirPath, int *fileCount) { #define MAX_DIRECTORY_FILES 512 - + ClearDirectoryFiles(); // Memory allocation for MAX_DIRECTORY_FILES dirFilesPath = (char **)malloc(sizeof(char *)*MAX_DIRECTORY_FILES); - for (int i = 0; i < MAX_DIRECTORY_FILES; i++) dirFilesPath[i] = (char *)malloc(sizeof(char)*MAX_FILEPATH_LENGTH); - + for (int i = 0; i < MAX_DIRECTORY_FILES; i++) dirFilesPath[i] = (char *)malloc(sizeof(char)*MAX_FILEPATH_LENGTH); + int counter = 0; struct dirent *ent; DIR *dir = opendir(dirPath); - + if (dir != NULL) // It's a directory { - // TODO: Reading could be done in two passes, + // TODO: Reading could be done in two passes, // first one to count files and second one to read names // That way we can allocate required memory, instead of a limited pool - + while ((ent = readdir(dir)) != NULL) { strcpy(dirFilesPath[counter], ent->d_name); counter++; } - + closedir(dir); } else TraceLog(LOG_WARNING, "Can not open directory...\n"); // Maybe it's a file... dirFilesCount = counter; *fileCount = dirFilesCount; - + return dirFilesPath; } @@ -1729,14 +1729,14 @@ void ClearDroppedFiles(void) RLAPI long GetFileModTime(const char *fileName) { struct stat result = { 0 }; - + if (stat(fileName, &result) == 0) { time_t mod = result.st_mtime; - + return (long)mod; } - + return 0; } @@ -2011,7 +2011,7 @@ bool IsMouseButtonPressed(int button) #else if ((currentMouseState[button] != previousMouseState[button]) && (currentMouseState[button] == 1)) pressed = true; #endif - + return pressed; } @@ -2259,7 +2259,7 @@ static bool InitGraphicsDevice(int width, int height) glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Choose OpenGL major version (just hint) glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Choose OpenGL minor version (just hint) glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Profiles Hint: Only 3.3 and above! - // Other values: GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_COMPAT_PROFILE + // Values: GLFW_OPENGL_CORE_PROFILE, GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_COMPAT_PROFILE #if defined(__APPLE__) glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // OSX Requires fordward compatibility #else @@ -2357,10 +2357,10 @@ static bool InitGraphicsDevice(int width, int height) #endif glfwMakeContextCurrent(window); - + // Try to disable GPU V-Sync by default, set framerate using SetTargetFPS() // NOTE: V-Sync can be enabled by graphic driver configuration - glfwSwapInterval(0); + glfwSwapInterval(0); #if defined(PLATFORM_DESKTOP) // Load OpenGL 3.3 extensions @@ -2372,6 +2372,7 @@ static bool InitGraphicsDevice(int width, int height) // NOTE: V-Sync can be enabled by graphic driver configuration if (configFlags & FLAG_VSYNC_HINT) { + // WARNING: It seems to hits a critical render path in Intel HD Graphics glfwSwapInterval(1); TraceLog(LOG_INFO, "Trying to enable VSYNC"); } @@ -2444,14 +2445,14 @@ static bool InitGraphicsDevice(int width, int height) // EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER is an optimization that can have large performance benefits on mobile devices. // Its syntax is subject to change, though. Please update your Visual Studio templates if you experience compilation issues with it. EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE, - - // EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that enables ANGLE to automatically call - // the IDXGIDevice3::Trim method on behalf of the application when it gets suspended. + + // EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that enables ANGLE to automatically call + // the IDXGIDevice3::Trim method on behalf of the application when it gets suspended. // Calling IDXGIDevice3::Trim when an application is suspended is a Windows Store application certification requirement. EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE, EGL_NONE, }; - + const EGLint fl9_3DisplayAttributes[] = { // These can be used to request ANGLE's D3D11 renderer, with D3D11 Feature Level 9_3. @@ -2474,7 +2475,7 @@ static bool InitGraphicsDevice(int width, int height) EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE, EGL_NONE, }; - + EGLConfig config = NULL; // eglGetPlatformDisplayEXT is an alternative to eglGetDisplay. It allows us to pass in display attributes, used to configure D3D11. @@ -2486,15 +2487,15 @@ static bool InitGraphicsDevice(int width, int height) } // - // To initialize the display, we make three sets of calls to eglGetPlatformDisplayEXT and eglInitialize, with varying + // To initialize the display, we make three sets of calls to eglGetPlatformDisplayEXT and eglInitialize, with varying // parameters passed to eglGetPlatformDisplayEXT: // 1) The first calls uses "defaultDisplayAttributes" as a parameter. This corresponds to D3D11 Feature Level 10_0+. - // 2) If eglInitialize fails for step 1 (e.g. because 10_0+ isn't supported by the default GPU), then we try again + // 2) If eglInitialize fails for step 1 (e.g. because 10_0+ isn't supported by the default GPU), then we try again // using "fl9_3DisplayAttributes". This corresponds to D3D11 Feature Level 9_3. - // 3) If eglInitialize fails for step 2 (e.g. because 9_3+ isn't supported by the default GPU), then we try again + // 3) If eglInitialize fails for step 2 (e.g. because 9_3+ isn't supported by the default GPU), then we try again // using "warpDisplayAttributes". This corresponds to D3D11 Feature Level 11_0 on WARP, a D3D11 software rasterizer. // - + // This tries to initialize EGL to D3D11 Feature Level 10_0+. See above comment for details. display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes); if (display == EGL_NO_DISPLAY) @@ -2502,7 +2503,7 @@ static bool InitGraphicsDevice(int width, int height) TraceLog(LOG_WARNING, "Failed to initialize EGL display"); return false; } - + if (eglInitialize(display, NULL, NULL) == EGL_FALSE) { // This tries to initialize EGL to D3D11 Feature Level 9_3, if 10_0+ is unavailable (e.g. on some mobile devices). @@ -2517,7 +2518,7 @@ static bool InitGraphicsDevice(int width, int height) { // This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is unavailable on the default GPU. display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes); - if (display == EGL_NO_DISPLAY) + if (display == EGL_NO_DISPLAY) { TraceLog(LOG_WARNING, "Failed to initialize EGL display"); return false; @@ -2545,7 +2546,7 @@ static bool InitGraphicsDevice(int width, int height) //PropertySet^ surfaceCreationProperties = ref new PropertySet(); //surfaceCreationProperties->Insert(ref new String(EGLNativeWindowTypeProperty), window); // CoreWindow^ window - // You can configure the surface to render at a lower resolution and be scaled up to + // You can configure the surface to render at a lower resolution and be scaled up to // the full window size. The scaling is often free on mobile hardware. // // One way to configure the SwapChainPanel is to specify precisely which resolution it should render at. @@ -2557,20 +2558,20 @@ static bool InitGraphicsDevice(int width, int height) // float customResolutionScale = 0.5f; // surfaceCreationProperties->Insert(ref new String(EGLRenderResolutionScaleProperty), PropertyValue::CreateSingle(customResolutionScale)); - - // eglCreateWindowSurface() requires a EGLNativeWindowType parameter, + + // eglCreateWindowSurface() requires a EGLNativeWindowType parameter, // In Windows platform: typedef HWND EGLNativeWindowType; - - + + // Property: EGLNativeWindowTypeProperty // Type: IInspectable // Description: Set this property to specify the window type to use for creating a surface. // If this property is missing, surface creation will fail. // //const wchar_t EGLNativeWindowTypeProperty[] = L"EGLNativeWindowTypeProperty"; - + //https://stackoverflow.com/questions/46550182/how-to-create-eglsurface-using-c-winrt-and-angle - + //surface = eglCreateWindowSurface(display, config, reinterpret_cast(surfaceCreationProperties), surfaceAttributes); surface = eglCreateWindowSurface(display, config, uwpWindow, surfaceAttributes); if (surface == EGL_NO_SURFACE) @@ -2586,16 +2587,16 @@ static bool InitGraphicsDevice(int width, int height) return false; } - // Get EGL display window size + // Get EGL display window size eglQuerySurface(display, surface, EGL_WIDTH, &screenWidth); eglQuerySurface(display, surface, EGL_HEIGHT, &screenHeight); - + #else // PLATFORM_ANDROID, PLATFORM_RPI EGLint numConfigs; // Get an EGL display connection display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (display == EGL_NO_DISPLAY) + if (display == EGL_NO_DISPLAY) { TraceLog(LOG_WARNING, "Failed to initialize EGL display"); return false; @@ -2828,7 +2829,7 @@ static void SetupFramebuffer(int width, int height) static void InitTimer(void) { srand((unsigned int)time(NULL)); // Initialize random seed - + #if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32) timeBeginPeriod(1); // Setup high-resolution timer to 1ms (granularity of 1-2 ms) #endif @@ -2931,7 +2932,7 @@ static void PollInputEvents(void) // Register previous mouse states previousMouseWheelY = currentMouseWheelY; currentMouseWheelY = 0; - for (int i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) { previousMouseState[i] = currentMouseState[i]; currentMouseState[i] = currentMouseStateEvdev[i]; @@ -3097,11 +3098,11 @@ static void SwapBuffers(void) glfwSwapBuffers(window); #if __APPLE__ // Workaround for missing/erroneous initial rendering on macOS - if (windowNeedsUpdating) + if (windowNeedsUpdating) { // Desugared version of Objective C: [glfwGetNSGLContext(window) update] ((id (*)(id, SEL))objc_msgSend)(glfwGetNSGLContext(window), sel_registerName("update")); - + windowNeedsUpdating--; } #endif @@ -3144,19 +3145,19 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i { GifEnd(); gifRecording = false; - + TraceLog(LOG_INFO, "End animated GIF recording"); } - else + else { gifRecording = true; gifFramesCounter = 0; - + // NOTE: delay represents the time between frames in the gif, if we capture a gif frame every // 10 game frames and each frame trakes 16.6ms (60fps), delay between gif frames should be ~16.6*10. GifBegin(FormatText("screenrec%03i.gif", screenshotCounter), screenWidth, screenHeight, (int)(GetFrameTime()*10.0f), 8, false); screenshotCounter++; - + TraceLog(LOG_INFO, "Begin animated GIF recording: %s", FormatText("screenrec%03i.gif", screenshotCounter)); } } @@ -3173,7 +3174,7 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i else { currentKeyState[key] = action; - + // NOTE: lastKeyPressed already registered on CharCallback() //if (action == GLFW_PRESS) lastKeyPressed = key; } @@ -3243,12 +3244,12 @@ static void MouseCursorPosCallback(GLFWwindow *window, double x, double y) // 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; } @@ -3349,7 +3350,7 @@ 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(); @@ -3457,15 +3458,15 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) // Get second touch position touchPosition[1].x = AMotionEvent_getX(event, 1); touchPosition[1].y = AMotionEvent_getY(event, 1); - + // Useful functions for gamepad inputs: //AMotionEvent_getAction() //AMotionEvent_getAxisValue() //AMotionEvent_getButtonState() - + // Gamepad dpad button presses capturing // TODO: That's weird, key input (or button) - // shouldn't come as a TYPE_MOTION event... + // shouldn't come as a TYPE_MOTION event... int32_t keycode = AKeyEvent_getKeyCode(event); if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN) { @@ -3541,7 +3542,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) // Normalize gestureEvent.position[x] for screenWidth and screenHeight gestureEvent.position[0].x /= (float)GetScreenWidth(); gestureEvent.position[0].y /= (float)GetScreenHeight(); - + gestureEvent.position[1].x /= (float)GetScreenWidth(); gestureEvent.position[1].y /= (float)GetScreenHeight(); @@ -3549,14 +3550,14 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) ProcessGestureEvent(gestureEvent); } #else - + // Support only simple touch position if (flags == AMOTION_EVENT_ACTION_DOWN) { // Get first touch position touchPosition[0].x = AMotionEvent_getX(event, 0); touchPosition[0].y = AMotionEvent_getY(event, 0); - + touchPosition[0].x /= (float)GetScreenWidth(); touchPosition[0].y /= (float)GetScreenHeight(); } @@ -3619,10 +3620,10 @@ static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent emscripten_get_pointerlock_status(&plce); //if (plce.isActive) TraceLog(LOG_WARNING, "Pointer lock exit did not work!"); } - + toggleCursorLock = false; } - + return 0; } @@ -3889,9 +3890,9 @@ static void InitMouse(void) // Open the linux directory of "/dev/input" directory = opendir(DEFAULT_EVDEV_PATH); - if (directory) + if (directory) { - while ((entity = readdir(directory)) != NULL) + while ((entity = readdir(directory)) != NULL) { if (strncmp("event", entity->d_name, strlen("event")) == 0) // Search for devices named "event*" { @@ -3899,7 +3900,7 @@ static void InitMouse(void) EventThreadSpawn(Path); // Identify the device and spawn a thread for it } } - + closedir(directory); } else @@ -3916,7 +3917,7 @@ static void EventThreadSpawn(char *device) #define BIT(x) (1UL<> OFF(bit)) & 1) - + struct input_absinfo absinfo; unsigned long evBits[NBITS(EV_MAX)]; unsigned long absBits[NBITS(ABS_MAX)]; @@ -3927,7 +3928,7 @@ static void EventThreadSpawn(char *device) bool hasAbsMulti = false; int freeWorkerId = -1; int fd = -1; - + InputEventWorker *worker; /////////////////////////////////// Open the device and allocate worker ///////////////////////////////////////////// @@ -3967,15 +3968,15 @@ static void EventThreadSpawn(char *device) int devNum = 0; char *ptrDevName = strrchr(device, 't'); worker->eventNum = -1; - + if (ptrDevName != NULL) { if (sscanf(ptrDevName, "t%d", &devNum) == 1) worker->eventNum = devNum; } - // At this point we have a connection to the device, - // but we don't yet know what the device is (Could be + // At this point we have a connection to the device, + // but we don't yet know what the device is (Could be // many things, even as simple as a power button) /////////////////////////////////// Identify the device ///////////////////////////////////////////// @@ -3983,15 +3984,15 @@ static void EventThreadSpawn(char *device) ioctl(fd, EVIOCGBIT(0, sizeof(evBits)), evBits); // Read a bitfield of the avalable device properties // Check for absolute input devices - if (TEST_BIT(evBits, EV_ABS)) + if (TEST_BIT(evBits, EV_ABS)) { ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits); // Check for absolute movement support (usualy touchscreens, but also joysticks) - if (TEST_BIT(absBits, ABS_X) && TEST_BIT(absBits, ABS_Y)) + if (TEST_BIT(absBits, ABS_X) && TEST_BIT(absBits, ABS_Y)) { hasAbs = true; - + // Get the scaling values ioctl(fd, EVIOCGABS(ABS_X), &absinfo); worker->absRange.x = absinfo.minimum; @@ -4000,12 +4001,12 @@ static void EventThreadSpawn(char *device) worker->absRange.y = absinfo.minimum; worker->absRange.height = absinfo.maximum - absinfo.minimum; } - + // Check for multiple absolute movement support (usualy multitouch touchscreens) - if (TEST_BIT(absBits, ABS_MT_POSITION_X) && TEST_BIT(absBits, ABS_MT_POSITION_Y)) + if (TEST_BIT(absBits, ABS_MT_POSITION_X) && TEST_BIT(absBits, ABS_MT_POSITION_Y)) { hasAbsMulti = true; - + // Get the scaling values ioctl(fd, EVIOCGABS(ABS_X), &absinfo); worker->absRange.x = absinfo.minimum; @@ -4017,15 +4018,15 @@ static void EventThreadSpawn(char *device) } // Check for relative movement support (usualy mouse) - if (TEST_BIT(evBits, EV_REL)) + if (TEST_BIT(evBits, EV_REL)) { ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relBits)), relBits); - + if (TEST_BIT(relBits, REL_X) && TEST_BIT(relBits, REL_Y)) hasRel = true; } // Check for button support to determine the device type(usualy on all input devices) - if (TEST_BIT(evBits, EV_KEY)) + if (TEST_BIT(evBits, EV_KEY)) { ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits); @@ -4077,12 +4078,12 @@ static void EventThreadSpawn(char *device) #if defined(USE_LAST_TOUCH_DEVICE) // Find touchscreen with the highest index int maxTouchNumber = -1; - + for (int i = 0; i < sizeof(eventWorkers)/sizeof(InputEventWorker); ++i) { if (eventWorkers[i].isTouch && (eventWorkers[i].eventNum > maxTouchNumber)) maxTouchNumber = eventWorkers[i].eventNum; } - + // Find toucnscreens with lower indexes for (int i = 0; i < sizeof(eventWorkers)/sizeof(InputEventWorker); ++i) { @@ -4134,7 +4135,7 @@ static void *EventThread(void *arg) if (event.code == REL_WHEEL) { currentMouseWheelY += event.value; - } + } } /////////////////////////////// Absolute movement parsing //////////////////////////////////// @@ -4231,9 +4232,9 @@ static void *EventThread(void *arg) usleep(5000); // Sleep for 5ms to avoid hogging CPU time } } - + close(worker->fd); - + return NULL; } diff --git a/src/raylib.h b/src/raylib.h index 49ff1c0c..5b68c0be 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -511,7 +511,7 @@ typedef struct Mesh { float *tangents; // Vertex tangents (XYZW - 4 components per vertex) (shader-location = 4) unsigned char *colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3) unsigned short *indices;// Vertex indices (in case vertex data comes indexed) - + // Animation vertex data float *baseVertices; // Vertex base position (required to apply bones transformations) float *baseNormals; // Vertex base normals (required to apply bones transformations) diff --git a/src/rlgl.h b/src/rlgl.h index d97d888e..7f2a1711 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -199,7 +199,7 @@ typedef unsigned char byte; float *tangents; // vertex tangents (XYZW - 4 components per vertex) (shader-location = 4) unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3) unsigned short *indices;// vertex indices (in case vertex data comes indexed) - + // Animation vertex data float *baseVertices; // Vertex base position (required to apply bones transformations) float *baseNormals; // Vertex base normals (required to apply bones transformations) @@ -729,7 +729,7 @@ typedef struct VrStereoConfig { //---------------------------------------------------------------------------------- #if !defined(GRAPHICS_API_OPENGL_11) && defined(SUPPORT_DISTORTION_SHADER) // Distortion shader embedded - static char distortionFShaderStr[] = + static char distortionFShaderStr[] = #if defined(GRAPHICS_API_OPENGL_21) "#version 120 \n" #elif defined(GRAPHICS_API_OPENGL_ES2) @@ -1217,9 +1217,9 @@ void rlEnd(void) // WARNING: If we are between rlPushMatrix() and rlPopMatrix() and we need to force a rlglDraw(), // we need to call rlPopMatrix() before to recover *currentMatrix (modelview) for the next forced draw call! // Also noted that if we had multiple matrix pushed, it will require "stackCounter" pops before launching the draw - + // TODO: Undoubtely, current rlPushMatrix/rlPopMatrix should be redesigned... or removed... it's not working properly - + rlPopMatrix(); rlglDraw(); } @@ -1507,7 +1507,7 @@ void rlDeleteRenderTextures(RenderTexture2D target) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) if (target.texture.id > 0) glDeleteTextures(1, &target.texture.id); - if (target.depth.id > 0) + if (target.depth.id > 0) { #if defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_ES2) glDeleteRenderbuffers(1, &target.depth.id); @@ -1640,7 +1640,7 @@ void rlglInit(int width, int height) char *extensions = (char *)glGetString(GL_EXTENSIONS); // One big const string // NOTE: We have to duplicate string because glGetString() returns a const string - int len = strlen(extensions) + 1; + int len = strlen(extensions) + 1; char *extensionsDup = (char *)malloc(len); strcpy(extensionsDup, extensions); @@ -2260,7 +2260,7 @@ RenderTexture2D rlLoadRenderTexture(int width, int height) } if (target.texture.id > 0) glDeleteTextures(1, &target.texture.id); - if (target.depth.id > 0) + if (target.depth.id > 0) { #if defined(USE_DEPTH_RENDERBUFFER) glDeleteRenderbuffers(1, &target.depth.id); @@ -2268,7 +2268,7 @@ RenderTexture2D rlLoadRenderTexture(int width, int height) glDeleteTextures(1, &target.depth.id); #endif } - + glDeleteFramebuffers(1, &target.id); } else TraceLog(LOG_INFO, "[FBO ID %i] Framebuffer object created successfully", target.id); @@ -2736,7 +2736,7 @@ void rlUnloadMesh(Mesh *mesh) if (mesh->tangents != NULL) free(mesh->tangents); if (mesh->texcoords2 != NULL) free(mesh->texcoords2); if (mesh->indices != NULL) free(mesh->indices); - + if (mesh->baseVertices != NULL) free(mesh->baseVertices); if (mesh->baseNormals != NULL) free(mesh->baseNormals); if (mesh->weightBias != NULL) free(mesh->weightBias); diff --git a/src/shapes.c b/src/shapes.c index 7d61c25f..69331445 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -9,7 +9,7 @@ * Allows drawing rectangles and text with a single draw call, very useful for GUI systems! * * #define SUPPORT_QUADS_DRAW_MODE -* Use QUADS instead of TRIANGLES for drawing when possible. +* Use QUADS instead of TRIANGLES for drawing when possible. * Some lines-based shapes could still use lines * * LICENSE: zlib/libpng @@ -116,13 +116,13 @@ void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color) startPos = endPos; endPos = tempPos; } - + float dx = endPos.x - startPos.x; float dy = endPos.y - startPos.y; - + float d = sqrtf(dx*dx + dy*dy); float angle = asinf(dy/d); - + rlEnableTexture(GetShapesTexture().id); rlPushMatrix(); @@ -155,12 +155,12 @@ void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color) for (int i = 1; i <= LINE_DIVISIONS; i++) { // Cubic easing in-out - // NOTE: Easing is calculated only for y position value + // NOTE: Easing is calculated only for y position value current.y = EaseCubicInOut((float)i, startPos.y, endPos.y - startPos.y, (float)LINE_DIVISIONS); current.x = previous.x + (endPos.x - startPos.x)/ (float)LINE_DIVISIONS; - + DrawLineEx(previous, current, thick, color); - + previous = current; } } @@ -176,7 +176,7 @@ void DrawCircle(int centerX, int centerY, float radius, Color color) void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2) { if (rlCheckBufferLimit(RL_TRIANGLES, 3*36)) rlglDraw(); - + rlBegin(RL_TRIANGLES); for (int i = 0; i < 360; i += 10) { @@ -193,31 +193,31 @@ void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Co // Draw a color-filled circle (Vector version) // NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw) void DrawCircleV(Vector2 center, float radius, Color color) -{ +{ #if defined(SUPPORT_QUADS_DRAW_MODE) if (rlCheckBufferLimit(RL_QUADS, 4*(36/2))) rlglDraw(); - + rlEnableTexture(GetShapesTexture().id); rlBegin(RL_QUADS); for (int i = 0; i < 360; i += 20) { rlColor4ub(color.r, color.g, color.b, color.a); - + rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height); rlVertex2f(center.x, center.y); - + rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height); rlVertex2f(center.x + sinf(DEG2RAD*i)*radius, center.y + cosf(DEG2RAD*i)*radius); - + rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height); rlVertex2f(center.x + sinf(DEG2RAD*(i + 10))*radius, center.y + cosf(DEG2RAD*(i + 10))*radius); - + rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height); rlVertex2f(center.x + sinf(DEG2RAD*(i + 20))*radius, center.y + cosf(DEG2RAD*(i + 20))*radius); } rlEnd(); - + rlDisableTexture(); #else if (rlCheckBufferLimit(RL_TRIANGLES, 3*(36/2))) rlglDraw(); @@ -226,7 +226,7 @@ void DrawCircleV(Vector2 center, float radius, Color color) for (int i = 0; i < 360; i += 10) { rlColor4ub(color.r, color.g, color.b, color.a); - + rlVertex2f(center.x, center.y); rlVertex2f(center.x + sinf(DEG2RAD*i)*radius, center.y + cosf(DEG2RAD*i)*radius); rlVertex2f(center.x + sinf(DEG2RAD*(i + 10))*radius, center.y + cosf(DEG2RAD*(i + 10))*radius); @@ -239,7 +239,7 @@ void DrawCircleV(Vector2 center, float radius, Color color) void DrawCircleLines(int centerX, int centerY, float radius, Color color) { if (rlCheckBufferLimit(RL_LINES, 2*36)) rlglDraw(); - + rlBegin(RL_LINES); rlColor4ub(color.r, color.g, color.b, color.a); @@ -263,7 +263,7 @@ void DrawRectangle(int posX, int posY, int width, int height, Color color) void DrawRectangleV(Vector2 position, Vector2 size, Color color) { Color colors[4] = { color, color, color, color }; - + DrawRectanglePro((Rectangle){ position.x, position.y, size.x, size.y }, (Vector2){ 0.0f, 0.0f }, 0.0f, colors); } @@ -271,7 +271,7 @@ void DrawRectangleV(Vector2 position, Vector2 size, Color color) void DrawRectangleRec(Rectangle rec, Color color) { Color colors[4] = { color, color, color, color }; - + DrawRectanglePro(rec, (Vector2){ 0.0f, 0.0f }, 0.0f, colors); } @@ -292,15 +292,15 @@ void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color rlColor4ub(colors[0].r, colors[0].g, colors[0].b, colors[0].a); rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height); rlVertex2f(rec.x, rec.y); - + rlColor4ub(colors[1].r, colors[1].g, colors[1].b, colors[1].a); rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height); rlVertex2f(rec.x, rec.y + rec.height); - + rlColor4ub(colors[2].r, colors[2].g, colors[2].b, colors[2].a); rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height); rlVertex2f(rec.x + rec.width, rec.y + rec.height); - + rlColor4ub(colors[3].r, colors[3].g, colors[3].b, colors[3].a); rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height); rlVertex2f(rec.x + rec.width, rec.y); @@ -329,14 +329,14 @@ void DrawRectangleGradientH(int posX, int posY, int width, int height, Color col void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4) { Color colors[4] = { col1, col2, col3, col4 }; - + DrawRectanglePro(rec, (Vector2){ 0.0f, 0.0f }, 0.0f, colors); } // Draw rectangle outline // NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw) void DrawRectangleLines(int posX, int posY, int width, int height, Color color) -{ +{ #if defined(SUPPORT_QUADS_DRAW_MODE) DrawRectangle(posX, posY, width, 1, color); DrawRectangle(posX + width - 1, posY + 1, 1, height - 2, color); @@ -362,13 +362,13 @@ void DrawRectangleLines(int posX, int posY, int width, int height, Color color) // Draw rectangle outline with extended parameters void DrawRectangleLinesEx(Rectangle rec, int lineThick, Color color) -{ +{ if (lineThick > rec.width || lineThick > rec.height) { if(rec.width > rec.height) lineThick = (int)rec.height/2; else if (rec.width < rec.height) lineThick = (int)rec.width/2; - } - + } + DrawRectangle( (int)rec.x, (int)rec.y, (int)rec.width, lineThick, color); DrawRectangle( (int)(rec.x - lineThick + rec.width), (int)(rec.y + lineThick), lineThick, (int)(rec.height - lineThick*2.0f), color); DrawRectangle( (int)rec.x, (int)(rec.y + rec.height - lineThick), (int)rec.width, lineThick, color); @@ -383,20 +383,20 @@ void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color) rlBegin(RL_QUADS); rlColor4ub(color.r, color.g, color.b, color.a); - + rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height); rlVertex2f(v1.x, v1.y); - + rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height); rlVertex2f(v2.x, v2.y); - + rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height); rlVertex2f(v2.x, v2.y); - + rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height); rlVertex2f(v3.x, v3.y); rlEnd(); - + rlDisableTexture(); #else rlBegin(RL_TRIANGLES); @@ -428,13 +428,13 @@ void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color) void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color) { if (sides < 3) sides = 3; - + if (rlCheckBufferLimit(RL_QUADS, 4*(360/sides))) rlglDraw(); rlPushMatrix(); rlTranslatef(center.x, center.y, 0.0); rlRotatef(rotation, 0, 0, 1); - + #if defined(SUPPORT_QUADS_DRAW_MODE) rlEnableTexture(GetShapesTexture().id); @@ -445,13 +445,13 @@ void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color col rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height); rlVertex2f(0, 0); - + rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height); rlVertex2f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius); - + rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height); rlVertex2f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius); - + rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height); rlVertex2f(sinf(DEG2RAD*(i + 360/sides))*radius, cosf(DEG2RAD*(i + 360/sides))*radius); } @@ -478,7 +478,7 @@ void DrawPolyEx(Vector2 *points, int pointsCount, Color color) if (pointsCount >= 3) { if (rlCheckBufferLimit(RL_QUADS, pointsCount)) rlglDraw(); - + #if defined(SUPPORT_QUADS_DRAW_MODE) rlEnableTexture(GetShapesTexture().id); @@ -577,7 +577,7 @@ bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2) { bool collision = false; - + if ((rec1.x <= (rec2.x + rec2.width) && (rec1.x + rec1.width) >= rec2.x) && (rec1.y <= (rec2.y + rec2.height) && (rec1.y + rec1.height) >= rec2.y)) collision = true; @@ -605,7 +605,7 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec) { int recCenterX = (int)(rec.x + rec.width/2.0f); int recCenterY = (int)(rec.y + rec.height/2.0f); - + float dx = (float)fabs(center.x - recCenterX); float dy = (float)fabs(center.y - recCenterY); @@ -615,7 +615,7 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec) if (dx <= (rec.width/2.0f)) { return true; } if (dy <= (rec.height/2.0f)) { return true; } - float cornerDistanceSq = (dx - rec.width/2.0f)*(dx - rec.width/2.0f) + + float cornerDistanceSq = (dx - rec.width/2.0f)*(dx - rec.width/2.0f) + (dy - rec.height/2.0f)*(dy - rec.height/2.0f); return (cornerDistanceSq <= (radius*radius)); @@ -674,7 +674,7 @@ Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2) { if (retRec.width >= rec1.width) retRec.width = rec1.width; } - + if (rec1.height > rec2.height) { if (retRec.height >= rec2.height) retRec.height = rec2.height; @@ -692,10 +692,10 @@ Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2) // Module specific Functions Definition //---------------------------------------------------------------------------------- -// Cubic easing in-out +// Cubic easing in-out // NOTE: Required for DrawLineBezier() -static float EaseCubicInOut(float t, float b, float c, float d) -{ +static float EaseCubicInOut(float t, float b, float c, float d) +{ if ((t /= 0.5f*d) < 1) return 0.5f*c*t*t*t + b; t -= 2; @@ -715,6 +715,6 @@ static Texture2D GetShapesTexture(void) recTexShapes = { 0.0f, 0.0f, 1.0f, 1.0f }; #endif } - + return texShapes; } diff --git a/src/text.c b/src/text.c index 5c3c14a8..07a25964 100644 --- a/src/text.c +++ b/src/text.c @@ -200,10 +200,10 @@ extern void LoadDefaultFont(void) // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, charsCount //------------------------------------------------------------------------------ - + // Allocate space for our characters info data // NOTE: This memory should be freed at end! --> CloseWindow() - defaultFont.chars = (CharInfo *)malloc(defaultFont.charsCount*sizeof(CharInfo)); + defaultFont.chars = (CharInfo *)malloc(defaultFont.charsCount*sizeof(CharInfo)); int currentLine = 0; int currentPosX = charsDivisor; @@ -238,7 +238,7 @@ extern void LoadDefaultFont(void) } defaultFont.baseSize = (int)defaultFont.chars[0].rec.height; - + TraceLog(LOG_INFO, "[TEX ID %i] Default font loaded successfully", defaultFont.texture.id); } @@ -258,7 +258,7 @@ Font GetFontDefault() #else Font font = { 0 }; return font; -#endif +#endif } // Load Font from file into GPU memory (VRAM) @@ -301,11 +301,11 @@ Font LoadFont(const char *fileName) Font LoadFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars) { Font font = { 0 }; - + font.baseSize = fontSize; font.charsCount = (charsCount > 0) ? charsCount : 95; font.chars = LoadFontData(fileName, font.baseSize, fontChars, font.charsCount, FONT_DEFAULT); - + if (font.chars != NULL) { Image atlas = GenImageFontAtlas(font.chars, font.charsCount, font.baseSize, 2, 0); @@ -313,7 +313,7 @@ Font LoadFontEx(const char *fileName, int fontSize, int charsCount, int *fontCha UnloadImage(atlas); } else font = GetFontDefault(); - + return font; } @@ -326,7 +326,7 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c #define SDF_CHAR_PADDING 4 #define SDF_ON_EDGE_VALUE 128 #define SDF_PIXEL_DIST_SCALE 64.0f - + #define BITMAP_ALPHA_THRESHOLD 80 CharInfo *chars = NULL; @@ -335,15 +335,15 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c // NOTE: Loaded information should be enough to generate font image atlas, // using any packaging method FILE *fontFile = fopen(fileName, "rb"); // Load font file - + if (fontFile != NULL) { fseek(fontFile, 0, SEEK_END); long size = ftell(fontFile); // Get file size fseek(fontFile, 0, SEEK_SET); // Reset file pointer - + unsigned char *fontBuffer = (unsigned char *)malloc(size); - + fread(fontBuffer, size, 1, fontFile); fclose(fontFile); @@ -358,10 +358,10 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c // NOTE: ascent is equivalent to font baseline int ascent, descent, lineGap; stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap); - + // In case no chars count provided, default to 95 charsCount = (charsCount > 0) ? charsCount : 95; - + // Fill fontChars in case not provided externally // NOTE: By default we fill charsCount consecutevely, starting at 32 (Space) int genFontChars = false; @@ -373,22 +373,22 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c } chars = (CharInfo *)malloc(charsCount*sizeof(CharInfo)); - + // NOTE: Using simple packaging, one char after another - for (int i = 0; i < charsCount; i++) + for (int i = 0; i < charsCount; i++) { int chw = 0, chh = 0; // Character width and height (on generation) int ch = fontChars[i]; // Character value to get info for chars[i].value = ch; - + // Render a unicode codepoint to a bitmap // stbtt_GetCodepointBitmap() -- allocates and returns a bitmap // stbtt_GetCodepointBitmapBox() -- how big the bitmap must be // stbtt_MakeCodepointBitmap() -- renders into bitmap you provide - + if (type != FONT_SDF) chars[i].data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); else if (ch != 32) chars[i].data = stbtt_GetCodepointSDF(&fontInfo, scaleFactor, ch, SDF_CHAR_PADDING, SDF_ON_EDGE_VALUE, SDF_PIXEL_DIST_SCALE, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); - + if (type == FONT_BITMAP) { // Aliased bitmap (black & white) font generation, avoiding anti-aliasing @@ -399,15 +399,15 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c else chars[i].data[p] = 255; } } - + chars[i].rec.width = (float)chw; chars[i].rec.height = (float)chh; chars[i].offsetY += (int)((float)ascent*scaleFactor); - + // Get bounding box for character (may be offset to account for chars that dip above or below the line) int chX1, chY1, chX2, chY2; stbtt_GetCodepointBitmapBox(&fontInfo, ch, scaleFactor, scaleFactor, &chX1, &chY1, &chX2, &chY2); - + TraceLog(LOG_DEBUG, "Character box measures: %i, %i, %i, %i", chX1, chY1, chX2 - chX1, chY2 - chY1); TraceLog(LOG_DEBUG, "Character offsetY: %i", (int)((float)ascent*scaleFactor) + chY1); @@ -419,7 +419,7 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c if (genFontChars) free(fontChars); } else TraceLog(LOG_WARNING, "[%s] TTF file could not be opened", fileName); - + return chars; } @@ -428,25 +428,25 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int padding, int packMethod) { Image atlas = { 0 }; - + // In case no chars count provided we suppose default of 95 charsCount = (charsCount > 0) ? charsCount : 95; - + // Calculate image size based on required pixel area // NOTE 1: Image is forced to be squared and POT... very conservative! - // NOTE 2: SDF font characters already contain an internal padding, + // NOTE 2: SDF font characters already contain an internal padding, // so image size would result bigger than default font type float requiredArea = 0; for (int i = 0; i < charsCount; i++) requiredArea += ((chars[i].rec.width + 2*padding)*(chars[i].rec.height + 2*padding)); float guessSize = sqrtf(requiredArea)*1.25f; int imageSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT - + atlas.width = imageSize; // Atlas bitmap width atlas.height = imageSize; // Atlas bitmap height atlas.data = (unsigned char *)calloc(1, atlas.width*atlas.height); // Create a bitmap to store characters (8 bpp) atlas.format = UNCOMPRESSED_GRAYSCALE; atlas.mipmaps = 1; - + // DEBUG: We can see padding in the generated image setting a gray background... //for (int i = 0; i < atlas.width*atlas.height; i++) ((unsigned char *)atlas.data)[i] = 100; @@ -454,9 +454,9 @@ Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int paddi { int offsetX = padding; int offsetY = padding; - + // NOTE: Using simple packaging, one char after another - for (int i = 0; i < charsCount; i++) + for (int i = 0; i < charsCount; i++) { // Copy pixel data from fc.data to atlas for (int y = 0; y < (int)chars[i].rec.height; y++) @@ -466,22 +466,22 @@ Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int paddi ((unsigned char *)atlas.data)[(offsetY + y)*atlas.width + (offsetX + x)] = chars[i].data[y*(int)chars[i].rec.width + x]; } } - + chars[i].rec.x = (float)offsetX; chars[i].rec.y = (float)offsetY; - + // Move atlas position X for next character drawing offsetX += ((int)chars[i].rec.width + 2*padding); - + if (offsetX >= (atlas.width - (int)chars[i].rec.width - padding)) { offsetX = padding; - - // NOTE: Be careful on offsetY for SDF fonts, by default SDF + + // NOTE: Be careful on offsetY for SDF fonts, by default SDF // use an internal padding of 4 pixels, it means char rectangle // height is bigger than fontSize, it could be up to (fontSize + 8) offsetY += (fontSize + 2*padding); - + if (offsetY > (atlas.height - fontSize - padding)) break; } } @@ -489,13 +489,13 @@ Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int paddi else if (packMethod == 1) // Use Skyline rect packing algorythm (stb_pack_rect) { TraceLog(LOG_DEBUG, "Using Skyline packing algorythm!"); - + stbrp_context *context = (stbrp_context *)malloc(sizeof(*context)); stbrp_node *nodes = (stbrp_node *)malloc(charsCount*sizeof(*nodes)); stbrp_init_target(context, atlas.width, atlas.height, nodes, charsCount); stbrp_rect *rects = (stbrp_rect *)malloc(charsCount*sizeof(stbrp_rect)); - + // Fill rectangles for packaging for (int i = 0; i < charsCount; i++) { @@ -506,12 +506,12 @@ Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int paddi // Package rectangles into atlas stbrp_pack_rects(context, rects, charsCount); - + for (int i = 0; i < charsCount; i++) { chars[i].rec.x = rects[i].x + (float)padding; chars[i].rec.y = rects[i].y + (float)padding; - + if (rects[i].was_packed) { // Copy pixel data from fc.data to atlas @@ -530,9 +530,9 @@ Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int paddi free(nodes); free(context); } - + // TODO: Crop image if required for smaller size - + // Convert image data from GRAYSCALE to GRAY_ALPHA // WARNING: ImageAlphaMask(&atlas, atlas) does not work in this case, requires manual operation unsigned char *dataGrayAlpha = (unsigned char *)malloc(imageSize*imageSize*sizeof(unsigned char)*2); // Two channels @@ -546,7 +546,7 @@ Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int paddi free(atlas.data); atlas.data = dataGrayAlpha; atlas.format = UNCOMPRESSED_GRAY_ALPHA; - + return atlas; } @@ -580,7 +580,7 @@ void DrawFPS(int posX, int posY) refreshRate = fps; counter = 0; } - + // NOTE: We have rounding errors every frame, so it oscillates a lot DrawText(FormatText("%2i FPS", fps), posX, posY, 20, LIME); } @@ -645,7 +645,7 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f i++; } else index = GetGlyphIndex(font, (unsigned char)text[i]); - + if ((unsigned char)text[i] != ' ') { DrawTexturePro(font.texture, font.chars[index].rec, @@ -795,27 +795,27 @@ char **SplitText(char *text, char delimiter, int *strCount) char *strDup = (char *)malloc(len + 1); strcpy(strDup, text); int counter = 1; - + // Count how many substrings we have on string for (int i = 0; i < len; i++) if (text[i] == delimiter) counter++; - + // Memory allocation for substrings strings = (char **)malloc(sizeof(char *)*counter); for (int i = 0; i < counter; i++) strings[i] = (char *)malloc(sizeof(char)*MAX_SUBSTRING_LENGTH); - + char *substrPtr = NULL; char delimiters[1] = { delimiter }; // Only caring for one delimiter substrPtr = strtok(strDup, delimiters); - + for (int i = 0; (i < counter) && (substrPtr != NULL); i++) { strcpy(strings[i], substrPtr); substrPtr = strtok(NULL, delimiters); } - + *strCount = counter; free(strDup); - + return strings; } @@ -823,9 +823,9 @@ char **SplitText(char *text, char delimiter, int *strCount) bool IsEqualText(const char *text1, const char *text2) { bool result = false; - + if (strcmp(text1, text2) == 0) result = true; - + return result; } @@ -861,7 +861,7 @@ static Font LoadImageFont(Image image, Color key, int firstChar) { if (!COLOR_EQUAL(pixels[y*image.width + x], key)) break; } - + if (!COLOR_EQUAL(pixels[y*image.width + x], key)) break; } @@ -1031,10 +1031,10 @@ static Font LoadBMFont(const char *fileName) UnloadImage(imCopy); } else font.texture = LoadTextureFromImage(imFont); - + UnloadImage(imFont); free(texPath); - + // Fill font characters info data font.baseSize = fontSize; diff --git a/src/textures.c b/src/textures.c index aa9e66f6..17f2ae8a 100644 --- a/src/textures.c +++ b/src/textures.c @@ -424,7 +424,7 @@ Color *GetImageData(Image image) if ((image.format == UNCOMPRESSED_R32) || (image.format == UNCOMPRESSED_R32G32B32) || (image.format == UNCOMPRESSED_R32G32B32A32)) TraceLog(LOG_WARNING, "32bit pixel format converted to 8bit per channel"); - + for (int i = 0, k = 0; i < image.width*image.height; i++) { switch (image.format) @@ -500,7 +500,7 @@ Color *GetImageData(Image image) pixels[i].g = 0; pixels[i].b = 0; pixels[i].a = 255; - + } break; case UNCOMPRESSED_R32G32B32: { @@ -508,7 +508,7 @@ Color *GetImageData(Image image) pixels[i].g = (unsigned char)(((float *)image.data)[k + 1]*255.0f); pixels[i].b = (unsigned char)(((float *)image.data)[k + 2]*255.0f); pixels[i].a = 255; - + k += 3; } case UNCOMPRESSED_R32G32B32A32: @@ -517,7 +517,7 @@ Color *GetImageData(Image image) pixels[i].g = (unsigned char)(((float *)image.data)[k]*255.0f); pixels[i].b = (unsigned char)(((float *)image.data)[k]*255.0f); pixels[i].a = (unsigned char)(((float *)image.data)[k]*255.0f); - + k += 4; } default: break; @@ -532,7 +532,7 @@ Color *GetImageData(Image image) Vector4 *GetImageDataNormalized(Image image) { Vector4 *pixels = (Vector4 *)malloc(image.width*image.height*sizeof(Vector4)); - + if (image.format >= COMPRESSED_DXT1_RGB) TraceLog(LOG_WARNING, "Pixel data retrieval not supported for compressed image formats"); else { @@ -611,7 +611,7 @@ Vector4 *GetImageDataNormalized(Image image) pixels[i].y = 0.0f; pixels[i].z = 0.0f; pixels[i].w = 1.0f; - + } break; case UNCOMPRESSED_R32G32B32: { @@ -619,7 +619,7 @@ Vector4 *GetImageDataNormalized(Image image) pixels[i].y = ((float *)image.data)[k + 1]; pixels[i].z = ((float *)image.data)[k + 2]; pixels[i].w = 1.0f; - + k += 3; } case UNCOMPRESSED_R32G32B32A32: @@ -628,14 +628,14 @@ Vector4 *GetImageDataNormalized(Image image) pixels[i].y = ((float *)image.data)[k + 1]; pixels[i].z = ((float *)image.data)[k + 2]; pixels[i].w = ((float *)image.data)[k + 3]; - + k += 4; } default: break; } } } - + return pixels; } @@ -720,16 +720,16 @@ void UpdateTexture(Texture2D texture, const void *pixels) void ExportImage(Image image, const char *fileName) { int success = 0; - + // NOTE: Getting Color array as RGBA unsigned char values unsigned char *imgData = (unsigned char *)GetImageData(image); - + if (IsFileExtension(fileName, ".png")) success = stbi_write_png(fileName, image.width, image.height, 4, imgData, image.width*4); else if (IsFileExtension(fileName, ".bmp")) success = stbi_write_bmp(fileName, image.width, image.height, 4, imgData); else if (IsFileExtension(fileName, ".tga")) success = stbi_write_tga(fileName, image.width, image.height, 4, imgData); else if (IsFileExtension(fileName, ".jpg")) success = stbi_write_jpg(fileName, image.width, image.height, 4, imgData, 80); // JPG quality: between 1 and 100 else if (IsFileExtension(fileName, ".ktx")) success = SaveKTX(image, fileName); - else if (IsFileExtension(fileName, ".raw")) + else if (IsFileExtension(fileName, ".raw")) { // Export raw pixel data (without header) // NOTE: It's up to the user to track image parameters @@ -740,7 +740,7 @@ void ExportImage(Image image, const char *fileName) if (success != 0) TraceLog(LOG_INFO, "Image exported successfully: %s", fileName); else TraceLog(LOG_WARNING, "Image could not be exported."); - + free(imgData); } @@ -748,10 +748,10 @@ void ExportImage(Image image, const char *fileName) void ExportImageAsCode(Image image, const char *fileName) { #define BYTES_TEXT_PER_LINE 20 - + char varFileName[256] = { 0 }; int dataSize = GetPixelDataSize(image.width, image.height, image.format); - + FILE *txtFile = fopen(fileName, "wt"); fprintf(txtFile, "\n//////////////////////////////////////////////////////////////////////////////////////\n"); @@ -764,11 +764,11 @@ void ExportImageAsCode(Image image, const char *fileName) fprintf(txtFile, "// Copyright (c) 2018 Ramon Santamaria (@raysan5) //\n"); fprintf(txtFile, "// //\n"); fprintf(txtFile, "////////////////////////////////////////////////////////////////////////////////////////\n\n"); - + // Get file name from path and convert variable name to uppercase strcpy(varFileName, GetFileNameWithoutExt(fileName)); for (int i = 0; varFileName[i] != '\0'; i++) if (varFileName[i] >= 'a' && varFileName[i] <= 'z') { varFileName[i] = varFileName[i] - 32; } - + // Add image information fprintf(txtFile, "// Image data information\n"); fprintf(txtFile, "#define %s_WIDTH %i\n", varFileName, image.width); @@ -987,7 +987,7 @@ void ImageFormat(Image *image, int newFormat) case UNCOMPRESSED_R32: { // WARNING: Image is converted to GRAYSCALE eqeuivalent 32bit - + image->data = (float *)malloc(image->width*image->height*sizeof(float)); for (int i = 0; i < image->width*image->height; i++) @@ -1023,7 +1023,7 @@ void ImageFormat(Image *image, int newFormat) free(pixels); pixels = NULL; - + // In case original image had mipmaps, generate mipmaps for formated image // NOTE: Original mipmaps are replaced by new ones, if custom mipmaps were used, they are lost if (image->mipmaps > 1) @@ -1087,14 +1087,14 @@ void ImageAlphaMask(Image *image, Image alphaMask) void ImageAlphaClear(Image *image, Color color, float threshold) { 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; UnloadImage(*image); - + int prevFormat = image->format; *image = LoadImageEx(pixels, image->width, image->height); - + ImageFormat(image, prevFormat); } @@ -1102,13 +1102,13 @@ void ImageAlphaClear(Image *image, Color color, float threshold) 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++) + for (int i = 0; i < image->width*image->height; i++) { if (pixels[i].a > (unsigned char)(threshold*255.0f)) { @@ -1127,18 +1127,18 @@ void ImageAlphaCrop(Image *image, float threshold) else if (crop.height < (float)miny) crop.height = (float)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) && + if ((crop.x != 1) && + (crop.y != 1) && (crop.width != image->width - 1) && (crop.height != image->height - 1)) ImageCrop(image, crop); } @@ -1148,8 +1148,8 @@ void ImageAlphaPremultiply(Image *image) { float alpha = 0.0f; Color *pixels = GetImageData(*image); - - for (int i = 0; i < image->width*image->height; i++) + + for (int i = 0; i < image->width*image->height; i++) { alpha = (float)pixels[i].a/255.0f; pixels[i].r = (unsigned char)((float)pixels[i].r*alpha); @@ -1158,10 +1158,10 @@ void ImageAlphaPremultiply(Image *image) } UnloadImage(*image); - + int prevFormat = image->format; *image = LoadImageEx(pixels, image->width, image->height); - + ImageFormat(image, prevFormat); } @@ -1282,9 +1282,9 @@ void ImageResizeCanvas(Image *image, int newWidth,int newHeight, int offsetX, in Image imTemp = GenImageColor(newWidth, newHeight, color); Rectangle srcRec = { 0.0f, 0.0f, (float)image->width, (float)image->height }; Rectangle dstRec = { (float)offsetX, (float)offsetY, (float)srcRec.width, (float)srcRec.height }; - + // TODO: Review different scaling situations - + if ((newWidth > image->width) && (newHeight > image->height)) { ImageDraw(&imTemp, *image, srcRec, dstRec); @@ -1314,7 +1314,7 @@ void ImageMipmaps(Image *image) { if (mipWidth != 1) mipWidth /= 2; if (mipHeight != 1) mipHeight /= 2; - + // Security check for NPOT textures if (mipWidth < 1) mipWidth = 1; if (mipHeight < 1) mipHeight = 1; @@ -1332,8 +1332,8 @@ void ImageMipmaps(Image *image) if (image->mipmaps < mipCount) { void *temp = realloc(image->data, mipSize); - - if (temp != NULL) + + if (temp != NULL) { image->data = temp; // Assign new pointer (new size) to store mipmaps data TraceLog(LOG_DEBUG, "Image data memory point reallocated: 0x%x", temp); @@ -1342,29 +1342,29 @@ void ImageMipmaps(Image *image) // Pointer to allocated memory point where store next mipmap level data unsigned char *nextmip = (unsigned char *)image->data + GetPixelDataSize(image->width, image->height, image->format); - + mipWidth = image->width/2; mipHeight = image->height/2; mipSize = GetPixelDataSize(mipWidth, mipHeight, image->format); Image imCopy = ImageCopy(*image); - + for (int i = 1; i < mipCount; i++) { TraceLog(LOG_DEBUG, "Gen mipmap level: %i (%i x %i) - size: %i - offset: 0x%x", i, mipWidth, mipHeight, mipSize, nextmip); - + ImageResize(&imCopy, mipWidth, mipHeight); // Uses internally Mitchell cubic downscale filter memcpy(nextmip, imCopy.data, mipSize); nextmip += mipSize; image->mipmaps++; - + mipWidth /= 2; mipHeight /= 2; - + // Security check for NPOT textures if (mipWidth < 1) mipWidth = 1; if (mipHeight < 1) mipHeight = 1; - + mipSize = GetPixelDataSize(mipWidth, mipHeight, image->format); } @@ -1487,10 +1487,10 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) Color *ImageExtractPalette(Image image, int maxPaletteSize, int *extractCount) { #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a)) - + Color *pixels = GetImageData(image); Color *palette = (Color *)malloc(maxPaletteSize*sizeof(Color)); - + int palCount = 0; for (int i = 0; i < maxPaletteSize; i++) palette[i] = BLANK; // Set all colors to BLANK @@ -1499,23 +1499,23 @@ Color *ImageExtractPalette(Image image, int maxPaletteSize, int *extractCount) if (pixels[i].a > 0) { bool colorInPalette = false; - + // Check if the color is already on palette for (int j = 0; j < maxPaletteSize; j++) { - if (COLOR_EQUAL(pixels[i], palette[j])) + if (COLOR_EQUAL(pixels[i], palette[j])) { colorInPalette = true; break; } } - + // Store color if not on the palette if (!colorInPalette) { palette[palCount] = pixels[i]; // Add pixels[i] to palette palCount++; - + // We reached the limit of colors supported by palette if (palCount >= maxPaletteSize) { @@ -1527,9 +1527,9 @@ Color *ImageExtractPalette(Image image, int maxPaletteSize, int *extractCount) } free(pixels); - + *extractCount = palCount; - + return palette; } @@ -1595,7 +1595,7 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) UnloadImage(srcCopy); // Source copy not required any more... Vector4 fsrc, fdst, fout; // float based versions of pixel data - + // Blit pixels, copy source image into destination // TODO: Probably out-of-bounds blitting could be considered here instead of so much cropping... for (int j = (int)dstRec.y; j < (int)(dstRec.y + dstRec.height); j++) @@ -1603,12 +1603,12 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) for (int i = (int)dstRec.x; i < (int)(dstRec.x + dstRec.width); i++) { // Alpha blending (https://en.wikipedia.org/wiki/Alpha_compositing) - + fdst = ColorNormalize(dstPixels[j*(int)dst->width + i]); fsrc = ColorNormalize(srcPixels[(j - (int)dstRec.y)*(int)dstRec.width + (i - (int)dstRec.x)]); fout.w = fsrc.w + fdst.w*(1.0f - fsrc.w); - + if (fout.w <= 0.0f) { fout.x = 0.0f; @@ -1622,9 +1622,9 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) fout.z = (fsrc.z*fsrc.w + fdst.z*fdst.w*(1 - fsrc.w))/fout.w; } - dstPixels[j*(int)dst->width + i] = (Color){ (unsigned char)(fout.x*255.0f), - (unsigned char)(fout.y*255.0f), - (unsigned char)(fout.z*255.0f), + dstPixels[j*(int)dst->width + i] = (Color){ (unsigned char)(fout.x*255.0f), + (unsigned char)(fout.y*255.0f), + (unsigned char)(fout.z*255.0f), (unsigned char)(fout.w*255.0f) }; // TODO: Support other blending options @@ -1662,16 +1662,16 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co // TODO: ISSUE: Measured text size does not seem to be correct... issue on ImageDraw() Vector2 imSize = MeasureTextEx(font, text, (float)font.baseSize, spacing); - + TraceLog(LOG_DEBUG, "Text Image size: %f, %f", imSize.x, imSize.y); // NOTE: glGetTexImage() not available in OpenGL ES - // TODO: This is horrible, retrieving font texture from GPU!!! + // TODO: This is horrible, retrieving font texture from GPU!!! // Define ImageFont struct? or include Image spritefont in Font struct? Image imFont = GetTextureData(font.texture); - + ImageFormat(&imFont, UNCOMPRESSED_R8G8B8A8); // Make sure image format could be properly colored! - + ImageColorTint(&imFont, tint); // Apply color tint to font // Create image to store text @@ -1702,10 +1702,10 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co else index = GetGlyphIndex(font, (unsigned char)text[i]); CharInfo letter = font.chars[index]; - + if ((unsigned char)text[i] != ' ') { - ImageDraw(&imText, imFont, letter.rec, (Rectangle){ (float)(posX + letter.offsetX), + ImageDraw(&imText, imFont, letter.rec, (Rectangle){ (float)(posX + letter.offsetX), (float)letter.offsetY, (float)letter.rec.width, (float)letter.rec.height }); } @@ -1734,11 +1734,11 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co void ImageDrawRectangle(Image *dst, Vector2 position, Rectangle rec, Color color) { Image imRec = GenImageColor((int)rec.width, (int)rec.height, color); - + Rectangle dstRec = { position.x, position.y, (float)imRec.width, (float)imRec.height }; ImageDraw(dst, imRec, rec, dstRec); - + UnloadImage(imRec); } @@ -2056,13 +2056,13 @@ void ImageColorReplace(Image *image, Color color, Color replace) Image GenImageColor(int width, int height, Color color) { Color *pixels = (Color *)calloc(width*height, sizeof(Color)); - + for (int i = 0; i < width*height; i++) pixels[i] = color; - + Image image = LoadImageEx(pixels, width, height); - + free(pixels); - + return image; } @@ -2120,17 +2120,17 @@ Image GenImageGradientRadial(int width, int height, float density, Color inner, float centerX = (float)width/2.0f; float centerY = (float)height/2.0f; - + for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { float dist = hypotf((float)x - centerX, (float)y - centerY); float factor = (dist - radius*density)/(radius*(1.0f - density)); - + factor = (float)fmax(factor, 0.f); factor = (float)fmin(factor, 1.f); // dist can be bigger than radius so we have to check - + pixels[y*width + x].r = (int)((float)outer.r*factor + (float)inner.r*(1.0f - factor)); pixels[y*width + x].g = (int)((float)outer.g*factor + (float)inner.g*(1.0f - factor)); pixels[y*width + x].b = (int)((float)outer.b*factor + (float)inner.b*(1.0f - factor)); @@ -2192,7 +2192,7 @@ Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float { float nx = (float)(x + offsetX)*scale/(float)width; float ny = (float)(y + offsetY)*scale/(float)height; - + // Typical values to start playing with: // lacunarity = ~2.0 -- spacing between successive octaves (use exactly 2.0 for wrapping output) // gain = 0.5 -- relative weighting applied to each successive octave @@ -2200,7 +2200,7 @@ Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float // NOTE: We need to translate the data from [-1..1] to [0..1] float p = (stb_perlin_fbm_noise3(nx, ny, 1.0f, 2.0f, 0.5f, 6, 0, 0, 0) + 1.0f)/2.0f; - + int intensity = (int)(p*255.0f); pixels[y*width + x] = (Color){intensity, intensity, intensity, 255}; } @@ -2233,7 +2233,7 @@ Image GenImageCellular(int width, int height, int tileSize) for (int y = 0; y < height; y++) { int tileY = y/tileSize; - + for (int x = 0; x < width; x++) { int tileX = x/tileSize; @@ -2263,7 +2263,7 @@ Image GenImageCellular(int width, int height, int tileSize) pixels[y*width + x] = (Color){ intensity, intensity, intensity, 255 }; } } - + free(seeds); Image image = LoadImageEx(pixels, width, height); @@ -2411,7 +2411,7 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V { float width = (float)texture.width; float height = (float)texture.height; - + if (sourceRec.width < 0) sourceRec.x -= sourceRec.width; if (sourceRec.height < 0) sourceRec.y -= sourceRec.height; @@ -2729,7 +2729,7 @@ static Image LoadDDS(const char *fileName) image.width = ddsHeader.width; image.height = ddsHeader.height; - + if (ddsHeader.mipmapCount == 0) image.mipmaps = 1; // Parameter not used else image.mipmaps = ddsHeader.mipmapCount; @@ -2946,9 +2946,9 @@ static Image LoadKTX(const char *fileName) // KTX file Header (64 bytes) // v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/ // v2.0 - http://github.khronos.org/KTX-Specification/ - + // TODO: Support KTX 2.2 specs! - + typedef struct { char id[12]; // Identifier: "«KTX 11»\r\n\x1A\n" unsigned int endianness; // Little endian: 0x01 0x02 0x03 0x04 @@ -3028,11 +3028,11 @@ static Image LoadKTX(const char *fileName) static int SaveKTX(Image image, const char *fileName) { int success = 0; - + // KTX file Header (64 bytes) // v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/ // v2.0 - http://github.khronos.org/KTX-Specification/ - still on draft, not ready for implementation - + typedef struct { char id[12]; // Identifier: "«KTX 11»\r\n\x1A\n" // KTX 2.0: "«KTX 22»\r\n\x1A\n" unsigned int endianness; // Little endian: 0x01 0x02 0x03 0x04 @@ -3060,11 +3060,11 @@ static int SaveKTX(Image image, const char *fileName) else { KTXHeader ktxHeader; - + // KTX identifier (v2.2) //unsigned char id[12] = { '«', 'K', 'T', 'X', ' ', '1', '1', '»', '\r', '\n', '\x1A', '\n' }; //unsigned char id[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A }; - + // Get the image header strcpy(ktxHeader.id, "«KTX 11»\r\n\x1A\n"); // KTX 1.1 signature ktxHeader.endianness = 0; @@ -3080,28 +3080,28 @@ static int SaveKTX(Image image, const char *fileName) ktxHeader.faces = 1; ktxHeader.mipmapLevels = image.mipmaps; // If it was 0, it means mipmaps should be generated on loading (not for compressed formats) ktxHeader.keyValueDataSize = 0; // No extra data after the header - + rlGetGlTextureFormats(image.format, &ktxHeader.glInternalFormat, &ktxHeader.glFormat, &ktxHeader.glType); // rlgl module function ktxHeader.glBaseInternalFormat = ktxHeader.glFormat; // KTX 1.1 only - + // NOTE: We can save into a .ktx all PixelFormats supported by raylib, including compressed formats like DXT, ETC or ASTC - + if (ktxHeader.glFormat == -1) TraceLog(LOG_WARNING, "Image format not supported for KTX export."); else { success = fwrite(&ktxHeader, sizeof(KTXHeader), 1, ktxFile); - + int width = image.width; int height = image.height; int dataOffset = 0; - + // Save all mipmaps data for (int i = 0; i < image.mipmaps; i++) { unsigned int dataSize = GetPixelDataSize(width, height, image.format); success = fwrite(&dataSize, sizeof(unsigned int), 1, ktxFile); success = fwrite((unsigned char *)image.data + dataOffset, dataSize, 1, ktxFile); - + width /= 2; height /= 2; dataOffset += dataSize; @@ -3110,7 +3110,7 @@ static int SaveKTX(Image image, const char *fileName) fclose(ktxFile); // Close file pointer } - + // If all data has been written correctly to file, success = 1 return success; } @@ -3321,7 +3321,7 @@ static Image LoadASTC(const char *fileName) TraceLog(LOG_DEBUG, "ASTC image width: %i", image.width); TraceLog(LOG_DEBUG, "ASTC image height: %i", image.height); TraceLog(LOG_DEBUG, "ASTC image blocks: %ix%i", astcHeader.blockX, astcHeader.blockY); - + image.mipmaps = 1; // NOTE: ASTC format only contains one mipmap level // NOTE: Each block is always stored in 128bit so we can calculate the bpp