mirror of
				https://github.com/raysan5/raylib.git
				synced 2025-10-26 12:27:01 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			230 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			230 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*******************************************************************************************
 | |
| *
 | |
| *   raylib [shapes] example - clock of clocks
 | |
| *
 | |
| *   Example complexity rating: [★★☆☆] 2/4
 | |
| *
 | |
| *   Example originally created with raylib 5.5, last time updated with raylib 5.6-dev
 | |
| *
 | |
| *   Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5)
 | |
| *
 | |
| *   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
 | |
| *   BSD-like license that allows static linking with closed source software
 | |
| *
 | |
| *   Copyright (c) 2025 JP Mortiboys (@themushroompirates)
 | |
| *
 | |
| ********************************************************************************************/
 | |
| #if defined(WIN32)
 | |
| #define _CRT_SECURE_NO_WARNINGS
 | |
| #endif
 | |
| 
 | |
| #include "raylib.h"
 | |
| 
 | |
| #include "raymath.h"    // Required for: Lerp()
 | |
| #include <time.h>       // Required for: time(), localtime()
 | |
| 
 | |
| //------------------------------------------------------------------------------------
 | |
| // Program main entry point
 | |
| //------------------------------------------------------------------------------------
 | |
| int main(void)
 | |
| {
 | |
|     // Initialization
 | |
|     //--------------------------------------------------------------------------------------
 | |
|     const int screenWidth = 800;
 | |
|     const int screenHeight = 450;
 | |
| 
 | |
|     SetConfigFlags(FLAG_MSAA_4X_HINT);
 | |
|     InitWindow(screenWidth, screenHeight, "raylib [shapes] example - clock of clocks");
 | |
|     
 | |
|     const Color bgColor = ColorLerp(DARKBLUE, BLACK, 0.75f);
 | |
|     const Color handsColor = ColorLerp(YELLOW, RAYWHITE, .25f);
 | |
|     
 | |
|     const float clockFaceSize = 24;
 | |
|     const float clockFaceSpacing = 8.0f;
 | |
|     const float sectionSpacing = 16.0f;
 | |
|     
 | |
|     const Vector2 TL = (Vector2){   0.0f,  90.0f }; // Top-left corner
 | |
|     const Vector2 TR = (Vector2){  90.0f, 180.0f }; // Top-right corner
 | |
|     const Vector2 BR = (Vector2){ 180.0f, 270.0f }; // Bottom-right corner
 | |
|     const Vector2 BL = (Vector2){   0.0f, 270.0f }; // Bottom-left corner
 | |
|     const Vector2 HH = (Vector2){   0.0f, 180.0f }; // Horizontal line
 | |
|     const Vector2 VV = (Vector2){  90.0f, 270.0f }; // Vertical line
 | |
|     const Vector2 ZZ = (Vector2){ 135.0f, 135.0f }; // Not relevant
 | |
|     
 | |
|     const Vector2 digitAngles[10][24] = {
 | |
|         /* 0 */ { TL,HH,HH,TR, /* */ VV,TL,TR,VV,/* */ VV,VV,VV,VV,/* */ VV,VV,VV,VV,/* */ VV,BL,BR,VV,/* */ BL,HH,HH,BR },
 | |
|         /* 1 */ { TL,HH,TR,ZZ, /* */ BL,TR,VV,ZZ,/* */ ZZ,VV,VV,ZZ,/* */ ZZ,VV,VV,ZZ,/* */ TL,BR,BL,TR,/* */ BL,HH,HH,BR },
 | |
|         /* 2 */ { TL,HH,HH,TR, /* */ BL,HH,TR,VV,/* */ TL,HH,BR,VV,/* */ VV,TL,HH,BR,/* */ VV,BL,HH,TR,/* */ BL,HH,HH,BR },
 | |
|         /* 3 */ { TL,HH,HH,TR, /* */ BL,HH,TR,VV,/* */ TL,HH,BR,VV,/* */ BL,HH,TR,VV,/* */ TL,HH,BR,VV,/* */ BL,HH,HH,BR },
 | |
|         /* 4 */ { TL,TR,TL,TR, /* */ VV,VV,VV,VV,/* */ VV,BL,BR,VV,/* */ BL,HH,TR,VV,/* */ ZZ,ZZ,VV,VV,/* */ ZZ,ZZ,BL,BR },
 | |
|         /* 5 */ { TL,HH,HH,TR, /* */ VV,TL,HH,BR,/* */ VV,BL,HH,TR,/* */ BL,HH,TR,VV,/* */ TL,HH,BR,VV,/* */ BL,HH,HH,BR },
 | |
|         /* 6 */ { TL,HH,HH,TR, /* */ VV,TL,HH,BR,/* */ VV,BL,HH,TR,/* */ VV,TL,TR,VV,/* */ VV,BL,BR,VV,/* */ BL,HH,HH,BR },
 | |
|         /* 7 */ { TL,HH,HH,TR, /* */ BL,HH,TR,VV,/* */ ZZ,ZZ,VV,VV,/* */ ZZ,ZZ,VV,VV,/* */ ZZ,ZZ,VV,VV,/* */ ZZ,ZZ,BL,BR },
 | |
|         /* 8 */ { TL,HH,HH,TR, /* */ VV,TL,TR,VV,/* */ VV,BL,BR,VV,/* */ VV,TL,TR,VV,/* */ VV,BL,BR,VV,/* */ BL,HH,HH,BR },
 | |
|         /* 9 */ { TL,HH,HH,TR, /* */ VV,TL,TR,VV,/* */ VV,BL,BR,VV,/* */ BL,HH,TR,VV,/* */ TL,HH,BR,VV,/* */ BL,HH,HH,BR },
 | |
|     };
 | |
|     // Time for the hands to move to the new position (in seconds); this must be <1s
 | |
|     const float handsMoveDuration = .5f;
 | |
|     
 | |
|     // We store the previous seconds value so we can see if the time has changed
 | |
|     int prevSeconds = -1;
 | |
|     
 | |
|     // This represents the real position where the hands are right now
 | |
|     Vector2 currentAngles[6][24] = { 0 };
 | |
|     
 | |
|     // This is the position where the hands were moving from
 | |
|     Vector2 srcAngles[6][24] = { 0 };
 | |
|     // This is the position where the hands are moving to
 | |
|     Vector2 dstAngles[6][24] = { 0 };
 | |
|     
 | |
|     // Current animation timer
 | |
|     float handsMoveTimer = 0.0f;
 | |
|     
 | |
|     // 12 or 24 hour mode
 | |
|     int hourMode = 24;
 | |
| 
 | |
|     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
 | |
|         //----------------------------------------------------------------------------------
 | |
|         
 | |
|         // Get the current time
 | |
|         time_t rawtime;
 | |
|         struct tm *timeinfo;
 | |
| 
 | |
|         time(&rawtime);
 | |
|         timeinfo = localtime(&rawtime);
 | |
|         
 | |
|         if (timeinfo->tm_sec != prevSeconds) {
 | |
|             // The time has changed, so we need to move the hands to the new positions
 | |
|             prevSeconds = timeinfo->tm_sec;
 | |
|         
 | |
|             // Format the current time so we can access the individual digits
 | |
|             const char *clockDigits = TextFormat("%02d%02d%02d", timeinfo->tm_hour % hourMode, timeinfo->tm_min, timeinfo->tm_sec);
 | |
|         
 | |
|             // Fetch where we want all the hands to be
 | |
|             for (int digit = 0; digit < 6; digit++) {
 | |
|                 for (int cell = 0; cell < 24; cell++) {
 | |
|                     srcAngles[digit][cell] = currentAngles[digit][cell];
 | |
|                     dstAngles[digit][cell] = digitAngles[ clockDigits[digit] - '0' ][cell];
 | |
|                     
 | |
|                     // Quick exception for 12h mode
 | |
|                     if (digit == 0 && hourMode == 12 && clockDigits[0] == '0') {
 | |
|                         dstAngles[digit][cell] = ZZ;
 | |
|                     }
 | |
|                     
 | |
|                     if (srcAngles[digit][cell].x > dstAngles[digit][cell].x) {
 | |
|                         srcAngles[digit][cell].x -= 360.0f;
 | |
|                     }
 | |
|                     if (srcAngles[digit][cell].y > dstAngles[digit][cell].y) {
 | |
|                         srcAngles[digit][cell].y -= 360.0f;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             
 | |
|             // Reset the timer
 | |
|             handsMoveTimer = -GetFrameTime();
 | |
|         }
 | |
|         
 | |
|         // Now let's animate all the hands if we need to
 | |
|         if (handsMoveTimer < handsMoveDuration) {
 | |
|             // Increase the timer but don't go above the maximum
 | |
|             handsMoveTimer = Clamp(handsMoveTimer + GetFrameTime(), 0, handsMoveDuration);
 | |
|             
 | |
|             // Calculate the % completion of the animation
 | |
|             float t = handsMoveTimer / handsMoveDuration;
 | |
|             
 | |
|             // A little cheeky smoothstep
 | |
|             t = t * t * (3.0f - 2.0f * t);
 | |
|             
 | |
|             for (int digit = 0; digit < 6; digit++) {
 | |
|                 for (int cell = 0; cell < 24; cell++) {
 | |
|                     currentAngles[digit][cell].x = Lerp(srcAngles[digit][cell].x, dstAngles[digit][cell].x, t);
 | |
|                     currentAngles[digit][cell].y = Lerp(srcAngles[digit][cell].y, dstAngles[digit][cell].y, t);
 | |
|                 }
 | |
|             }
 | |
|             
 | |
|             if (handsMoveTimer == handsMoveDuration) {
 | |
|                 // The animation has now finished
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         // Handle input
 | |
|         
 | |
|         // Toggle between 12 and 24 hour mode with space
 | |
|         if (IsKeyPressed(KEY_SPACE)) {
 | |
|             hourMode = 36 - hourMode;
 | |
|         }
 | |
|         
 | |
|         
 | |
|         
 | |
|         //----------------------------------------------------------------------------------
 | |
| 
 | |
|         // Draw
 | |
|         //----------------------------------------------------------------------------------
 | |
|         BeginDrawing();
 | |
| 
 | |
|             ClearBackground(bgColor);
 | |
|             
 | |
|             DrawText(TextFormat("%d-h mode, space to change", hourMode), 10, 30, 20, RAYWHITE);
 | |
|             
 | |
|             float xOffset = 4.0f;
 | |
|             
 | |
|             for (int digit = 0; digit < 6; digit++) {
 | |
|             
 | |
|                 for (int row = 0; row < 6; row++) {
 | |
|                     for (int col = 0; col < 4; col++) {
 | |
|                         Vector2 centre = (Vector2){
 | |
|                             xOffset + col*(clockFaceSize+clockFaceSpacing) + clockFaceSize * .5f,
 | |
|                             100 + row*(clockFaceSize+clockFaceSpacing) + clockFaceSize * .5f
 | |
|                         };
 | |
|                         DrawRing(centre, clockFaceSize * 0.5f - 2.0f, clockFaceSize * 0.5f, 0, 360, 24, DARKGRAY);
 | |
|                         
 | |
|                         // Big hand
 | |
|                         DrawRectanglePro(
 | |
|                             (Rectangle){centre.x, centre.y, clockFaceSize*.5f+4.0f, 4.0f},
 | |
|                             (Vector2){ 2.0f, 2.0f },
 | |
|                             currentAngles[digit][row*4+col].x,
 | |
|                             handsColor
 | |
|                         );
 | |
|                         
 | |
|                         // Little hand
 | |
|                         DrawRectanglePro(
 | |
|                             (Rectangle){centre.x, centre.y, clockFaceSize*.5f+2.0f, 4.0f},
 | |
|                             (Vector2){ 2.0f, 2.0f },
 | |
|                             currentAngles[digit][row*4+col].y,
 | |
|                             handsColor
 | |
|                         );
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 xOffset += (clockFaceSize+clockFaceSpacing) * 4;
 | |
|                 if (digit % 2 == 1) {
 | |
|                     
 | |
|                     DrawRing((Vector2){xOffset + 4.0f, 160.0f}, 6.0f, 8.0f, 0.0f, 360.0f, 24, handsColor);
 | |
|                     DrawRing((Vector2){xOffset + 4.0f, 225.0f}, 6.0f, 8.0f, 0.0f, 360.0f, 24, handsColor);
 | |
|                     
 | |
|                     xOffset += sectionSpacing;
 | |
|                     
 | |
|                 }
 | |
|             }
 | |
|             
 | |
|             DrawFPS(10, 10);
 | |
|             
 | |
| 
 | |
|         EndDrawing();
 | |
|         //----------------------------------------------------------------------------------
 | |
|     }
 | |
| 
 | |
|     // De-Initialization
 | |
|     //--------------------------------------------------------------------------------------
 | |
| 
 | |
|     CloseWindow();          // Close window and OpenGL context
 | |
|     //--------------------------------------------------------------------------------------
 | |
| 
 | |
|     return 0;
 | |
| } | 
