소스 검색

REDESIGNED: example: `shapes_digital_clock`

Ray 2 일 전
부모
커밋
a42eb2f79b
2개의 변경된 파일174개의 추가작업 그리고 43개의 파일을 삭제
  1. 174 43
      examples/shapes/shapes_digital_clock.c
  2. BIN
      examples/shapes/shapes_digital_clock.png

+ 174 - 43
examples/shapes/shapes_digital_clock.c

@@ -11,7 +11,7 @@
 *   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 Hamza RAHAL (@hmz-rhl)
+*   Copyright (c) 2025 Hamza RAHAL (@hmz-rhl) and Ramon Santamaria (@raysan5)
 *
 ********************************************************************************************/
 
@@ -20,37 +20,40 @@
 #include <math.h>       // Required for: cosf(), sinf()
 #include <time.h>       // Required for: time(), localtime()
 
-#define DIGIT_SIZE 30
+#define CLOCK_ANALOG    0
+#define CLOCK_DIGITAL   1
 
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
-typedef enum {
-    MODE_NORMAL = 0,
-    MODE_HANDS_FREE,
-} ClockMode;
-
+// Clock hand type
 typedef struct {
-    int value;
-    Vector2 origin;
-    float angle;
-    int length;
-    int thickness;
-    Color color;
+    int value;          // Time value
+
+    // Visual elements
+    float angle;        // Hand angle
+    int length;         // Hand length
+    int thickness;      // Hand thickness
+    Color color;        // Hand color
 } ClockHand;
 
+// Clock hands
 typedef struct {
-    ClockMode mode;
-    ClockHand second;
-    ClockHand minute;
-    ClockHand hour;
+    ClockHand second;   // Clock hand for seconds
+    ClockHand minute;   // Clock hand for minutes
+    ClockHand hour;     // Clock hand for hours
 } Clock;
 
 //----------------------------------------------------------------------------------
 // Module Functions Declaration
 //----------------------------------------------------------------------------------
 static void UpdateClock(Clock *clock); // Update clock time
-static void DrawClock(Clock clock, Vector2 centerPos); // Draw clock at desired position
+static void DrawClockAnalog(Clock clock, Vector2 position); // Draw analog clock at desired center position
+static void DrawClockDigital(Clock clock, Vector2 position); // Draw digital clock at desired position
+
+static void DrawDisplayValue(Vector2 position, int value, Color colorOn, Color colorOff);
+static void Draw7SDisplay(Vector2 position, char segments, Color colorOn, Color colorOff);
+static void DrawDisplaySegment(Vector2 center, int length, int thick, bool vertical, Color color);
 
 //------------------------------------------------------------------------------------
 // Program main entry point
@@ -62,16 +65,18 @@ int main(void)
     const int screenWidth = 800;
     const int screenHeight = 450;
 
+    SetConfigFlags(FLAG_MSAA_4X_HINT);
     InitWindow(screenWidth, screenHeight, "raylib [shapes] example - digital clock");
 
