| /******************************************************************************************* | |
| * | |
| *   raylib [core] example - loading thread | |
| * | |
| *   NOTE: This example requires linking with pthreads library on MinGW,  | |
| *   it can be accomplished passing -static parameter to compiler | |
| * | |
| *   Example originally created with raylib 2.5, last time updated with raylib 3.0 | |
| * | |
| *   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, | |
| * | |
| *   Copyright (c) 2014-2024 Ramon Santamaria (@raysan5) | |
| * | |
| ********************************************************************************************/ | |
| 
 | |
| #include "raylib.h" | |
|  | |
| // WARNING: This example does not build on Windows with MSVC compiler | |
| #include "pthread.h"                        // POSIX style threads management | |
|  | |
| #include <stdatomic.h>                      // C11 atomic data types | |
|  | |
| #include <time.h>                           // Required for: clock() | |
|  | |
| // Using C11 atomics for synchronization | |
| // NOTE: A plain bool (or any plain data type for that matter) can't be used for inter-thread synchronization | |
| static atomic_bool dataLoaded = false; // Data Loaded completion indicator | |
| static void *LoadDataThread(void *arg);     // Loading data thread function declaration | |
|  | |
| static atomic_int dataProgress = 0;                // Data progress accumulator | |
|  | |
| //------------------------------------------------------------------------------------ | |
| // Program main entry point | |
| //------------------------------------------------------------------------------------ | |
| int main(void) | |
| { | |
|     // Initialization | |
|     //-------------------------------------------------------------------------------------- | |
|     const int screenWidth = 800; | |
|     const int screenHeight = 450; | |
| 
 | |
|     InitWindow(screenWidth, screenHeight, "raylib [core] example - loading thread"); | |
| 
 | |
|     pthread_t threadId = { 0 };     // Loading data thread id | |
|  | |
|     enum { STATE_WAITING, STATE_LOADING, STATE_FINISHED } state = STATE_WAITING; | |
|     int framesCounter = 0; | |
| 
 | |
|     SetTargetFPS(60);               // Set our game to run at 60 frames-per-second | |
|     //-------------------------------------------------------------------------------------- | |
|  | |
|     // Main game loop | |
|     while (!WindowShouldClose())    // Detect window close button or ESC key | |
|     { | |
|         // Update | |
|         //---------------------------------------------------------------------------------- | |
|         switch (state) | |
|         { | |
|             case STATE_WAITING: | |
|             { | |
|                 if (IsKeyPressed(KEY_ENTER)) | |
|                 { | |
|                     int error = pthread_create(&threadId, NULL, &LoadDataThread, NULL); | |
|                     if (error != 0) TraceLog(LOG_ERROR, "Error creating loading thread"); | |
|                     else TraceLog(LOG_INFO, "Loading thread initialized successfully"); | |
| 
 | |
|                     state = STATE_LOADING; | |
|                 } | |
|             } break; | |
|             case STATE_LOADING: | |
|             { | |
|                 framesCounter++; | |
|                 if (atomic_load_explicit(&dataLoaded, memory_order_relaxed)) | |
|                 { | |
|                     framesCounter = 0; | |
|                     int error = pthread_join(threadId, NULL); | |
|                     if (error != 0) TraceLog(LOG_ERROR, "Error joining loading thread"); | |
|                     else TraceLog(LOG_INFO, "Loading thread terminated successfully"); | |
| 
 | |
|                     state = STATE_FINISHED; | |
|                 } | |
|             } break; | |
|             case STATE_FINISHED: | |
|             { | |
|                 if (IsKeyPressed(KEY_ENTER)) | |
|                 { | |
|                     // Reset everything to launch again | |
|                     atomic_store_explicit(&dataLoaded, false, memory_order_relaxed); | |
|                     atomic_store_explicit(&dataProgress, 0, memory_order_relaxed); | |
|                     state = STATE_WAITING; | |
|                 } | |
|             } break; | |
|             default: break; | |
|         } | |
|         //---------------------------------------------------------------------------------- | |
|  | |
|         // Draw | |
|         //---------------------------------------------------------------------------------- | |
|         BeginDrawing(); | |
| 
 | |
|             ClearBackground(RAYWHITE); | |
| 
 | |
|             switch (state) | |
|             { | |
|                 case STATE_WAITING: DrawText("PRESS ENTER to START LOADING DATA", 150, 170, 20, DARKGRAY); break; | |
|                 case STATE_LOADING: | |
|                 { | |
|                     DrawRectangle(150, 200, atomic_load_explicit(&dataProgress, memory_order_relaxed), 60, SKYBLUE); | |
|                     if ((framesCounter/15)%2) DrawText("LOADING DATA...", 240, 210, 40, DARKBLUE); | |
| 
 | |
|                 } break; | |
|                 case STATE_FINISHED: | |
|                 { | |
|                     DrawRectangle(150, 200, 500, 60, LIME); | |
|                     DrawText("DATA LOADED!", 250, 210, 40, GREEN); | |
| 
 | |
|                 } break; | |
|                 default: break; | |
|             } | |
| 
 | |
|             DrawRectangleLines(150, 200, 500, 60, DARKGRAY); | |
| 
 | |
|         EndDrawing(); | |
|         //---------------------------------------------------------------------------------- | |
|     } | |
| 
 | |
|     // De-Initialization | |
|     //-------------------------------------------------------------------------------------- | |
|     CloseWindow();        // Close window and OpenGL context | |
|     //-------------------------------------------------------------------------------------- | |
|  | |
|     return 0; | |
| } | |
| 
 | |
| // Loading data thread function definition | |
| static void *LoadDataThread(void *arg) | |
| { | |
|     int timeCounter = 0;            // Time counted in ms | |
|     clock_t prevTime = clock();     // Previous time | |
|  | |
|     // We simulate data loading with a time counter for 5 seconds | |
|     while (timeCounter < 5000) | |
|     { | |
|         clock_t currentTime = clock() - prevTime; | |
|         timeCounter = currentTime*1000/CLOCKS_PER_SEC; | |
| 
 | |
|         // We accumulate time over a global variable to be used in | |
|         // main thread as a progress bar | |
|         atomic_store_explicit(&dataProgress, timeCounter/10, memory_order_relaxed); | |
|     } | |
| 
 | |
|     // When data has finished loading, we set global variable | |
|     atomic_store_explicit(&dataLoaded, true, memory_order_relaxed); | |
| 
 | |
|     return NULL; | |
| }
 |