├── icon
└── icon.png
├── fonts
├── Oswald-Bold.ttf
└── OFL.txt
├── .github
└── docs
│ └── preview.png
├── .gitignore
├── .vscode
└── settings.json
├── config.json
├── launch.sh
├── src
├── main.c
├── destroy.c
├── init.c
├── pollevent.c
├── render.c
└── draw.c
├── include
├── KeyMap.h
└── FlipClock.h
├── README.md
└── Makefile
/icon/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JaeSeoKim/sdl-flip-clock/HEAD/icon/icon.png
--------------------------------------------------------------------------------
/fonts/Oswald-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JaeSeoKim/sdl-flip-clock/HEAD/fonts/Oswald-Bold.ttf
--------------------------------------------------------------------------------
/.github/docs/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JaeSeoKim/sdl-flip-clock/HEAD/.github/docs/preview.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Trash files
2 | .DS_Store
3 |
4 | # output
5 | objs
6 | flipClock
7 | FlipClock-v*.zip
8 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.associations": {
3 | "functional": "c",
4 | "flipclock.h": "c"
5 | },
6 | "color-highlight.useARGB": true,
7 | }
8 |
--------------------------------------------------------------------------------
/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "Flip Clock",
3 | "icon": "icon/icon.png",
4 | "launch": "launch.sh",
5 | "description": "Simple Filp Clock by JaeSeoKim (v1.1)"
6 | }
7 |
--------------------------------------------------------------------------------
/launch.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | cd /mnt/SDCARD/App/FlipClock/
3 |
4 | if pgrep flipClock > /dev/null; then
5 | killall -9 flipClock
6 | fi
7 |
8 | /mnt/SDCARD/App/FlipClock/flipClock
9 |
--------------------------------------------------------------------------------
/src/main.c:
--------------------------------------------------------------------------------
1 | #include "FlipClock.h"
2 |
3 | FlipClock _G = {
4 | 640, // DISPLAY_WIDTH
5 | 480, // DISPLAY_HEIGHT
6 | NULL, // Fill the remaining fields with NULL
7 | };
8 |
9 | void quit(int exitcode) {
10 | destroy();
11 | exit(exitcode);
12 | }
13 |
14 | int main() {
15 | int ret = EXIT_SUCCESS;
16 | signal(SIGTERM, quit);
17 | signal(SIGSEGV, quit);
18 |
19 | if (init() < 0) {
20 | printf("init failed\n");
21 | ret = EXIT_FAILURE;
22 | }
23 |
24 | if (draw_loop() < 0) {
25 | printf("draw_lopp failed\n");
26 | ret = EXIT_FAILURE;
27 | }
28 |
29 | destroy();
30 | return ret;
31 | }
32 |
--------------------------------------------------------------------------------
/src/destroy.c:
--------------------------------------------------------------------------------
1 | #include "FlipClock.h"
2 |
3 | void destroy() {
4 | printf("##Start destory\n");
5 |
6 | if (access("/tmp/stay_awake", F_OK) != -1) {
7 | printf("\tStop stay awake\n");
8 | remove("/tmp/stay_awake");
9 | }
10 |
11 | if (_G.renderer != NULL) {
12 | printf("\tdestorying renderer...\n");
13 | #if defined SDL && SDL == 1
14 | SDL_FreeSurface(_G.renderer);
15 | #else
16 | SDL_DestroyRenderer(_G.renderer);
17 | #endif
18 | }
19 |
20 | if (_G.window != NULL) {
21 | printf("\tdestorying window...\n");
22 | #if defined SDL && SDL == 1
23 | SDL_FreeSurface(_G.window);
24 | #else
25 | SDL_DestroyWindow(_G.window);
26 | #endif
27 | }
28 |
29 | if (_G.timeFont != NULL) {
30 | printf("\tClosing font...\n");
31 | TTF_CloseFont(_G.timeFont);
32 | }
33 | if (_G.ampmFont != NULL) {
34 | printf("\tClosing smFont...\n");
35 | TTF_CloseFont(_G.ampmFont);
36 | }
37 |
38 | TTF_Quit();
39 | SDL_Quit();
40 | printf("##Finish destory\n\n");
41 | }
42 |
--------------------------------------------------------------------------------
/include/KeyMap.h:
--------------------------------------------------------------------------------
1 | #ifndef KEYMAP_H__
2 | #define KEYMAP_H__
3 |
4 | #include "FlipClock.h"
5 |
6 | #if SDL != 1
7 | typedef SDL_Keycode SDLKey;
8 | #endif
9 |
10 | #define BTN_UP SDLK_UP
11 | #define BTN_UP_INDEX 0
12 | #define BTN_DOWN SDLK_DOWN
13 | #define BTN_DOWN_INDEX 1
14 | #define BTN_LEFT SDLK_LEFT
15 | #define BTN_LEFT_INDEX 2
16 | #define BTN_RIGHT SDLK_RIGHT
17 | #define BTN_RIGHT_INDEX 3
18 | #define BTN_A SDLK_SPACE
19 | #define BTN_A_INDEX 4
20 | #define BTN_B SDLK_LCTRL
21 | #define BTN_B_INDEX 5
22 | #define BTN_X SDLK_LSHIFT
23 | #define BTN_X_INDEX 6
24 | #define BTN_Y SDLK_LALT
25 | #define BTN_Y_INDEX 7
26 | #define BTN_L1 SDLK_e
27 | #define BTN_L1_INDEX 8
28 | #define BTN_R1 SDLK_t
29 | #define BTN_R1_INDEX 9
30 | #define BTN_L2 SDLK_TAB
31 | #define BTN_L2_INDEX 10
32 | #define BTN_R2 SDLK_BACKSPACE
33 | #define BTN_R2_INDEX 11
34 | #define BTN_SELECT SDLK_RCTRL
35 | #define BTN_SELECT_INDEX 12
36 | #define BTN_START SDLK_RETURN
37 | #define BTN_START_INDEX 13
38 | #define BTN_MENU SDLK_ESCAPE
39 | #define BTN_MENU_INDEX 14
40 | #define BTN_POWER SDLK_UNKNOWN // SDLK_FIRST = 0; SDLK_UNKNOWN = 0;
41 | #define BTN_POWER_INDEX 15
42 |
43 | #endif // KEYMAP_H__
44 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
SDL Flip Clock for the MiyooMini series
2 |
3 |
4 |
8 |
9 |
10 | This is a simple Flip Clock created using SDL.
11 |
12 | ## Features
13 |
14 | - Always awake
15 | - Quit the program using Menu + Select
16 | - Change 12/24 mode using Start
17 | - And ... that's it all!
18 |
19 | ## Download
20 |
21 | [Click here to get the last version released](https://github.com/JaeSeoKim/sdl-flip-clock/releases)
22 |
23 | ## Installation
24 |
25 | ### To use with Onion-OS
26 |
27 | 1. Download and unzip the latest release file
28 | 2. Move the unzipped folder to the `/App` path on the SD card
29 |
30 | > [!IMPORTANT]
31 | > The directory name must be `FlipClock`!
32 |
33 | 3. Boot up your Miyoomini and run `Flip Clock` in the Apps section!
34 |
35 | ## ChangeLogs
36 |
37 | ### v1.1
38 |
39 | #### Features
40 |
41 | - Change 12/24 mode using Start
42 |
43 | #### Fix
44 |
45 | - Improve Performance(6fps -> 58fps)
46 | - refactor `RenderFillCircle`
47 |
48 | #### Etc
49 |
50 | - Refactor bunch of codes...
51 |
52 | ### v1.0
53 |
54 | #### Features
55 |
56 | - Always awake
57 | - Quit the program using Menu + Select
58 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | TARGET=flipClock
2 | VERSION=1.1
3 |
4 | CC=$(CROSS_COMPILE)gcc
5 | # CFLAGS+=-I$(INC_DIR) -Werror
6 | CFLAGS+=-I$(INC_DIR)
7 |
8 | ifeq ($(MIYOOMINI),1)
9 | CFLAGS+=-DSDL=1
10 | LDLIBS=-DSDL=1 -lSDL -lpthread -lSDL_ttf
11 | else
12 | LDLIBS=-lSDL2 -lpthread -lSDL2_ttf
13 | endif
14 |
15 | ifeq ($(MIYOOMINI),1)
16 | CROSS_COMPILE?=~/buildroot/output/host/bin/arm-linux-gnueabihf-
17 | SYSROOT ?= $(shell ${CC} --print-sysroot)
18 | ARCH=-marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7ve+simd
19 | CFLAGS+=-Os $(ARCH) -I${SYSROOT}/usr/include -ffunction-sections -fdata-sections -Wall
20 | LDFLAGS+=-I${SYSROOT}/usr/lib $(ARCH) -Bstatic,-lutil,-Bdynamic
21 | endif
22 |
23 | RM=rm
24 | RMFLAGS=-rf
25 |
26 | MKDIR=mkdir
27 | MKDIRFLAGS=-p
28 |
29 | OUTPUT_DIR=build
30 | INC_DIR=include
31 | SRC_DIR=src
32 | OBJ_DIR=objs
33 |
34 | SRCS=$(wildcard $(SRC_DIR)/*.c)
35 | OBJS=$(addprefix $(OBJ_DIR)/, $(notdir $(SRCS:.c=.o)))
36 |
37 | all: $(TARGET)
38 |
39 | re: clean all
40 |
41 | clean:
42 | $(RM) $(RMFLAGS) $(OBJS) $(TARGET) FlipClock-v$(VERSION).zip
43 |
44 | $(TARGET): ${OBJS}
45 | $(CC) $(LDFLAGS) $(LDLIBS) $(OBJS) -o $(TARGET)
46 |
47 | $(OBJ_DIR)/%.o : $(SRC_DIR)/%.c | $(OBJ_DIR)
48 | $(CC) $(CFLAGS) -c $< -o $@
49 |
50 | $(OBJ_DIR):
51 | @$(MKDIR) $(MKDIRFLAGS) $(OBJ_DIR)
52 |
53 | pack: FlipClock-v$(VERSION).zip
54 |
55 | FlipClock-v$(VERSION).zip: $(TARGET)
56 | zip -r FlipClock-v$(VERSION).zip fonts flipClock icon config.json launch.sh
57 |
58 |
59 | .PHONY: all clean re
60 |
--------------------------------------------------------------------------------
/include/FlipClock.h:
--------------------------------------------------------------------------------
1 | #ifndef FLIP_CLOCK_H__
2 | #define FLIP_CLOCK_H__
3 |
4 | #if defined SDL && SDL == 1
5 | #include "SDL/SDL.h"
6 | #include "SDL/SDL_ttf.h"
7 | #else
8 | #include "SDL2/SDL.h"
9 | #include "SDL2/SDL_ttf.h"
10 | #endif
11 |
12 | #include "fcntl.h"
13 | #include "signal.h"
14 | #include "stdio.h"
15 | #include "stdlib.h"
16 | #include "time.h"
17 | #include "unistd.h"
18 |
19 | #include "KeyMap.h"
20 |
21 | #if defined SDL && SDL == 1
22 | typedef SDL_Surface SDL_Window;
23 | typedef SDL_Surface SDL_Renderer;
24 | #endif
25 |
26 | #define FRAME_RATE 60.0f
27 |
28 | #define FLIP_COLOR 0xFF222222
29 | #define FONT_COLOR 0xFFbababa
30 | #define BG_COLOR 0xFF000000
31 |
32 | struct FlipClock {
33 | int32_t DISPLAY_WIDTH;
34 | int32_t DISPLAY_HEIGHT;
35 | SDL_Window *window;
36 | SDL_Renderer *renderer;
37 | TTF_Font *timeFont;
38 | int timeFontDescent;
39 | TTF_Font *ampmFont;
40 | int ampmFontDescent;
41 | int KEY_STATUS[16];
42 | int quit;
43 | int mode;
44 | int lastTickCount;
45 | int curTickCount;
46 | int GAP;
47 | int DIVIDER;
48 | int MARGIN_X;
49 | int FLIP_SIZE;
50 | int FLIP_PADDING;
51 | int TIME_SIZE;
52 | int AMPM_SIZE;
53 | } typedef FlipClock;
54 |
55 | #define is_active_mode(MODE) _G.mode & (1 << (MODE))
56 | #define MODE_AMPM 0
57 | #define MODE_FPS 1
58 |
59 | #define INPUT_DELAY 300;
60 |
61 | extern FlipClock _G;
62 |
63 | // init.c
64 | int init();
65 | int init_display_Resolution();
66 |
67 | // destroy.c
68 | void destroy();
69 |
70 | // draw.c
71 | int draw_loop();
72 | int handle_key();
73 | int draw_screen(float fps);
74 | void draw_flip(int x, int y);
75 | void draw_time(int x, int y, int time);
76 | void draw_ampm(int x, int y, int hour);
77 | void draw_divider();
78 | void draw_fps(float fps);
79 | struct tm *get_local_time();
80 |
81 | // pollevent.c
82 | void pollevent();
83 |
84 | // render.c
85 | void RenderFillRoundedRect(SDL_Renderer *renderer, int x, int y, int w, int h,
86 | int percent, Uint32 color);
87 | void RenderFillCircle(SDL_Renderer *renderer, int cx, int cy, int radius,
88 | Uint32 color);
89 | int RenderFillRect(SDL_Renderer *dst, SDL_Rect *rect, Uint32 color);
90 | int RenderClear(SDL_Renderer *dst, Uint32 color);
91 | int RenderPresent(SDL_Renderer *renderer, SDL_Window *window);
92 | int BlitSurface(SDL_Surface *src, SDL_Rect *srcrect, SDL_Renderer *dst,
93 | SDL_Rect *dstrect);
94 | SDL_Surface *RenderText_Blended(TTF_Font *font, const char *text, Uint32 color);
95 | SDL_Color uint32ToSDLColor(Uint32 color);
96 |
97 | #endif // FLIP_CLOCK_H__
98 |
--------------------------------------------------------------------------------
/src/init.c:
--------------------------------------------------------------------------------
1 | #include "FlipClock.h"
2 |
3 | int init() {
4 | printf("##Start initialization\n");
5 |
6 | if (access("/tmp/stay_awake", F_OK) == -1) {
7 | printf("\tSet stay awake\n");
8 | close(creat("/tmp/stay_awake", 666));
9 | }
10 |
11 | if (SDL_Init(SDL_INIT_VIDEO) < 0) {
12 | printf("\tSDL_Init Fail: %s\n", SDL_GetError());
13 | return -1;
14 | }
15 |
16 | if (TTF_Init() < 0) {
17 | printf("\tTTF_Init Fail: %s\n", TTF_GetError());
18 | return -1;
19 | }
20 |
21 | if (init_display_Resolution() < 0) {
22 | return -1;
23 | }
24 | printf("\tDisplay Resolution: %dx%d\n", _G.DISPLAY_WIDTH, _G.DISPLAY_HEIGHT);
25 |
26 | _G.mode = 1 << MODE_AMPM;
27 |
28 | _G.MARGIN_X = _G.DISPLAY_WIDTH / 20;
29 | _G.GAP = 16;
30 | _G.DIVIDER = 4;
31 | _G.FLIP_SIZE = (_G.DISPLAY_WIDTH - _G.MARGIN_X * 2 - _G.GAP) / 2;
32 | _G.FLIP_PADDING = 32;
33 | _G.TIME_SIZE = _G.FLIP_SIZE - _G.FLIP_PADDING * 2;
34 | _G.AMPM_SIZE = _G.TIME_SIZE / 10;
35 |
36 | #if defined SDL && SDL == 1
37 | const char *FONT_LOCATION = "/mnt/SDCARD/App/FlipClock/fonts/Oswald-Bold.ttf";
38 | #else
39 | const char *FONT_LOCATION = "./fonts/Oswald-Bold.ttf";
40 | #endif
41 | _G.timeFont = TTF_OpenFont(FONT_LOCATION, _G.TIME_SIZE);
42 | _G.ampmFont = TTF_OpenFont(FONT_LOCATION, _G.AMPM_SIZE);
43 | if (_G.timeFont == NULL || _G.ampmFont == NULL) {
44 | printf("\tTTF_OpenFont Fail: %s\n", TTF_GetError());
45 | return -1;
46 | }
47 | _G.timeFontDescent = TTF_FontDescent(_G.timeFont);
48 | _G.ampmFontDescent = TTF_FontDescent(_G.ampmFont);
49 |
50 | #if defined SDL && SDL == 1
51 | _G.window =
52 | SDL_SetVideoMode(_G.DISPLAY_WIDTH, _G.DISPLAY_HEIGHT, 32, SDL_HWSURFACE);
53 | #else
54 | _G.window = SDL_CreateWindow("Flip Clock", SDL_WINDOWPOS_UNDEFINED,
55 | SDL_WINDOWPOS_UNDEFINED, _G.DISPLAY_WIDTH,
56 | _G.DISPLAY_HEIGHT, SDL_WINDOW_SHOWN);
57 | #endif
58 | if (_G.window == NULL) {
59 | printf("\tSDL_SetVideoMode Fail: %s\n", SDL_GetError());
60 | return -1;
61 | }
62 |
63 | #if defined SDL && SDL == 1
64 | _G.renderer = SDL_CreateRGBSurface(SDL_HWSURFACE, _G.DISPLAY_WIDTH,
65 | _G.DISPLAY_HEIGHT, 32, 0, 0, 0, 0);
66 | #else
67 | _G.renderer = SDL_CreateRenderer(_G.window, -1, 0);
68 | #endif
69 |
70 | if (_G.renderer == NULL) {
71 | printf("\tSDL_CreateRGBSurface Fail: %s\n", SDL_GetError());
72 | return -1;
73 | }
74 |
75 | printf("##Finish initialization\n\n");
76 | return 0;
77 | }
78 |
79 | int init_display_Resolution() {
80 | #if defined SDL && SDL == 1
81 | const SDL_VideoInfo *info = SDL_GetVideoInfo();
82 | _G.DISPLAY_WIDTH = info->current_w;
83 | _G.DISPLAY_HEIGHT = info->current_h;
84 | #else
85 | SDL_DisplayMode mode;
86 | if (SDL_GetDesktopDisplayMode(0, &mode)) {
87 | printf("SDL_GetDesktopDisplayMode Fail: %s\n", SDL_GetError());
88 | return -1;
89 | }
90 | _G.DISPLAY_WIDTH = mode.w;
91 | _G.DISPLAY_HEIGHT = mode.h;
92 | #endif
93 | return 0;
94 | }
95 |
--------------------------------------------------------------------------------
/src/pollevent.c:
--------------------------------------------------------------------------------
1 | #include "FlipClock.h"
2 |
3 | void handle_keydown(SDLKey sym);
4 | void handle_keyup(SDLKey sym);
5 |
6 | void pollevent() {
7 | SDL_Event event;
8 |
9 | while (SDL_PollEvent(&event)) {
10 | switch (event.type) {
11 | case SDL_QUIT:
12 | _G.quit = 1;
13 | break;
14 | case SDL_KEYDOWN:
15 | handle_keydown(event.key.keysym.sym);
16 | break;
17 | case SDL_KEYUP:
18 | handle_keyup(event.key.keysym.sym);
19 | break;
20 | default:
21 | break;
22 | }
23 | }
24 | }
25 |
26 | void handle_keydown(SDLKey sym) {
27 | switch (sym) {
28 | case BTN_UP:
29 | if (_G.KEY_STATUS[BTN_UP_INDEX] == 0)
30 | _G.KEY_STATUS[BTN_UP_INDEX] = _G.curTickCount;
31 | break;
32 | case BTN_DOWN:
33 | if (_G.KEY_STATUS[BTN_DOWN_INDEX] == 0)
34 | _G.KEY_STATUS[BTN_DOWN_INDEX] = _G.curTickCount;
35 | break;
36 | case BTN_LEFT:
37 | if (_G.KEY_STATUS[BTN_LEFT_INDEX] == 0)
38 | _G.KEY_STATUS[BTN_LEFT_INDEX] = _G.curTickCount;
39 | break;
40 | case BTN_RIGHT:
41 | if (_G.KEY_STATUS[BTN_RIGHT_INDEX] == 0)
42 | _G.KEY_STATUS[BTN_RIGHT_INDEX] = _G.curTickCount;
43 | break;
44 | case BTN_A:
45 | if (_G.KEY_STATUS[BTN_A_INDEX] == 0)
46 | _G.KEY_STATUS[BTN_A_INDEX] = _G.curTickCount;
47 | break;
48 | case BTN_B:
49 | if (_G.KEY_STATUS[BTN_B_INDEX] == 0)
50 | _G.KEY_STATUS[BTN_B_INDEX] = _G.curTickCount;
51 | break;
52 | case BTN_X:
53 | if (_G.KEY_STATUS[BTN_X_INDEX] == 0)
54 | _G.KEY_STATUS[BTN_X_INDEX] = _G.curTickCount;
55 | break;
56 | case BTN_Y:
57 | if (_G.KEY_STATUS[BTN_Y_INDEX] == 0)
58 | _G.KEY_STATUS[BTN_Y_INDEX] = _G.curTickCount;
59 | break;
60 | case BTN_L1:
61 | if (_G.KEY_STATUS[BTN_L1_INDEX] == 0)
62 | _G.KEY_STATUS[BTN_L1_INDEX] = _G.curTickCount;
63 | break;
64 | case BTN_R1:
65 | if (_G.KEY_STATUS[BTN_R1_INDEX] == 0)
66 | _G.KEY_STATUS[BTN_R1_INDEX] = _G.curTickCount;
67 | break;
68 | case BTN_L2:
69 | if (_G.KEY_STATUS[BTN_L2_INDEX] == 0)
70 | _G.KEY_STATUS[BTN_L2_INDEX] = _G.curTickCount;
71 | break;
72 | case BTN_R2:
73 | if (_G.KEY_STATUS[BTN_R2_INDEX] == 0)
74 | _G.KEY_STATUS[BTN_R2_INDEX] = _G.curTickCount;
75 | break;
76 | case BTN_SELECT:
77 | if (_G.KEY_STATUS[BTN_SELECT_INDEX] == 0)
78 | _G.KEY_STATUS[BTN_SELECT_INDEX] = _G.curTickCount;
79 | break;
80 | case BTN_START:
81 | if (_G.KEY_STATUS[BTN_START_INDEX] == 0)
82 | _G.KEY_STATUS[BTN_START_INDEX] = _G.curTickCount;
83 | break;
84 | case BTN_MENU:
85 | if (_G.KEY_STATUS[BTN_MENU_INDEX] == 0)
86 | _G.KEY_STATUS[BTN_MENU_INDEX] = _G.curTickCount;
87 | break;
88 | case BTN_POWER:
89 | if (_G.KEY_STATUS[BTN_POWER_INDEX] == 0)
90 | _G.KEY_STATUS[BTN_POWER_INDEX] = _G.curTickCount;
91 | break;
92 | default:
93 | break;
94 | }
95 | printf("Key pressed: %s\n", SDL_GetKeyName(sym));
96 | }
97 |
98 | void handle_keyup(SDLKey sym) {
99 | switch (sym) {
100 | case BTN_UP:
101 | _G.KEY_STATUS[BTN_UP_INDEX] = 0;
102 | break;
103 | case BTN_DOWN:
104 | _G.KEY_STATUS[BTN_DOWN_INDEX] = 0;
105 | break;
106 | case BTN_LEFT:
107 | _G.KEY_STATUS[BTN_LEFT_INDEX] = 0;
108 | break;
109 | case BTN_RIGHT:
110 | _G.KEY_STATUS[BTN_RIGHT_INDEX] = 0;
111 | break;
112 | case BTN_A:
113 | _G.KEY_STATUS[BTN_A_INDEX] = 0;
114 | break;
115 | case BTN_B:
116 | _G.KEY_STATUS[BTN_B_INDEX] = 0;
117 | break;
118 | case BTN_X:
119 | _G.KEY_STATUS[BTN_X_INDEX] = 0;
120 | break;
121 | case BTN_Y:
122 | _G.KEY_STATUS[BTN_Y_INDEX] = 0;
123 | break;
124 | case BTN_L1:
125 | _G.KEY_STATUS[BTN_L1_INDEX] = 0;
126 | break;
127 | case BTN_R1:
128 | _G.KEY_STATUS[BTN_R1_INDEX] = 0;
129 | break;
130 | case BTN_L2:
131 | _G.KEY_STATUS[BTN_L2_INDEX] = 0;
132 | break;
133 | case BTN_R2:
134 | _G.KEY_STATUS[BTN_R2_INDEX] = 0;
135 | break;
136 | case BTN_SELECT:
137 | _G.KEY_STATUS[BTN_SELECT_INDEX] = 0;
138 | break;
139 | case BTN_START:
140 | _G.KEY_STATUS[BTN_START_INDEX] = 0;
141 | break;
142 | case BTN_MENU:
143 | _G.KEY_STATUS[BTN_MENU_INDEX] = 0;
144 | break;
145 | case BTN_POWER:
146 | _G.KEY_STATUS[BTN_POWER_INDEX] = 0;
147 | break;
148 | default:
149 | break;
150 | }
151 | printf("Key released: %s\n", SDL_GetKeyName(sym));
152 | }
153 |
--------------------------------------------------------------------------------
/src/render.c:
--------------------------------------------------------------------------------
1 | #include "FlipClock.h"
2 |
3 | int calculateRadius(int width, int height, int percent) {
4 | float smallest = width < height ? width : height;
5 | if (percent > 100) {
6 | percent = 100;
7 | } else if (percent < 0) {
8 | percent = 0;
9 | }
10 | return (smallest / 2 * percent) / 100;
11 | }
12 |
13 | void RenderFillRoundedRect(SDL_Renderer *renderer, int x, int y, int w, int h,
14 | int percent, Uint32 color) {
15 | int radius = calculateRadius(w, h, percent);
16 |
17 | int x1 = x + radius;
18 | int x2 = x + w - radius;
19 | int y1 = y + radius;
20 | int y2 = y + h - radius;
21 |
22 | SDL_Rect rect = {x1, y, w - radius * 2, h};
23 | RenderFillRect(renderer, &rect, color);
24 | rect = (SDL_Rect){x, y1, w, h - radius * 2};
25 | RenderFillRect(renderer, &rect, color);
26 |
27 | RenderFillCircle(renderer, x1, y1, radius, color);
28 | RenderFillCircle(renderer, x2, y1, radius, color);
29 | RenderFillCircle(renderer, x1, y2, radius, color);
30 | RenderFillCircle(renderer, x2, y2, radius, color);
31 | }
32 |
33 | void RenderFillCircle(SDL_Renderer *renderer, int cx, int cy, int radius,
34 | Uint32 color) {
35 | const int diameter = (radius * 2);
36 |
37 | int x = (radius - 1);
38 | int y = 0;
39 | int tx = 1;
40 | int ty = 1;
41 | int error = (tx - diameter);
42 |
43 | SDL_Surface *surface =
44 | SDL_CreateRGBSurface(0, diameter, diameter, 32, 0x000000FF, 0x0000FF00,
45 | 0x00FF0000, 0xFF000000);
46 |
47 | while (x >= y) {
48 | for (int i = radius - x; i <= radius + x; i++) {
49 | *(Uint32 *)(surface->pixels + surface->pitch * (radius + y) +
50 | (i * surface->format->BytesPerPixel)) = color;
51 | *(Uint32 *)(surface->pixels + surface->pitch * (radius - y) +
52 | (i * surface->format->BytesPerPixel)) = color;
53 | }
54 | for (int i = radius - y; i <= radius + y; i++) {
55 | *(Uint32 *)(surface->pixels + surface->pitch * (radius + x) +
56 | (i * surface->format->BytesPerPixel)) = color;
57 | *(Uint32 *)(surface->pixels + surface->pitch * (radius - x) +
58 | (i * surface->format->BytesPerPixel)) = color;
59 | }
60 |
61 | if (error <= 0) {
62 | ++y;
63 | error += ty;
64 | ty += 2;
65 | }
66 | if (error > 0) {
67 | --x;
68 | tx += 2;
69 | error += (tx - diameter);
70 | }
71 | }
72 | BlitSurface(surface, NULL, renderer,
73 | &(SDL_Rect){cx - radius, cy - radius, diameter, diameter});
74 |
75 | SDL_FreeSurface(surface);
76 | }
77 |
78 | int RenderFillRect(SDL_Renderer *dst, SDL_Rect *rect, Uint32 color) {
79 | #if defined SDL && SDL == 1
80 | return SDL_FillRect(dst, rect, color);
81 | #else
82 | SDL_SetRenderDrawColor(dst, color >> 16 & 255, color >> 8 & 255, color & 255,
83 | color >> 24 & 255);
84 | return SDL_RenderFillRect(dst, rect);
85 | #endif
86 | }
87 |
88 | int RenderPresent(SDL_Renderer *renderer, SDL_Window *window) {
89 | #if defined SDL && SDL == 1
90 | return SDL_BlitSurface(renderer, NULL, window, NULL);
91 | #else
92 | SDL_RenderPresent(renderer);
93 | return 0;
94 | #endif
95 | }
96 |
97 | int RenderClear(SDL_Renderer *dst, Uint32 color) {
98 | #if defined SDL && SDL == 1
99 | return RenderFillRect(dst, NULL, color);
100 | #else
101 | SDL_SetRenderDrawColor(dst, color >> 16 & 255, color >> 8 & 255, color & 255,
102 | color >> 24 & 255);
103 | return SDL_RenderClear(dst);
104 | #endif
105 | }
106 |
107 | int BlitSurface(SDL_Surface *src, SDL_Rect *srcrect, SDL_Renderer *dst,
108 | SDL_Rect *dstrect) {
109 | #if defined SDL && SDL == 1
110 | return SDL_BlitSurface(src, srcrect, dst, dstrect);
111 | #else
112 | SDL_Texture *mTexture = SDL_CreateTextureFromSurface(dst, src);
113 | if (mTexture == NULL) {
114 | return -1;
115 | }
116 | int ret = SDL_RenderCopy(dst, mTexture, NULL, dstrect);
117 | SDL_DestroyTexture(mTexture);
118 | return ret;
119 | #endif
120 | };
121 |
122 | SDL_Surface *RenderText_Blended(TTF_Font *font, const char *text,
123 | Uint32 color) {
124 | return TTF_RenderText_Blended(font, text, uint32ToSDLColor(color));
125 | }
126 |
127 | SDL_Color uint32ToSDLColor(Uint32 color) {
128 | return (SDL_Color){color >> 16 & 255, color >> 8 & 255, color & 255,
129 | color >> 24 & 255};
130 | }
131 |
--------------------------------------------------------------------------------
/fonts/OFL.txt:
--------------------------------------------------------------------------------
1 | Copyright 2016 The Oswald Project Authors (https://github.com/googlefonts/OswaldFont)
2 |
3 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
4 | This license is copied below, and is also available with a FAQ at:
5 | https://openfontlicense.org
6 |
7 |
8 | -----------------------------------------------------------
9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10 | -----------------------------------------------------------
11 |
12 | PREAMBLE
13 | The goals of the Open Font License (OFL) are to stimulate worldwide
14 | development of collaborative font projects, to support the font creation
15 | efforts of academic and linguistic communities, and to provide a free and
16 | open framework in which fonts may be shared and improved in partnership
17 | with others.
18 |
19 | The OFL allows the licensed fonts to be used, studied, modified and
20 | redistributed freely as long as they are not sold by themselves. The
21 | fonts, including any derivative works, can be bundled, embedded,
22 | redistributed and/or sold with any software provided that any reserved
23 | names are not used by derivative works. The fonts and derivatives,
24 | however, cannot be released under any other type of license. The
25 | requirement for fonts to remain under this license does not apply
26 | to any document created using the fonts or their derivatives.
27 |
28 | DEFINITIONS
29 | "Font Software" refers to the set of files released by the Copyright
30 | Holder(s) under this license and clearly marked as such. This may
31 | include source files, build scripts and documentation.
32 |
33 | "Reserved Font Name" refers to any names specified as such after the
34 | copyright statement(s).
35 |
36 | "Original Version" refers to the collection of Font Software components as
37 | distributed by the Copyright Holder(s).
38 |
39 | "Modified Version" refers to any derivative made by adding to, deleting,
40 | or substituting -- in part or in whole -- any of the components of the
41 | Original Version, by changing formats or by porting the Font Software to a
42 | new environment.
43 |
44 | "Author" refers to any designer, engineer, programmer, technical
45 | writer or other person who contributed to the Font Software.
46 |
47 | PERMISSION & CONDITIONS
48 | Permission is hereby granted, free of charge, to any person obtaining
49 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
50 | redistribute, and sell modified and unmodified copies of the Font
51 | Software, subject to the following conditions:
52 |
53 | 1) Neither the Font Software nor any of its individual components,
54 | in Original or Modified Versions, may be sold by itself.
55 |
56 | 2) Original or Modified Versions of the Font Software may be bundled,
57 | redistributed and/or sold with any software, provided that each copy
58 | contains the above copyright notice and this license. These can be
59 | included either as stand-alone text files, human-readable headers or
60 | in the appropriate machine-readable metadata fields within text or
61 | binary files as long as those fields can be easily viewed by the user.
62 |
63 | 3) No Modified Version of the Font Software may use the Reserved Font
64 | Name(s) unless explicit written permission is granted by the corresponding
65 | Copyright Holder. This restriction only applies to the primary font name as
66 | presented to the users.
67 |
68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69 | Software shall not be used to promote, endorse or advertise any
70 | Modified Version, except to acknowledge the contribution(s) of the
71 | Copyright Holder(s) and the Author(s) or with their explicit written
72 | permission.
73 |
74 | 5) The Font Software, modified or unmodified, in part or in whole,
75 | must be distributed entirely under this license, and must not be
76 | distributed under any other license. The requirement for fonts to
77 | remain under this license does not apply to any document created
78 | using the Font Software.
79 |
80 | TERMINATION
81 | This license becomes null and void if any of the above conditions are
82 | not met.
83 |
84 | DISCLAIMER
85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93 | OTHER DEALINGS IN THE FONT SOFTWARE.
94 |
--------------------------------------------------------------------------------
/src/draw.c:
--------------------------------------------------------------------------------
1 | #include "FlipClock.h"
2 |
3 | int draw_loop() {
4 | printf("##Start rendering loop\n");
5 |
6 | _G.lastTickCount = SDL_GetTicks();
7 | _G.curTickCount = _G.lastTickCount;
8 |
9 | float fps = 0.0f;
10 | int frame = _G.curTickCount;
11 | int frameCount = 0;
12 |
13 | while (_G.quit == 0) {
14 | _G.curTickCount = SDL_GetTicks();
15 | pollevent();
16 | handle_key();
17 |
18 | // sync frame rate
19 | if (_G.curTickCount - _G.lastTickCount < 1000 / FRAME_RATE) {
20 | continue;
21 | }
22 |
23 | // calculate FPS
24 | ++frameCount;
25 | if (_G.curTickCount - frame >= 1000) {
26 | fps = frameCount / ((_G.curTickCount - frame) / 1000.f);
27 | frameCount = 0;
28 | frame = _G.curTickCount;
29 | }
30 |
31 | // before draw
32 | RenderClear(_G.renderer, BG_COLOR);
33 |
34 | // draw
35 | draw_screen(fps);
36 |
37 | // after draw
38 | RenderPresent(_G.renderer, _G.window);
39 | _G.lastTickCount = _G.curTickCount;
40 | }
41 |
42 | printf("##Finish rendering loop\n");
43 | return 0;
44 | }
45 |
46 | int handle_key() {
47 | // MENU + SELECT -> Exit
48 | if (_G.KEY_STATUS[BTN_MENU_INDEX] && _G.KEY_STATUS[BTN_SELECT_INDEX]) {
49 | _G.quit = 1;
50 | }
51 |
52 | // START -> toggle `12/24` mode
53 | if (_G.KEY_STATUS[BTN_START_INDEX] &&
54 | _G.KEY_STATUS[BTN_START_INDEX] <= _G.curTickCount) {
55 | _G.KEY_STATUS[BTN_START_INDEX] = _G.curTickCount + INPUT_DELAY;
56 | if (is_active_mode(MODE_AMPM)) {
57 | _G.mode &= ~(1 << MODE_AMPM);
58 | } else {
59 | _G.mode |= 1 << MODE_AMPM;
60 | }
61 | }
62 |
63 | // MENU + X -> toggle `FPS` mode
64 | if (_G.KEY_STATUS[BTN_MENU_INDEX] &&
65 | _G.KEY_STATUS[BTN_MENU_INDEX] <= _G.curTickCount &&
66 | _G.KEY_STATUS[BTN_X_INDEX] &&
67 | _G.KEY_STATUS[BTN_X_INDEX] <= _G.curTickCount) {
68 |
69 | _G.KEY_STATUS[BTN_MENU_INDEX] = _G.curTickCount + INPUT_DELAY;
70 | _G.KEY_STATUS[BTN_X_INDEX] = _G.curTickCount + INPUT_DELAY;
71 |
72 | if (is_active_mode(MODE_FPS)) {
73 | _G.mode &= ~(1 << MODE_FPS);
74 | } else {
75 | _G.mode |= 1 << MODE_FPS;
76 | }
77 | }
78 |
79 | return 0;
80 | }
81 |
82 | #define FLIPCLOCK_HOUR 0
83 | #define FLIPCLOCK_MINIUTE 1
84 |
85 | int draw_screen(float fps) {
86 | struct tm *time = get_local_time();
87 |
88 | int x = _G.MARGIN_X;
89 | int y = (_G.DISPLAY_HEIGHT - _G.FLIP_SIZE) / 2;
90 |
91 | for (int layout = 0; layout < 2; ++layout) {
92 | int display_time_number =
93 | layout == FLIPCLOCK_HOUR ? time->tm_hour : time->tm_min;
94 |
95 | if (layout == FLIPCLOCK_HOUR && is_active_mode(MODE_AMPM)) {
96 | display_time_number %= 12;
97 | if (display_time_number == 0) {
98 | display_time_number = 12;
99 | }
100 | }
101 |
102 | draw_flip(x, y);
103 | draw_time(x, y, display_time_number);
104 |
105 | if (layout == FLIPCLOCK_HOUR && is_active_mode(MODE_AMPM)) {
106 | draw_ampm(x, y, time->tm_hour);
107 | }
108 |
109 | // Update Position
110 | x += _G.GAP + _G.FLIP_SIZE;
111 | }
112 |
113 | draw_divider();
114 |
115 | if (is_active_mode(MODE_FPS)) {
116 | draw_fps(fps);
117 | }
118 |
119 | return 0;
120 | }
121 |
122 | struct tm *get_local_time() {
123 | time_t ltime;
124 | ltime = time(<ime);
125 | return localtime(<ime);
126 | }
127 |
128 | void draw_flip(int x, int y) {
129 | RenderFillRoundedRect(_G.renderer, x, y, _G.FLIP_SIZE, _G.FLIP_SIZE, 10,
130 | FLIP_COLOR);
131 | }
132 |
133 | void draw_time(int x, int y, int time) {
134 | char timeString[3] = {
135 | time / 10 + '0',
136 | time % 10 + '0',
137 | '\0',
138 | };
139 |
140 | SDL_Surface *textSurface =
141 | RenderText_Blended(_G.timeFont, timeString, FONT_COLOR);
142 |
143 | BlitSurface(
144 | textSurface, NULL, _G.renderer,
145 | &(SDL_Rect){x + _G.FLIP_PADDING + (_G.TIME_SIZE - textSurface->w) / 2,
146 | y + _G.FLIP_PADDING + _G.timeFontDescent, textSurface->w,
147 | textSurface->h});
148 |
149 | // free allocated memories
150 | SDL_FreeSurface(textSurface);
151 | }
152 |
153 | void draw_ampm(int x, int y, int hour) {
154 | SDL_Surface *textSurface =
155 | RenderText_Blended(_G.ampmFont, hour < 12 ? "AM" : "PM", FONT_COLOR);
156 |
157 | BlitSurface(textSurface, NULL, _G.renderer,
158 | &(SDL_Rect){x + _G.FLIP_PADDING / 2,
159 | y + _G.FLIP_SIZE - _G.FLIP_PADDING / 2 -
160 | _G.AMPM_SIZE + _G.ampmFontDescent,
161 | textSurface->w, textSurface->h});
162 |
163 | // free allocated memories
164 | SDL_FreeSurface(textSurface);
165 | }
166 |
167 | void draw_divider() {
168 | RenderFillRect(_G.renderer,
169 | &(SDL_Rect){0, _G.DISPLAY_HEIGHT / 2 - _G.DIVIDER,
170 | _G.DISPLAY_WIDTH, _G.DIVIDER},
171 | BG_COLOR);
172 | }
173 |
174 | void draw_fps(float fps) {
175 | char FPS[11] = {
176 | '\0',
177 | };
178 |
179 | sprintf(FPS, "FPS: %.2f", fps);
180 | SDL_Surface *textSurface = RenderText_Blended(_G.ampmFont, FPS, FONT_COLOR);
181 | BlitSurface(textSurface, NULL, _G.renderer,
182 | &(SDL_Rect){4, 4, textSurface->w, textSurface->h});
183 |
184 | // free allocated memories
185 | SDL_FreeSurface(textSurface);
186 | }
187 |
--------------------------------------------------------------------------------