-    // Initialize clock
-    Clock myClock = {
-        .mode = MODE_NORMAL,
+    int clockMode = CLOCK_DIGITAL;
 
+    // Initialize clock
+    // NOTE: Includes visual info for anlaog clock
+    Clock clock = {
         .second.angle = 45,
         .second.length = 140,
         .second.thickness = 3,
-        .second.color = BEIGE,
+        .second.color = MAROON,
 
         .minute.angle = 10,
         .minute.length = 130,
@@ -94,11 +99,12 @@ int main(void)
         //----------------------------------------------------------------------------------
         if (IsKeyPressed(KEY_SPACE))
         {
-            if (myClock.mode == MODE_HANDS_FREE) myClock.mode = MODE_NORMAL;
-            else if (myClock.mode == MODE_NORMAL) myClock.mode = MODE_HANDS_FREE;
+            // Toggle clock mode
+            if (clockMode == CLOCK_DIGITAL) clockMode = CLOCK_ANALOG;
+            else if (clockMode == CLOCK_ANALOG) clockMode = CLOCK_DIGITAL;
         }
 
-        UpdateClock(&myClock);
+        UpdateClock(&clock); // Update clock required data: value and angle
         //----------------------------------------------------------------------------------
 
         // Draw
@@ -107,11 +113,21 @@ int main(void)
 
             ClearBackground(RAYWHITE);
 
-            DrawCircle(400, 225, 5, BLACK); // Clock center dot
+            // Draw clock in selected mode
+            if (clockMode == CLOCK_ANALOG) DrawClockAnalog(clock, (Vector2){ 400, 240 }); 
+            else if (clockMode == CLOCK_DIGITAL)
+            {
+                DrawClockDigital(clock, (Vector2){ 30, 60 });
 
-            DrawClock(myClock, (Vector2){ 400, 225 }); // Clock in selected mode
+                // Draw clock using default raylib font
+                // Get pointer to formated clock time string
+                // WARNING: Pointing to an internal static string that is reused between TextFormat() calls
+                const char *clockTime = TextFormat("%02i:%02i:%02i", clock.hour.value, clock.minute.value, clock.second.value);
+                DrawText(clockTime, GetScreenWidth()/2 - MeasureText(clockTime, 150)/2, 300, 150, BLACK);
+            }
 
-            DrawText("Press [SPACE] to switch clock mode", 10, 10, 20, DARKGRAY);
+            DrawText(TextFormat("Press [SPACE] to switch clock mode: %s", 
+                (clockMode == CLOCK_DIGITAL)? "DIGITAL CLOCK" : "ANALOGUE CLOCK"), 10, 10, 20, DARKGRAY);
 
         EndDrawing();
         //----------------------------------------------------------------------------------
@@ -154,31 +170,146 @@ static void UpdateClock(Clock *clock)
     clock->second.angle -= 90;
 }
 
-// Draw clock
-static void DrawClock(Clock clock, Vector2 centerPosition)
+// Draw analog clock
+// Parameter: position, refers to center position
+static void DrawClockAnalog(Clock clock, Vector2 position)
 {
-    if (clock.mode == MODE_HANDS_FREE)
-    {
-        DrawCircleLinesV(centerPosition, clock.minute.length, LIGHTGRAY);
+        // Draw clock base
+        DrawCircleV(position, clock.second.length + 40, LIGHTGRAY);
+        DrawCircleV(position, 12, GRAY);
 
-        DrawText(TextFormat("%i", clock.second.value), centerPosition.x + (clock.second.length - 10)*cosf(clock.second.angle*(float)(PI/180)) - DIGIT_SIZE/2, centerPosition.y + clock.second.length*sinf(clock.second.angle*(float)(PI/180)) - DIGIT_SIZE/2, DIGIT_SIZE, GRAY);
-
-        DrawText(TextFormat("%i", clock.minute.value), centerPosition.x + clock.minute.length*cosf(clock.minute.angle*(float)(PI/180)) - DIGIT_SIZE/2, centerPosition.y + clock.minute.length*sinf(clock.minute.angle*(float)(PI/180)) - DIGIT_SIZE/2, DIGIT_SIZE, RED);
+        // Draw clock minutes/seconds lines
+        for (int i = 0; i < 60; i++)
+        {
+            DrawLineEx((Vector2){ position.x + (clock.second.length + ((i%5)? 10 : 6))*cosf((6.0f*i - 90.0f)*DEG2RAD), 
+                position.y + (clock.second.length + ((i%5)? 10 : 6))*sinf((6.0f*i - 90.0f)*DEG2RAD) }, 
+                (Vector2){ position.x + (clock.second.length + 20)*cosf((6.0f*i - 90.0f)*DEG2RAD), 
+                position.y + (clock.second.length + 20)*sinf((6.0f*i - 90.0f)*DEG2RAD) }, ((i%5)? 1.0f : 3.0f), DARKGRAY);
+            
+            // Draw seconds numbers
+            //DrawText(TextFormat("%02i", i), centerPosition.x + (clock.second.length + 50)*cosf((6.0f*i - 90.0f)*DEG2RAD) - 10/2, 
+            //    centerPosition.y + (clock.second.length + 50)*sinf((6.0f*i - 90.0f)*DEG2RAD) - 10/2, 10, GRAY);
+        }
 
-        DrawText(TextFormat("%i", clock.hour.value), centerPosition.x + clock.hour.length*cosf(clock.hour.angle*(float)(PI/180)) - DIGIT_SIZE/2, centerPosition.y + clock.hour.length*sinf(clock.hour.angle*(float)(PI/180)) - DIGIT_SIZE/2, DIGIT_SIZE, GOLD);
-    }
-    else if (clock.mode == MODE_NORMAL)
-    {
         // Draw hand seconds
-        DrawRectanglePro((Rectangle){ centerPosition.x, centerPosition.y, clock.second.length, clock.second.thickness },
+        DrawRectanglePro((Rectangle){ position.x, position.y, clock.second.length, clock.second.thickness },
             (Vector2){ 0.0f, clock.second.thickness/2.0f }, clock.second.angle, clock.second.color);
 
         // Draw hand minutes
-        DrawRectanglePro((Rectangle){ centerPosition.x, centerPosition.y, clock.minute.length, clock.minute.thickness },
+        DrawRectanglePro((Rectangle){ position.x, position.y, clock.minute.length, clock.minute.thickness },
             (Vector2){ 0.0f, clock.minute.thickness/2.0f }, clock.minute.angle, clock.minute.color);
 
         // Draw hand hours
-        DrawRectanglePro((Rectangle){ centerPosition.x, centerPosition.y, clock.hour.length, clock.hour.thickness },
+        DrawRectanglePro((Rectangle){ position.x, position.y, clock.hour.length, clock.hour.thickness },
             (Vector2){ 0.0f, clock.hour.thickness/2.0f }, clock.hour.angle, clock.hour.color);
+}
+
+// Draw digital clock
+// PARAM: position, refers to top-left corner
+static void DrawClockDigital(Clock clock, Vector2 position)
+{
+    // Draw clock using custom 7-segments display (made of shapes)
+    DrawDisplayValue((Vector2){ position.x, position.y }, clock.hour.value/10, RED, Fade(LIGHTGRAY, 0.3f));
+    DrawDisplayValue((Vector2){ position.x + 120, position.y }, clock.hour.value%10, RED, Fade(LIGHTGRAY, 0.3f));
+
+    DrawCircle(position.x + 240, position.y + 70, 12, (clock.second.value%2)? RED : Fade(LIGHTGRAY, 0.3f));
+    DrawCircle(position.x + 240, position.y + 150, 12, (clock.second.value%2)? RED : Fade(LIGHTGRAY, 0.3f));
+
+    DrawDisplayValue((Vector2){ position.x + 260, position.y }, clock.minute.value/10, RED, Fade(LIGHTGRAY, 0.3f));
+    DrawDisplayValue((Vector2){ position.x + 380, position.y }, clock.minute.value%10, RED, Fade(LIGHTGRAY, 0.3f));
+
+    DrawCircle(position.x + 500, position.y + 70, 12, (clock.second.value%2)? RED : Fade(LIGHTGRAY, 0.3f));
+    DrawCircle(position.x + 500, position.y + 150, 12, (clock.second.value%2)? RED : Fade(LIGHTGRAY, 0.3f));
+
+    DrawDisplayValue((Vector2){ position.x + 520, position.y }, clock.second.value/10, RED, Fade(LIGHTGRAY, 0.3f));
+    DrawDisplayValue((Vector2){ position.x + 640, position.y }, clock.second.value%10, RED, Fade(LIGHTGRAY, 0.3f));
+}
+
+// Draw 7-segment display with value
+static void DrawDisplayValue(Vector2 position, int value, Color colorOn, Color colorOff)
+{
+    switch (value)
+    {
+        case 0: Draw7SDisplay(position, 0b00111111, colorOn, colorOff); break;
+        case 1: Draw7SDisplay(position, 0b00000110, colorOn, colorOff); break;
+        case 2: Draw7SDisplay(position, 0b01011011, colorOn, colorOff); break;
+        case 3: Draw7SDisplay(position, 0b01001111, colorOn, colorOff); break;
+        case 4: Draw7SDisplay(position, 0b01100110, colorOn, colorOff); break;
+        case 5: Draw7SDisplay(position, 0b01101101, colorOn, colorOff); break;
+        case 6: Draw7SDisplay(position, 0b01111101, colorOn, colorOff); break;
+        case 7: Draw7SDisplay(position, 0b00000111, colorOn, colorOff); break;
+        case 8: Draw7SDisplay(position, 0b01111111, colorOn, colorOff); break;
+        case 9: Draw7SDisplay(position, 0b01101111, colorOn, colorOff); break;
+        default: break;
+    }
+}
+
+// Draw seven segments display
+// Parameter: position, refers to top-left corner of display
+// Parameter: segments, defines in binary the segments to be activated
+static void Draw7SDisplay(Vector2 position, char segments, Color colorOn, Color colorOff)
+{
+    int segmentLen = 60;
+    int segmentThick = 20;
+    float offsetYAdjust = segmentThick*0.3f; // HACK: Adjust gap space between segment limits
+
+    // Segment A
+    DrawDisplaySegment((Vector2){ position.x + segmentThick + segmentLen/2.0f, position.y + segmentThick }, 
+        segmentLen, segmentThick, false, (segments & 0b00000001)? colorOn : colorOff);
+    // Segment B
+    DrawDisplaySegment((Vector2){ position.x + segmentThick + segmentLen + segmentThick/2.0f, position.y + 2*segmentThick + segmentLen/2.0f - offsetYAdjust }, 
+        segmentLen, segmentThick, true, (segments & 0b00000010)? colorOn : colorOff);
+    // Segment C
+    DrawDisplaySegment((Vector2){ position.x + segmentThick + segmentLen + segmentThick/2.0f, position.y + 4*segmentThick + segmentLen + segmentLen/2.0f - 3*offsetYAdjust }, 
+        segmentLen, segmentThick, true, (segments & 0b00000100)? colorOn : colorOff);
+    // Segment D
+    DrawDisplaySegment((Vector2){ position.x + segmentThick + segmentLen/2.0f, position.y + 5*segmentThick + 2*segmentLen - 4*offsetYAdjust }, 
+        segmentLen, segmentThick, false, (segments & 0b00001000)? colorOn : colorOff);
+    // Segment E
+    DrawDisplaySegment((Vector2){ position.x + segmentThick/2.0f, position.y + 4*segmentThick + segmentLen + segmentLen/2.0f - 3*offsetYAdjust }, 
+        segmentLen, segmentThick, true, (segments & 0b00010000)? colorOn : colorOff);
+    // Segment F
+    DrawDisplaySegment((Vector2){ position.x + segmentThick/2.0f, position.y + 2*segmentThick + segmentLen/2.0f - offsetYAdjust }, 
+        segmentLen, segmentThick, true, (segments & 0b00100000)? colorOn : colorOff);
+    // Segment G
+    DrawDisplaySegment((Vector2){ position.x + segmentThick + segmentLen/2.0f, position.y + 3*segmentThick + segmentLen - 2*offsetYAdjust }, 
+        segmentLen, segmentThick, false, (segments & 0b01000000)? colorOn : colorOff);
+}
+
+// Draw one 7-segment display segment, horizontal or vertical
+static void DrawDisplaySegment(Vector2 center, int length, int thick, bool vertical, Color color)
+{
+    if (!vertical)
+    {
+        // Horizontal segment points
+        //   3___________________________5
+        //  /                             \
+        // /1             x               6\
+        // \                               /
+        //  \2___________________________4/
+        Vector2 segmentPointsH[6] = {
+            (Vector2){ center.x - length/2.0f - thick/2.0f,  center.y },  // Point 1
+            (Vector2){ center.x - length/2.0f,  center.y + thick/2.0f },  // Point 2
+            (Vector2){ center.x - length/2.0f, center.y - thick/2.0f },   // Point 3
+            (Vector2){ center.x + length/2.0f,  center.y + thick/2.0f },  // Point 4
+            (Vector2){ center.x + length/2.0f,  center.y - thick/2.0f },  // Point 5
+            (Vector2){ center.x + length/2.0f + thick/2.0f,  center.y },  // Point 6
+        };
+
+        DrawTriangleStrip(segmentPointsH, 6, color);
+    }
+    else
+    {
+        // Vertical segment points
+        Vector2 segmentPointsV[6] = {
+            (Vector2){ center.x,  center.y - length/2.0f - thick/2.0f },  // Point 1
+            (Vector2){ center.x - thick/2.0f,  center.y - length/2.0f },  // Point 2
+            (Vector2){ center.x + thick/2.0f, center.y - length/2.0f },   // Point 3
+            (Vector2){ center.x - thick/2.0f,  center.y + length/2.0f },  // Point 4
+            (Vector2){ center.x + thick/2.0f,  center.y + length/2.0f },  // Point 5
+            (Vector2){ center.x,  center.y + length/2 + thick/2.0f },     // Point 6
+        };
+
+        DrawTriangleStrip(segmentPointsV, 6, color);
     }
 }

BIN
examples/shapes/shapes_digital_clock.png