diff options
author | QMK Bot <hello@qmk.fm> | 2021-06-24 02:22:11 +0000 |
---|---|---|
committer | QMK Bot <hello@qmk.fm> | 2021-06-24 02:22:11 +0000 |
commit | b69fa51ec39d2825067b11f065ff8e59e41d8dc9 (patch) | |
tree | c36f3c63b8472a1f5b951cc9e2e5a03df1532fee /users | |
parent | 1ea01765e19bf84b9a09954443b7d64be2bec0c7 (diff) | |
parent | 909d9c228fb03750170aa7ca49ea10d08a6e1113 (diff) | |
download | qmk_firmware-b69fa51ec39d2825067b11f065ff8e59e41d8dc9.tar.gz qmk_firmware-b69fa51ec39d2825067b11f065ff8e59e41d8dc9.zip |
Merge remote-tracking branch 'origin/master' into develop
Diffstat (limited to 'users')
-rw-r--r-- | users/snowe/luna.c | 229 | ||||
-rw-r--r-- | users/snowe/luna.h | 31 | ||||
-rw-r--r-- | users/snowe/ocean_dream.c | 555 | ||||
-rw-r--r-- | users/snowe/ocean_dream.h | 103 | ||||
-rw-r--r-- | users/snowe/oled_setup.c | 141 | ||||
-rw-r--r-- | users/snowe/oled_setup.h | 30 | ||||
-rw-r--r-- | users/snowe/readme.md | 10 | ||||
-rw-r--r-- | users/snowe/readme_ocean_dream.md | 258 | ||||
-rw-r--r-- | users/snowe/rules.mk | 27 | ||||
-rw-r--r-- | users/snowe/snowe.h | 43 | ||||
-rw-r--r-- | users/snowe/wrappers.h | 92 |
11 files changed, 1519 insertions, 0 deletions
diff --git a/users/snowe/luna.c b/users/snowe/luna.c new file mode 100644 index 000000000..4653abfae --- /dev/null +++ b/users/snowe/luna.c | |||
@@ -0,0 +1,229 @@ | |||
1 | /* | ||
2 | * Copyright 2021 QMK Community | ||
3 | * Copyright 2021 Tyler Thrailkill (@snowe/@snowe2010) <tyler.b.thrailkill@gmail.com> | ||
4 | * | ||
5 | * This program is free software: you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation, either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include "quantum.h" | ||
20 | #include "luna.h" | ||
21 | |||
22 | // KEYBOARD PET START | ||
23 | |||
24 | // settings | ||
25 | #define MIN_WALK_SPEED 10 | ||
26 | #define MIN_RUN_SPEED 40 | ||
27 | |||
28 | // advanced settings | ||
29 | #define ANIM_FRAME_DURATION 200 // how long each frame lasts in ms | ||
30 | #define ANIM_SIZE 96 // number of bytes in array. If you change sprites, minimize for adequate firmware size. max is 1024 | ||
31 | |||
32 | bool isSneaking = false; | ||
33 | bool isJumping = false; | ||
34 | bool showedJump = true; | ||
35 | |||
36 | // status variables | ||
37 | int current_wpm = 0; | ||
38 | led_t led_usb_state = { | ||
39 | .num_lock = false, | ||
40 | .caps_lock = false, | ||
41 | .scroll_lock = false | ||
42 | }; | ||
43 | |||
44 | // current frame | ||
45 | uint8_t current_frame = 0; | ||
46 | |||
47 | // timers | ||
48 | uint32_t anim_timer = 0; | ||
49 | uint32_t anim_sleep = 0; | ||
50 | |||
51 | // logic | ||
52 | void render_luna(int LUNA_X, int LUNA_Y) { | ||
53 | |||
54 | // Sit | ||
55 | static const char PROGMEM sit[2][ANIM_SIZE] = { | ||
56 | // 'sit1', 32x22px | ||
57 | { | ||
58 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1c, | ||
59 | 0x02, 0x05, 0x02, 0x24, 0x04, 0x04, 0x02, 0xa9, 0x1e, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
60 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x10, 0x08, 0x68, 0x10, 0x08, 0x04, 0x03, 0x00, 0x00, | ||
61 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x82, 0x7c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
62 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x0c, 0x10, 0x10, 0x20, 0x20, 0x20, 0x28, | ||
63 | 0x3e, 0x1c, 0x20, 0x20, 0x3e, 0x0f, 0x11, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
64 | }, | ||
65 | |||
66 | // 'sit2', 32x22px | ||
67 | { | ||
68 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1c, | ||
69 | 0x02, 0x05, 0x02, 0x24, 0x04, 0x04, 0x02, 0xa9, 0x1e, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
70 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x90, 0x08, 0x18, 0x60, 0x10, 0x08, 0x04, 0x03, 0x00, 0x00, | ||
71 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0e, 0x82, 0x7c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
72 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x0c, 0x10, 0x10, 0x20, 0x20, 0x20, 0x28, | ||
73 | 0x3e, 0x1c, 0x20, 0x20, 0x3e, 0x0f, 0x11, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
74 | } | ||
75 | }; | ||
76 | |||
77 | // Walk | ||
78 | static const char PROGMEM walk[2][ANIM_SIZE] = { | ||
79 | // 'walk1', 32x22px | ||
80 | { | ||
81 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x90, 0x90, 0x90, 0xa0, 0xc0, 0x80, 0x80, | ||
82 | 0x80, 0x70, 0x08, 0x14, 0x08, 0x90, 0x10, 0x10, 0x08, 0xa4, 0x78, 0x80, 0x00, 0x00, 0x00, 0x00, | ||
83 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x08, 0xfc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, | ||
84 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x18, 0xea, 0x10, 0x0f, 0x00, 0x00, 0x00, 0x00, | ||
85 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1c, 0x20, 0x20, 0x3c, 0x0f, 0x11, 0x1f, 0x03, | ||
86 | 0x06, 0x18, 0x20, 0x20, 0x3c, 0x0c, 0x12, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
87 | }, | ||
88 | |||
89 | // 'walk2', 32x22px | ||
90 | { | ||
91 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x20, 0x20, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, | ||
92 | 0x00, 0xe0, 0x10, 0x28, 0x10, 0x20, 0x20, 0x20, 0x10, 0x48, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
93 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x20, 0xf8, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | ||
94 | 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x30, 0xd5, 0x20, 0x1f, 0x00, 0x00, 0x00, 0x00, | ||
95 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x20, 0x30, 0x0c, 0x02, 0x05, 0x09, 0x12, 0x1e, | ||
96 | 0x02, 0x1c, 0x14, 0x08, 0x10, 0x20, 0x2c, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
97 | } | ||
98 | }; | ||
99 | |||
100 | // Run | ||
101 | static const char PROGMEM run[2][ANIM_SIZE] = { | ||
102 | // 'run1', 32x22px | ||
103 | { | ||
104 | 0x00, 0x00, 0x00, 0x00, 0xe0, 0x10, 0x08, 0x08, 0xc8, 0xb0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, | ||
105 | 0x80, 0x40, 0x40, 0x3c, 0x14, 0x04, 0x08, 0x90, 0x18, 0x04, 0x08, 0xb0, 0x40, 0x80, 0x00, 0x00, | ||
106 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0xc4, 0xa4, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, | ||
107 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc8, 0x58, 0x28, 0x2a, 0x10, 0x0f, 0x00, 0x00, | ||
108 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x09, 0x04, 0x04, 0x04, 0x04, 0x02, 0x03, 0x02, 0x01, 0x01, | ||
109 | 0x02, 0x02, 0x04, 0x08, 0x10, 0x26, 0x2b, 0x32, 0x04, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
110 | }, | ||
111 | |||
112 | // 'run2', 32x22px | ||
113 | { | ||
114 | 0x00, 0x00, 0x00, 0xe0, 0x10, 0x10, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, | ||
115 | 0x80, 0x80, 0x78, 0x28, 0x08, 0x10, 0x20, 0x30, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, | ||
116 | 0x00, 0x00, 0x00, 0x03, 0x04, 0x08, 0x10, 0x11, 0xf9, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, | ||
117 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0xb0, 0x50, 0x55, 0x20, 0x1f, 0x00, 0x00, | ||
118 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x0c, 0x10, 0x20, 0x28, 0x37, | ||
119 | 0x02, 0x1e, 0x20, 0x20, 0x18, 0x0c, 0x14, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
120 | } | ||
121 | }; | ||
122 | |||
123 | // Bark | ||
124 | static const char PROGMEM bark[2][ANIM_SIZE] = { | ||
125 | // 'bark1', 32x22px | ||
126 | { | ||
127 | 0x00, 0xc0, 0x20, 0x10, 0xd0, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, | ||
128 | 0x3c, 0x14, 0x04, 0x08, 0x90, 0x18, 0x04, 0x08, 0xb0, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
129 | 0x00, 0x03, 0x04, 0x08, 0x10, 0x11, 0xf9, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, | ||
130 | 0x00, 0x00, 0x00, 0x00, 0x80, 0xc8, 0x48, 0x28, 0x2a, 0x10, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
131 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x0c, 0x10, 0x20, 0x28, 0x37, 0x02, 0x02, | ||
132 | 0x04, 0x08, 0x10, 0x26, 0x2b, 0x32, 0x04, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
133 | }, | ||
134 | |||
135 | // 'bark2', 32x22px | ||
136 | { | ||
137 | 0x00, 0xe0, 0x10, 0x10, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, | ||
138 | 0x40, 0x2c, 0x14, 0x04, 0x08, 0x90, 0x18, 0x04, 0x08, 0xb0, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, | ||
139 | 0x00, 0x03, 0x04, 0x08, 0x10, 0x11, 0xf9, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, | ||
140 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0x48, 0x28, 0x2a, 0x10, 0x0f, 0x20, 0x4a, 0x09, 0x10, | ||
141 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x0c, 0x10, 0x20, 0x28, 0x37, 0x02, 0x02, | ||
142 | 0x04, 0x08, 0x10, 0x26, 0x2b, 0x32, 0x04, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
143 | } | ||
144 | }; | ||
145 | |||
146 | // Sneak | ||
147 | static const char PROGMEM sneak[2][ANIM_SIZE] = { | ||
148 | // 'sneak1', 32x22px | ||
149 | { | ||
150 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x40, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, | ||
151 | 0x00, 0x00, 0xc0, 0x40, 0x40, 0x80, 0x00, 0x80, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
152 | 0x00, 0x00, 0x00, 0x00, 0x1e, 0x21, 0xf0, 0x04, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, 0x04, | ||
153 | 0x04, 0x04, 0x03, 0x01, 0x00, 0x00, 0x09, 0x01, 0x80, 0x80, 0xab, 0x04, 0xf8, 0x00, 0x00, 0x00, | ||
154 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1c, 0x20, 0x20, 0x3c, 0x0f, 0x11, 0x1f, 0x02, 0x06, | ||
155 | 0x18, 0x20, 0x20, 0x38, 0x08, 0x10, 0x18, 0x04, 0x04, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, | ||
156 | }, | ||
157 | |||
158 | // 'sneak2', 32x22px | ||
159 | { | ||
160 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
161 | 0x00, 0x00, 0xe0, 0xa0, 0x20, 0x40, 0x80, 0xc0, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
162 | 0x00, 0x00, 0x00, 0x00, 0x3e, 0x41, 0xf0, 0x04, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, 0x02, 0x04, | ||
163 | 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x40, 0x40, 0x55, 0x82, 0x7c, 0x00, 0x00, 0x00, | ||
164 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x20, 0x30, 0x0c, 0x02, 0x05, 0x09, 0x12, 0x1e, 0x04, | ||
165 | 0x18, 0x10, 0x08, 0x10, 0x20, 0x28, 0x34, 0x06, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
166 | } | ||
167 | }; | ||
168 | |||
169 | // animation | ||
170 | void animation_phase(void) { | ||
171 | |||
172 | // jump | ||
173 | if (isJumping || !showedJump) { | ||
174 | |||
175 | // clear | ||
176 | oled_set_cursor(LUNA_X,LUNA_Y +2); | ||
177 | oled_write(" ", false); | ||
178 | |||
179 | oled_set_cursor(LUNA_X,LUNA_Y -1); | ||
180 | |||
181 | showedJump = true; | ||
182 | } else { | ||
183 | |||
184 | // clear | ||
185 | oled_set_cursor(LUNA_X,LUNA_Y -1); | ||
186 | oled_write(" ", false); | ||
187 | |||
188 | oled_set_cursor(LUNA_X,LUNA_Y); | ||
189 | } | ||
190 | |||
191 | // switch frame | ||
192 | current_frame = (current_frame + 1) % 2; | ||
193 | |||
194 | // current status | ||
195 | if(led_usb_state.caps_lock) { | ||
196 | oled_write_raw_P(bark[abs(1 - current_frame)], ANIM_SIZE); | ||
197 | |||
198 | } else if(isSneaking) { | ||
199 | oled_write_raw_P(sneak[abs(1 - current_frame)], ANIM_SIZE); | ||
200 | |||
201 | } else if(current_wpm <= MIN_WALK_SPEED) { | ||
202 | oled_write_raw_P(sit[abs(1 - current_frame)], ANIM_SIZE); | ||
203 | |||
204 | } else if(current_wpm <= MIN_RUN_SPEED) { | ||
205 | oled_write_raw_P(walk[abs(1 - current_frame)], ANIM_SIZE); | ||
206 | |||
207 | } else { | ||
208 | oled_write_raw_P(run[abs(1 - current_frame)], ANIM_SIZE); | ||
209 | } | ||
210 | } | ||
211 | |||
212 | // animation timer | ||
213 | if(timer_elapsed32(anim_timer) > ANIM_FRAME_DURATION) { | ||
214 | anim_timer = timer_read32(); | ||
215 | current_wpm = get_current_wpm(); | ||
216 | animation_phase(); | ||
217 | } | ||
218 | |||
219 | // this fixes the screen on and off bug | ||
220 | if (current_wpm > 0) { | ||
221 | oled_on(); | ||
222 | anim_sleep = timer_read32(); | ||
223 | } else if(timer_elapsed32(anim_sleep) > OLED_TIMEOUT) { | ||
224 | oled_off(); | ||
225 | } | ||
226 | |||
227 | } | ||
228 | |||
229 | // KEYBOARD PET END \ No newline at end of file | ||
diff --git a/users/snowe/luna.h b/users/snowe/luna.h new file mode 100644 index 000000000..c96d7a12d --- /dev/null +++ b/users/snowe/luna.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * Copyright 2021 QMK Community | ||
3 | * Copyright 2021 Tyler Thrailkill (@snowe/@snowe2010) <tyler.b.thrailkill@gmail.com> | ||
4 | * | ||
5 | * This program is free software: you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation, either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #pragma once | ||
20 | |||
21 | extern bool isSneaking; | ||
22 | extern bool isJumping; | ||
23 | extern bool showedJump; | ||
24 | |||
25 | // status variables | ||
26 | extern led_t led_usb_state; | ||
27 | //extern int current_wpm; | ||
28 | |||
29 | |||
30 | void render_luna(int LUNA_X, int LUNA_Y); | ||
31 | |||
diff --git a/users/snowe/ocean_dream.c b/users/snowe/ocean_dream.c new file mode 100644 index 000000000..2f372628d --- /dev/null +++ b/users/snowe/ocean_dream.c | |||
@@ -0,0 +1,555 @@ | |||
1 | /* | ||
2 | * Copyright 2021 Tyler Thrailkill (@snowe/@snowe2010) <tyler.b.thrailkill@gmail.com> | ||
3 | * | ||
4 | * This program is free software: you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation, either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include "ocean_dream.h" | ||
19 | #include "quantum.h" | ||
20 | #include "print.h" | ||
21 | |||
22 | // Calculated Parameters | ||
23 | #define TWINKLE_PROBABILITY_MODULATOR 100 / TWINKLE_PROBABILITY // CALCULATED: Don't Touch | ||
24 | #define TOTAL_STARS STARS_PER_LINE *NUMBER_OF_STAR_LINES // CALCULATED: Don't Touch | ||
25 | #define OCEAN_ANIMATION_MODULATOR NUMBER_OF_FRAMES / OCEAN_ANIMATION_SPEED // CALCULATED: Don't Touch | ||
26 | #define SHOOTING_STAR_ANIMATION_MODULATOR NUMBER_OF_FRAMES / SHOOTING_STAR_ANIMATION_SPEED // CALCULATED: Don't Touch | ||
27 | #define STAR_ANIMATION_MODULATOR NUMBER_OF_FRAMES / STAR_ANIMATION_SPEED // CALCULATED: Don't Touch | ||
28 | |||
29 | uint8_t animation_counter = 0; // global animation counter. | ||
30 | bool is_calm = false; | ||
31 | uint32_t starry_night_anim_timer = 0; | ||
32 | uint32_t starry_night_anim_sleep = 0; | ||
33 | static int current_wpm = 0; | ||
34 | |||
35 | static uint8_t increment_counter(uint8_t counter, uint8_t max) { | ||
36 | counter++; | ||
37 | if (counter >= max) { | ||
38 | return 0; | ||
39 | } else { | ||
40 | return counter; | ||
41 | } | ||
42 | } | ||
43 | |||
44 | #ifdef ENABLE_WAVE | ||
45 | static uint8_t decrement_counter(uint8_t counter, uint8_t max) { | ||
46 | counter--; | ||
47 | if (counter < 0 || counter > max) { | ||
48 | return max; | ||
49 | } else { | ||
50 | return counter; | ||
51 | } | ||
52 | } | ||
53 | #endif | ||
54 | |||
55 | #ifdef ENABLE_MOON // region | ||
56 | # ifndef STATIC_MOON | ||
57 | uint8_t moon_animation_frame = 0; // keeps track of current moon frame | ||
58 | uint16_t moon_animation_counter = 0; // counts how many frames to wait before animating moon to next frame | ||
59 | # endif | ||
60 | |||
61 | # ifdef STATIC_MOON | ||
62 | static const char PROGMEM moon[6] = { | ||
63 | 0x18, 0x7E, 0xFF, 0xC3, 0x81, 0x81, | ||
64 | }; | ||
65 | # endif | ||
66 | |||
67 | # ifndef STATIC_MOON | ||
68 | static const char PROGMEM moon_animation[14][8] = { | ||
69 | // clang-format off | ||
70 | { 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, }, | ||
71 | { 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x42, 0x00, }, | ||
72 | { 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xC3, 0x00, 0x00, }, | ||
73 | { 0x3C, 0x7E, 0xFF, 0xFF, 0xC3, 0x81, 0x00, 0x00, }, | ||
74 | { 0x3C, 0x7E, 0xFF, 0xC3, 0x81, 0x00, 0x00, 0x00, }, | ||
75 | { 0x3C, 0x7E, 0xC3, 0x81, 0x81, 0x00, 0x00, 0x00, }, | ||
76 | { 0x3C, 0x42, 0x81, 0x81, 0x00, 0x00, 0x00, 0x00, }, | ||
77 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, | ||
78 | { 0x00, 0x00, 0x00, 0x00, 0x81, 0x81, 0x42, 0x3C, }, | ||
79 | { 0x00, 0x00, 0x00, 0x81, 0x81, 0xC3, 0x7E, 0x3C, }, | ||
80 | { 0x00, 0x00, 0x00, 0x81, 0xC3, 0xFF, 0x7E, 0x3C, }, | ||
81 | { 0x00, 0x00, 0x81, 0xC3, 0xFF, 0xFF, 0x7E, 0x3C, }, | ||
82 | { 0x00, 0x00, 0xC3, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, }, | ||
83 | { 0x00, 0x42, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, }, | ||
84 | // clang-format on | ||
85 | }; | ||
86 | # endif | ||
87 | |||
88 | static void draw_moon(void) { | ||
89 | # ifdef STATIC_MOON | ||
90 | oled_set_cursor(MOON_COLUMN, MOON_LINE); | ||
91 | oled_write_raw_P(moon, 6); | ||
92 | # endif | ||
93 | # ifndef STATIC_MOON | ||
94 | moon_animation_counter = increment_counter(moon_animation_counter, ANIMATE_MOON_EVERY_N_FRAMES); | ||
95 | if (moon_animation_counter == 0) { | ||
96 | moon_animation_frame = increment_counter(moon_animation_frame, 14); | ||
97 | oled_set_cursor(MOON_COLUMN, MOON_LINE); | ||
98 | oled_write_raw_P(moon_animation[moon_animation_frame], 8); | ||
99 | } | ||
100 | # endif | ||
101 | } | ||
102 | #endif // endregion | ||
103 | |||
104 | #ifdef ENABLE_WAVE // region | ||
105 | uint8_t starry_night_wave_frame_width_counter = 31; | ||
106 | uint8_t rough_waves_frame_counter = 0; | ||
107 | |||
108 | // clang-format off | ||
109 | static const char PROGMEM ocean_top[8][32] = { | ||
110 | // still ocean | ||
111 | { | ||
112 | 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, | ||
113 | 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, | ||
114 | 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, | ||
115 | 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, | ||
116 | }, | ||
117 | // small ripples | ||
118 | { | ||
119 | 0x20, 0x60, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, | ||
120 | 0x20, 0x60, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, | ||
121 | 0x20, 0x60, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, | ||
122 | 0x20, 0x60, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, | ||
123 | }, | ||
124 | // level 2 ripples | ||
125 | { | ||
126 | 0x20, 0x60, 0x40, 0x40, 0x20, 0x60, 0x40, 0x40, | ||
127 | 0x20, 0x60, 0x40, 0x40, 0x20, 0x60, 0x40, 0x40, | ||
128 | 0x20, 0x60, 0x40, 0x40, 0x20, 0x60, 0x40, 0x40, | ||
129 | 0x20, 0x60, 0x40, 0x40, 0x20, 0x60, 0x40, 0x40, | ||
130 | }, | ||
131 | // level 3 waves | ||
132 | { | ||
133 | 0x40, 0x20, 0x10, 0x20, 0x40, 0x40, 0x40, 0x40, | ||
134 | 0x40, 0x20, 0x10, 0x20, 0x40, 0x40, 0x40, 0x40, | ||
135 | 0x40, 0x20, 0x10, 0x20, 0x40, 0x40, 0x40, 0x40, | ||
136 | 0x40, 0x20, 0x10, 0x20, 0x40, 0x40, 0x40, 0x40, | ||
137 | }, | ||
138 | { | ||
139 | 0x40, 0x40, 0x20, 0x10, 0x28, 0x50, 0x40, 0x40, | ||
140 | 0x40, 0x40, 0x20, 0x10, 0x28, 0x50, 0x40, 0x40, | ||
141 | 0x40, 0x40, 0x20, 0x10, 0x28, 0x50, 0x40, 0x40, | ||
142 | 0x40, 0x40, 0x20, 0x10, 0x28, 0x50, 0x40, 0x40, | ||
143 | }, | ||
144 | { | ||
145 | 0x40, 0x40, 0x40, 0x20, 0x10, 0x30, 0x70, 0x60, | ||
146 | 0x40, 0x40, 0x40, 0x20, 0x10, 0x30, 0x70, 0x60, | ||
147 | 0x40, 0x40, 0x40, 0x20, 0x10, 0x30, 0x70, 0x60, | ||
148 | 0x40, 0x40, 0x40, 0x20, 0x10, 0x30, 0x70, 0x60, | ||
149 | }, | ||
150 | }; | ||
151 | static const char PROGMEM ocean_bottom[8][32] = { | ||
152 | // still ocean | ||
153 | { | ||
154 | 0x00, 0x40, 0x40, 0x41, 0x01, 0x01, 0x01, 0x21, | ||
155 | 0x20, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x44, | ||
156 | 0x44, 0x40, 0x40, 0x00, 0x00, 0x08, 0x08, 0x00, | ||
157 | 0x01, 0x01, 0x01, 0x00, 0x40, 0x40, 0x00, 0x00, | ||
158 | }, | ||
159 | // small ripples | ||
160 | { | ||
161 | 0x00, 0x00, 0x40, 0x40, 0x01, 0x01, 0x01, 0x20, | ||
162 | 0x20, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, | ||
163 | 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, | ||
164 | 0x00, 0x01, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, | ||
165 | }, | ||
166 | // level 2 ripples | ||
167 | { | ||
168 | 0x00, 0x00, 0x40, 0x40, 0x01, 0x01, 0x01, 0x20, | ||
169 | 0x20, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, | ||
170 | 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, | ||
171 | 0x00, 0x01, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, | ||
172 | }, | ||
173 | // level 3 waves | ||
174 | { | ||
175 | 0x00, 0x40, 0x40, 0x42, 0x42, 0x03, 0x11, 0x11, | ||
176 | 0x20, 0x20, 0x00, 0x00, 0x08, 0x0C, 0x0C, 0x04, | ||
177 | 0x05, 0x41, 0x41, 0x21, 0x20, 0x00, 0x00, 0x08, | ||
178 | 0x0A, 0x0A, 0x0B, 0x41, 0x41, 0x41, 0x41, 0x00, | ||
179 | }, | ||
180 | { | ||
181 | 0x10, 0x10, 0x00, 0x80, 0x84, 0xC4, 0x02, 0x06, | ||
182 | 0x84, 0x44, 0xC0, 0x80, 0x80, 0x20, 0x20, 0x10, | ||
183 | 0x08, 0x12, 0x91, 0x81, 0x42, 0x40, 0x00, 0x00, | ||
184 | 0x10, 0x12, 0x22, 0x22, 0x24, 0x04, 0x84, 0x80, | ||
185 | }, | ||
186 | { | ||
187 | 0x08, 0x80, 0x80, 0x82, 0x82, 0x03, 0x21, 0x21, | ||
188 | 0x10, 0x10, 0x00, 0x00, 0x04, 0x04, 0x0C, 0x08, | ||
189 | 0x09, 0x41, 0x42, 0x22, 0x20, 0x00, 0x00, 0x08, | ||
190 | 0x0A, 0x0A, 0x0B, 0x41, 0x43, 0x42, 0x42, 0x00, | ||
191 | }, | ||
192 | }; | ||
193 | // clang-format on | ||
194 | |||
195 | static void animate_waves(void) { | ||
196 | starry_night_wave_frame_width_counter = decrement_counter(starry_night_wave_frame_width_counter, WIDTH - 1); // only 3 frames for last wave type | ||
197 | rough_waves_frame_counter = increment_counter(rough_waves_frame_counter, 3); // only 3 frames for last wave type | ||
198 | |||
199 | void draw_ocean(uint8_t frame, uint16_t offset, uint8_t byte_index) { | ||
200 | oled_write_raw_byte(pgm_read_byte(ocean_top[frame] + byte_index), offset); | ||
201 | oled_write_raw_byte(pgm_read_byte(ocean_bottom[frame] + byte_index), offset + WIDTH); | ||
202 | } | ||
203 | |||
204 | for (int i = 0; i < WIDTH; ++i) { | ||
205 | uint16_t offset = OCEAN_LINE * WIDTH + i; | ||
206 | uint8_t byte_index = starry_night_wave_frame_width_counter + i; | ||
207 | if (byte_index >= WIDTH) { | ||
208 | byte_index = byte_index - WIDTH; | ||
209 | } | ||
210 | if (is_calm || current_wpm <= WAVE_CALM) { | ||
211 | draw_ocean(0, offset, byte_index); | ||
212 | } else if (current_wpm <= WAVE_HEAVY_STORM) { | ||
213 | draw_ocean(1, offset, byte_index); | ||
214 | } else if (current_wpm <= WAVE_HURRICANE) { | ||
215 | draw_ocean(2, offset, byte_index); | ||
216 | } else { | ||
217 | draw_ocean(3 + rough_waves_frame_counter, offset, byte_index); | ||
218 | } | ||
219 | } | ||
220 | } | ||
221 | #endif // endregion | ||
222 | |||
223 | #ifdef ENABLE_ISLAND // region | ||
224 | uint8_t island_frame_1 = 0; | ||
225 | |||
226 | // clang-format off | ||
227 | // only use 46 bytes (first 18 are blank, so we don't write them, makes it smaller and we can see the shooting stars properly!) | ||
228 | |||
229 | // To save space and allow the shooting stars to be seen, only draw the tree on every frame. | ||
230 | // Tree is only 14bytes wide so we save 108 bytes on just the first row. Second row, the | ||
231 | // first 18 bytes is always the same piece of land, so only store that once, which saves 90 bytes | ||
232 | static const char PROGMEM islandRightTop[6][14] = { | ||
233 | {0x84, 0xEC, 0x6C, 0x3C, 0xF8, 0xFE, 0x3F, 0x6B, 0xDB, 0xB9, 0x30, 0x40, 0x00, 0x00,}, | ||
234 | {0x80, 0xC3, 0xEE, 0x7C, 0xB8, 0xFC, 0xFE, 0x6F, 0xDB, 0x9B, 0xB2, 0x30, 0x00, 0x00,}, | ||
235 | {0x00, 0xC0, 0xEE, 0x7F, 0x3D, 0xF8, 0xFC, 0x7E, 0x57, 0xDB, 0xDB, 0x8A, 0x00, 0x00,}, | ||
236 | {0x00, 0xC0, 0xE6, 0x7F, 0x3B, 0xF9, 0xFC, 0xFC, 0xB6, 0xB3, 0x33, 0x61, 0x00, 0x00,}, | ||
237 | {0x00, 0x00, 0x00, 0x00, 0x80, 0xEE, 0xFF, 0xFB, 0xF9, 0xFC, 0xDE, 0xB6, 0xB6, 0x24,}, | ||
238 | {0x00, 0x00, 0x00, 0x00, 0xC0, 0xEE, 0xFE, 0xFF, 0xFB, 0xFD, 0xEE, 0xB6, 0xB6, 0x92,}, | ||
239 | }; | ||
240 | static const char PROGMEM islandRightBottom[6][14] = { | ||
241 | {0x41, 0x40, 0x60, 0x3E, 0x3F, 0x23, 0x20, 0x60, 0x41, 0x43, 0x40, 0x40, 0x40, 0x80,}, | ||
242 | {0x40, 0x41, 0x60, 0x3E, 0x3F, 0x23, 0x20, 0x60, 0x40, 0x40, 0x41, 0x41, 0x40, 0x80,}, | ||
243 | {0x40, 0x40, 0x61, 0x3D, 0x3F, 0x27, 0x21, 0x60, 0x40, 0x40, 0x40, 0x40, 0x40, 0x80,}, | ||
244 | {0x40, 0x43, 0x61, 0x3C, 0x3F, 0x27, 0x21, 0x60, 0x41, 0x43, 0x43, 0x42, 0x40, 0x80,}, | ||
245 | {0x40, 0x40, 0x60, 0x3C, 0x3F, 0x27, 0x23, 0x63, 0x44, 0x40, 0x41, 0x41, 0x41, 0x81,}, | ||
246 | {0x40, 0x40, 0x60, 0x3C, 0x3F, 0x27, 0x23, 0x63, 0x42, 0x42, 0x41, 0x41, 0x41, 0x80,}, | ||
247 | }; | ||
248 | static const char PROGMEM islandLeft[18] = { | ||
249 | 0x80, 0x40, 0x40, 0x40, 0x40, 0x60, | ||
250 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, | ||
251 | 0x20, 0x20, 0x20, 0x60, 0x40, 0x40, | ||
252 | }; | ||
253 | // clang-format on | ||
254 | |||
255 | static void animate_island(void) { | ||
256 | if (animation_counter == 0) { | ||
257 | island_frame_1 = increment_counter(island_frame_1, 2); | ||
258 | } | ||
259 | |||
260 | void draw_island_parts(uint8_t frame) { | ||
261 | oled_set_cursor(ISLAND_COLUMN + 3, ISLAND_LINE); | ||
262 | oled_write_raw_P(islandRightTop[frame], 14); | ||
263 | oled_set_cursor(ISLAND_COLUMN + 0, ISLAND_LINE + 1); | ||
264 | oled_write_raw_P(islandLeft, 18); | ||
265 | oled_set_cursor(ISLAND_COLUMN + 3, ISLAND_LINE + 1); | ||
266 | oled_write_raw_P(islandRightBottom[frame], 14); | ||
267 | } | ||
268 | |||
269 | if (is_calm || current_wpm < ISLAND_CALM) { | ||
270 | draw_island_parts(0); | ||
271 | } else if (current_wpm >= ISLAND_CALM && current_wpm < ISLAND_HEAVY_STORM) { | ||
272 | draw_island_parts(island_frame_1 + 1); | ||
273 | } else if (current_wpm >= ISLAND_HEAVY_STORM && current_wpm < ISLAND_HURRICANE) { | ||
274 | draw_island_parts(island_frame_1 + 2); | ||
275 | } else { | ||
276 | draw_island_parts(island_frame_1 + 4); | ||
277 | } | ||
278 | } | ||
279 | #endif // endregion | ||
280 | |||
281 | #ifdef ENABLE_STARS // region | ||
282 | bool stars_setup = false; // only setup stars once, then we just twinkle them | ||
283 | struct Coordinate { | ||
284 | int x; | ||
285 | int y; | ||
286 | bool exists; | ||
287 | }; | ||
288 | |||
289 | struct Coordinate stars[TOTAL_STARS]; // tracks all stars/coordinates | ||
290 | |||
291 | /** | ||
292 | * Setup all the initial stars on the screen | ||
293 | * This function divides the screen into regions based on STARS_PER_LINE and NUMBER_OF_STAR_LINES | ||
294 | * where each line is made up of 8x8 pixel groups, that are populated by a single star. | ||
295 | * | ||
296 | * Not sure how this function will work with larger or smaller screens. | ||
297 | * It should be fine, as long as the screen width is a multiple of 8 | ||
298 | */ | ||
299 | static void setup_stars(void) { | ||
300 | // For every line, split the line into STARS_PER_LINE, find a random point in that region, and turn the pixel on | ||
301 | // 36% probability it will not be added | ||
302 | // (said another way, 80% chance it will start out lit in the x direction, then 80% chance it will start out lit in the y direction = 64% probability it will start out lit at all) | ||
303 | for (int line = 0; line < NUMBER_OF_STAR_LINES; ++line) { | ||
304 | for (int column_group = 0; column_group < STARS_PER_LINE; ++column_group) { | ||
305 | uint8_t rand_column = rand() % 10; | ||
306 | uint8_t rand_row = rand() % 10; | ||
307 | if (rand_column < 8 && rand_row < 8) { | ||
308 | int column_adder = column_group * 8; | ||
309 | int line_adder = line * 8; | ||
310 | int x = rand_column + column_adder; | ||
311 | int y = rand_row + line_adder; | ||
312 | oled_write_pixel(x, y, true); | ||
313 | stars[column_group + (line * STARS_PER_LINE)].x = x; | ||
314 | stars[column_group + (line * STARS_PER_LINE)].y = y; | ||
315 | stars[column_group + (line * STARS_PER_LINE)].exists = true; | ||
316 | } else { | ||
317 | stars[column_group + (line * STARS_PER_LINE)].exists = false; | ||
318 | } | ||
319 | } | ||
320 | } | ||
321 | stars_setup = true; | ||
322 | } | ||
323 | |||
324 | /** | ||
325 | * Twinkle the stars (move them one pixel in any direction) with a probability of 50% to twinkle any given star | ||
326 | */ | ||
327 | static void twinkle_stars(void) { | ||
328 | for (int line = 0; line < NUMBER_OF_STAR_LINES; ++line) { | ||
329 | for (int column_group = 0; column_group < STARS_PER_LINE; ++column_group) { | ||
330 | struct Coordinate star = stars[column_group + (line * STARS_PER_LINE)]; | ||
331 | |||
332 | // skip stars that were never added | ||
333 | if (!star.exists) { | ||
334 | continue; | ||
335 | } | ||
336 | if (rand() % TWINKLE_PROBABILITY_MODULATOR == 0) { | ||
337 | oled_write_pixel(star.x, star.y, false); // black out pixel | ||
338 | |||
339 | // don't allow stars to leave their own region | ||
340 | if (star.x == (column_group * 8)) { // star is the farthest left it can go in its region | ||
341 | star.x++; // move it right immediately | ||
342 | } else if (star.x == (((column_group + 1) * 8) - 1)) { // star is farthest right it can go in its region | ||
343 | star.x--; // move it left immediately | ||
344 | } | ||
345 | if (star.y == (line * 8)) { // star is the farthest up it can go in its region | ||
346 | star.y++; // move it down immediately | ||
347 | } else if (star.y == (((line + 1) * 8) - 1)) { // star is farthest down it can go in its region | ||
348 | star.y--; // move it up immediately | ||
349 | } | ||
350 | |||
351 | // now decide direction | ||
352 | int new_x; | ||
353 | int x_choice = rand() % 3; | ||
354 | if (x_choice == 0) { | ||
355 | new_x = star.x - 1; | ||
356 | } else if (x_choice == 1) { | ||
357 | new_x = star.x + 1; | ||
358 | } else { | ||
359 | new_x = star.x; | ||
360 | } | ||
361 | |||
362 | int new_y; | ||
363 | int y_choice = rand() % 3; | ||
364 | if (y_choice == 0) { | ||
365 | new_y = star.y - 1; | ||
366 | } else if (y_choice == 1) { | ||
367 | new_y = star.y + 1; | ||
368 | } else { | ||
369 | new_y = star.y; | ||
370 | } | ||
371 | |||
372 | star.x = new_x; | ||
373 | star.y = new_y; | ||
374 | oled_write_pixel(new_x, new_y, true); | ||
375 | } | ||
376 | |||
377 | stars[column_group + (line * STARS_PER_LINE)] = star; | ||
378 | } | ||
379 | } | ||
380 | } | ||
381 | |||
382 | /** | ||
383 | * Setup the stars and then animate them on subsequent frames | ||
384 | */ | ||
385 | static void animate_stars(void) { | ||
386 | if (!stars_setup) { | ||
387 | setup_stars(); | ||
388 | } else { | ||
389 | twinkle_stars(); | ||
390 | } | ||
391 | } | ||
392 | #endif // endregion | ||
393 | |||
394 | #ifdef ENABLE_SHOOTING_STARS // region | ||
395 | bool shooting_stars_setup = false; // only setup shooting stars array once with defaults | ||
396 | |||
397 | struct ShootingStar { | ||
398 | int x_1; | ||
399 | int y_1; | ||
400 | int x_2; | ||
401 | int y_2; | ||
402 | bool running; | ||
403 | int frame; | ||
404 | int delay; | ||
405 | }; | ||
406 | |||
407 | struct ShootingStar shooting_stars[MAX_NUMBER_OF_SHOOTING_STARS]; // tracks all the shooting stars | ||
408 | |||
409 | static void setup_shooting_star(struct ShootingStar *shooting_star) { | ||
410 | int column_to_start = rand() % (WIDTH / 2); | ||
411 | int row_to_start = rand() % (HEIGHT - 48); // shooting_stars travel diagonally 1 down, 1 across. So the lowest a shooting_star can start and not 'hit' the ocean is 32 above the ocean. | ||
412 | |||
413 | shooting_star->x_1 = column_to_start; | ||
414 | shooting_star->y_1 = row_to_start; | ||
415 | shooting_star->x_2 = column_to_start + 1; | ||
416 | shooting_star->y_2 = row_to_start + 1; | ||
417 | shooting_star->running = true; | ||
418 | shooting_star->frame++; | ||
419 | shooting_star->delay = rand() % SHOOTING_STAR_DELAY; | ||
420 | } | ||
421 | |||
422 | static void move_shooting_star(struct ShootingStar *shooting_star) { | ||
423 | oled_write_pixel(shooting_star->x_1, shooting_star->y_1, false); | ||
424 | oled_write_pixel(shooting_star->x_2, shooting_star->y_2, false); | ||
425 | |||
426 | shooting_star->x_1++; | ||
427 | shooting_star->y_1++; | ||
428 | shooting_star->x_2++; | ||
429 | shooting_star->y_2++; | ||
430 | shooting_star->frame++; | ||
431 | |||
432 | oled_write_pixel(shooting_star->x_1, shooting_star->y_1, true); | ||
433 | oled_write_pixel(shooting_star->x_2, shooting_star->y_2, true); | ||
434 | } | ||
435 | |||
436 | static void finish_shooting_star(struct ShootingStar *shooting_star) { | ||
437 | oled_write_pixel(shooting_star->x_1, shooting_star->y_1, false); | ||
438 | oled_write_pixel(shooting_star->x_2, shooting_star->y_2, false); | ||
439 | shooting_star->running = false; | ||
440 | shooting_star->frame = 0; | ||
441 | } | ||
442 | |||
443 | static void animate_shooting_star(struct ShootingStar *shooting_star) { | ||
444 | if (shooting_star->frame > SHOOTING_STAR_FRAMES) { | ||
445 | finish_shooting_star(shooting_star); | ||
446 | return; | ||
447 | } else if (!shooting_star->running) { | ||
448 | setup_shooting_star(shooting_star); | ||
449 | } else { | ||
450 | if (shooting_star->delay == 0) { | ||
451 | move_shooting_star(shooting_star); | ||
452 | } else { | ||
453 | shooting_star->delay--; | ||
454 | } | ||
455 | } | ||
456 | } | ||
457 | |||
458 | static void animate_shooting_stars(void) { | ||
459 | if (is_calm) { | ||
460 | return; | ||
461 | } | ||
462 | if (!shooting_stars_setup) { | ||
463 | for (int i = 0; i < MAX_NUMBER_OF_SHOOTING_STARS; ++i) { | ||
464 | shooting_stars[i].running = false; | ||
465 | } | ||
466 | shooting_stars_setup = true; | ||
467 | } | ||
468 | /** | ||
469 | * Fixes issue with stars that were falling _while_ the | ||
470 | * wpm dropped below the condition for them to keep falling | ||
471 | */ | ||
472 | void end_extra_stars(uint8_t starting_index) { | ||
473 | for (int shooting_star_index = starting_index; shooting_star_index < MAX_NUMBER_OF_SHOOTING_STARS; ++shooting_star_index) { | ||
474 | struct ShootingStar shooting_star = shooting_stars[shooting_star_index]; | ||
475 | if (shooting_star.running) { | ||
476 | finish_shooting_star(&shooting_star); | ||
477 | shooting_stars[shooting_star_index] = shooting_star; | ||
478 | } | ||
479 | } | ||
480 | } | ||
481 | |||
482 | int number_of_shooting_stars = current_wpm / SHOOTING_STAR_WPM_INCREMENT; | ||
483 | number_of_shooting_stars = (number_of_shooting_stars > MAX_NUMBER_OF_SHOOTING_STARS) ? MAX_NUMBER_OF_SHOOTING_STARS : number_of_shooting_stars; | ||
484 | |||
485 | if (number_of_shooting_stars == 0) { | ||
486 | // make sure all shooting_stars are ended | ||
487 | end_extra_stars(0); | ||
488 | } else { | ||
489 | for (int shooting_star_index = 0; shooting_star_index < number_of_shooting_stars; ++shooting_star_index) { | ||
490 | struct ShootingStar shooting_star = shooting_stars[shooting_star_index]; | ||
491 | animate_shooting_star(&shooting_star); | ||
492 | shooting_stars[shooting_star_index] = shooting_star; | ||
493 | } | ||
494 | end_extra_stars(number_of_shooting_stars); | ||
495 | } | ||
496 | } | ||
497 | #endif // endregion | ||
498 | |||
499 | /** | ||
500 | * Main rendering function | ||
501 | * | ||
502 | * Calls all different animations at different rates | ||
503 | */ | ||
504 | void render_stars(void) { | ||
505 | // // animation timer | ||
506 | if (timer_elapsed32(starry_night_anim_timer) > STARRY_NIGHT_ANIM_FRAME_DURATION) { | ||
507 | starry_night_anim_timer = timer_read32(); | ||
508 | current_wpm = get_current_wpm(); | ||
509 | |||
510 | #ifdef ENABLE_ISLAND | ||
511 | animate_island(); | ||
512 | #endif | ||
513 | |||
514 | #ifdef ENABLE_SHOOTING_STARS | ||
515 | if (animation_counter % SHOOTING_STAR_ANIMATION_MODULATOR == 0) { | ||
516 | animate_shooting_stars(); | ||
517 | } | ||
518 | #endif | ||
519 | |||
520 | #ifdef ENABLE_STARS | ||
521 | // TODO offsetting the star animation from the wave animation would look better, | ||
522 | // but if I do that, then the stars appear in the water because | ||
523 | // the ocean animation has to wait a bunch of frames to overwrite it. | ||
524 | // Possible solutions: | ||
525 | // 1. Only draw stars to the top of the island/ocean. | ||
526 | // 2. Draw ocean every frame, only move ocean on frames matching modulus | ||
527 | // Problems: | ||
528 | // 1. What if someone wants to move the island up a bit, or they want to have the stars reflect in the water? | ||
529 | // 2. More cpu intensive. And I'm already running out of cpu as it is... | ||
530 | if (animation_counter % STAR_ANIMATION_MODULATOR == 0) { | ||
531 | animate_stars(); | ||
532 | } | ||
533 | #endif | ||
534 | |||
535 | #ifdef ENABLE_WAVE | ||
536 | if (animation_counter % OCEAN_ANIMATION_MODULATOR == 0) { | ||
537 | animate_waves(); | ||
538 | } | ||
539 | #endif | ||
540 | |||
541 | #ifdef ENABLE_MOON | ||
542 | draw_moon(); | ||
543 | #endif | ||
544 | |||
545 | animation_counter = increment_counter(animation_counter, NUMBER_OF_FRAMES); | ||
546 | } | ||
547 | |||
548 | // this fixes the screen on and off bug | ||
549 | if (current_wpm > 0) { | ||
550 | oled_on(); | ||
551 | starry_night_anim_sleep = timer_read32(); | ||
552 | } else if (timer_elapsed32(starry_night_anim_sleep) > OLED_TIMEOUT) { | ||
553 | oled_off(); | ||
554 | } | ||
555 | } | ||
diff --git a/users/snowe/ocean_dream.h b/users/snowe/ocean_dream.h new file mode 100644 index 000000000..498375559 --- /dev/null +++ b/users/snowe/ocean_dream.h | |||
@@ -0,0 +1,103 @@ | |||
1 | /* | ||
2 | * Copyright 2021 Tyler Thrailkill (@snowe/@snowe2010) <tyler.b.thrailkill@gmail.com> | ||
3 | * | ||
4 | * This program is free software: you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation, either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #pragma once | ||
19 | #include "quantum.h" | ||
20 | |||
21 | /** | ||
22 | * Features: | ||
23 | * You can turn on and off features in this section | ||
24 | */ | ||
25 | #define ENABLE_MOON // Uses 182 bytes | ||
26 | #define ENABLE_WAVE // Uses 844 bytes | ||
27 | #define ENABLE_SHOOTING_STARS // Uses 872 bytes | ||
28 | #define ENABLE_ISLAND | ||
29 | #define ENABLE_STARS // Uses 606 bytes | ||
30 | |||
31 | /** | ||
32 | * Global Settings | ||
33 | */ | ||
34 | #define STARRY_NIGHT_ANIM_FRAME_DURATION 30 // how long each frame lasts in ms | ||
35 | #define NUMBER_OF_FRAMES 20 // Self explanatory. Probably shouldn't touch this, not sure how stuff will work if it's changed. If changed should be multiple of 1, 2, 3, 4, and 5 | ||
36 | #define WIDTH OLED_DISPLAY_HEIGHT // for vertical displays | ||
37 | #define HEIGHT OLED_DISPLAY_WIDTH // for vertical displays | ||
38 | |||
39 | /** | ||
40 | * Moon Parameters | ||
41 | */ | ||
42 | #define MOON_LINE 4 // the line you want the moon to appear at | ||
43 | #define MOON_COLUMN 4 // the column you want the moon to appear at | ||
44 | //#define STATIC_MOON // uncomment this to make the moon a static image, no animation | ||
45 | #ifndef STATIC_MOON | ||
46 | # define ANIMATE_MOON_EVERY_N_FRAMES 100 // animate the moon every n frames | ||
47 | #endif | ||
48 | |||
49 | /** | ||
50 | * Wave Parameters | ||
51 | */ | ||
52 | #define OCEAN_LINE 14 // Line you want to render the ocean starting at (best at oled_max_lines() - 2) | ||
53 | #define WAVE_CALM 20 // render calm ocean under this WPM and ripple ocean at this WPM | ||
54 | #define WAVE_HEAVY_STORM 40 // render medium ocean at this WPM | ||
55 | #define WAVE_HURRICANE 60 // render heavy waves above this WPM | ||
56 | // What number of frames you want to animate the ocean at. | ||
57 | // Should be equal to or smaller than NUMBER_OF_FRAMES, e.g. 30, would animate on every other frame, 20, every third frame, etc | ||
58 | // Don't set equal to 0. | ||
59 | #define OCEAN_ANIMATION_SPEED 1 | ||
60 | |||
61 | /** | ||
62 | * Shooting Star Parameters | ||
63 | */ | ||
64 | #define SHOOTING_STAR_DELAY 12 // delay modulus for time between shooting stars. Decides number of frames to delay, e.g. 12 means 0-11 frames of delay between each shooting star | ||
65 | #define SHOOTING_STAR_FRAMES 16 // how many 2 pixel frames per shooting star. Increment this for longer shooting stars | ||
66 | #define MAX_NUMBER_OF_SHOOTING_STARS 12 // maximum number of shooting stars that can be on screen at the same time | ||
67 | #define SHOOTING_STAR_WPM_INCREMENT 10 // every n WPM increase, add an extra star, up to MAX_NUMBER_OF_SHOOTING_STARS, e.g. an increment of 5 would result in 1 shooting star at 5-9wpm, 2 at 10-14, etc. | ||
68 | // What number of frames you want to animate the shooting stars at. | ||
69 | // Should be equal to or smaller than NUMBER_OF_FRAMES, e.g. 30, would animate on every other frame, 20, every third frame, etc | ||
70 | // Don't set equal to 0. | ||
71 | #define SHOOTING_STAR_ANIMATION_SPEED 30 | ||
72 | |||
73 | /** | ||
74 | * Star Parameters | ||
75 | */ | ||
76 | #define STARS_PER_LINE 4 // number of stars per line (for a display that is 128x32, this would be 4 stars spread out evenly over the 32byte width, one every 8 bytes) | ||
77 | #define NUMBER_OF_STAR_LINES 16 // number of lines to fill up with stars (for a display that is 128x32, 16 bytes are filled with the ocean animation, so that leaves 112 pixels left over. The number of lines depends on your OLED_FONT_HEIGHT) | ||
78 | #define TWINKLE_PROBABILITY 25 // probability that any star twinkles on a given frame | ||
79 | // What number of frames you want to animate the stars at. | ||
80 | // Should be equal to or smaller than NUMBER_OF_FRAMES, e.g. 20, would animate on every frame, 10, every other frame, etc | ||
81 | // Don't set equal to 0. | ||
82 | #define STAR_ANIMATION_SPEED 1 | ||
83 | |||
84 | /** | ||
85 | * Island Parameters | ||
86 | */ | ||
87 | #define ISLAND_LINE 12 // line that the island starts at. Island is 2 lines tall | ||
88 | #define ISLAND_COLUMN 0 // column that the island starts at | ||
89 | #define ISLAND_CALM 20 // WPM at which the palm tree calmly moves | ||
90 | #define ISLAND_HEAVY_STORM 40 // WPM at which the heavy storm occurs | ||
91 | #define ISLAND_HURRICANE 60 // WPM at which THE HURRICANE STARTS | ||
92 | |||
93 | /* | ||
94 | * DON'T TOUCH | ||
95 | */ | ||
96 | |||
97 | extern bool is_calm; | ||
98 | |||
99 | // timers | ||
100 | extern uint32_t starry_night_anim_timer; | ||
101 | extern uint32_t starry_night_anim_sleep; | ||
102 | |||
103 | void render_stars(void); | ||
diff --git a/users/snowe/oled_setup.c b/users/snowe/oled_setup.c new file mode 100644 index 000000000..b3e04df45 --- /dev/null +++ b/users/snowe/oled_setup.c | |||
@@ -0,0 +1,141 @@ | |||
1 | /* | ||
2 | * Copyright QMK Community | ||
3 | * Copyright 2021 Tyler Thrailkill (@snowe/@snowe2010) <tyler.b.thrailkill@gmail.com> | ||
4 | * | ||
5 | * This program is free software: you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation, either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #ifdef OLED_DRIVER_ENABLE | ||
20 | |||
21 | # include QMK_KEYBOARD_H | ||
22 | # include "quantum.h" | ||
23 | # include "snowe.h" | ||
24 | |||
25 | # include <stdio.h> // for keylog? | ||
26 | |||
27 | oled_rotation_t oled_init_user(oled_rotation_t rotation) { | ||
28 | if (!is_master) { | ||
29 | return OLED_ROTATION_270; // flips the display 180 degrees if offhand | ||
30 | } | ||
31 | return OLED_ROTATION_270; | ||
32 | } | ||
33 | |||
34 | # define L_BASE 0 | ||
35 | # define L_LOWER 2 | ||
36 | # define L_RAISE 4 | ||
37 | # define L_ADJUST 8 | ||
38 | |||
39 | void oled_render_layer_state(void) { | ||
40 | oled_write_P(PSTR("Layer"), false); | ||
41 | switch (layer_state) { | ||
42 | case L_BASE: | ||
43 | oled_write_ln_P(PSTR("Main"), false); | ||
44 | break; | ||
45 | case L_LOWER: | ||
46 | oled_write_ln_P(PSTR("Bot"), false); | ||
47 | break; | ||
48 | case L_RAISE: | ||
49 | oled_write_ln_P(PSTR("Top"), false); | ||
50 | break; | ||
51 | case L_ADJUST: | ||
52 | case L_ADJUST | L_LOWER: | ||
53 | case L_ADJUST | L_RAISE: | ||
54 | case L_ADJUST | L_LOWER | L_RAISE: | ||
55 | oled_write_ln_P(PSTR("Comb"), false); | ||
56 | break; | ||
57 | } | ||
58 | } | ||
59 | |||
60 | char keylog_str[24] = {}; | ||
61 | |||
62 | const char code_to_name[60] = { | ||
63 | ' ', ' ', ' ', ' ', 'a', 'b', 'c', 'd', 'e', 'f', | ||
64 | 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', | ||
65 | 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', | ||
66 | '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', | ||
67 | 'R', 'E', 'B', 'T', '_', '-', '=', '[', ']', '\\', | ||
68 | '#', ';', '\'', '`', ',', '.', '/', ' ', ' ', ' '}; | ||
69 | |||
70 | void set_keylog(uint16_t keycode, keyrecord_t *record) { | ||
71 | char name = ' '; | ||
72 | if ((keycode >= QK_MOD_TAP && keycode <= QK_MOD_TAP_MAX) || (keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX)) { | ||
73 | keycode = keycode & 0xFF; | ||
74 | } | ||
75 | if (keycode < 60) { | ||
76 | name = code_to_name[keycode]; | ||
77 | } | ||
78 | |||
79 | // update keylog | ||
80 | snprintf(keylog_str, sizeof(keylog_str), "%dx%d, k%2d : %c", record->event.key.row, record->event.key.col, keycode, name); | ||
81 | } | ||
82 | |||
83 | void oled_render_keylog(void) { oled_write(keylog_str, false); } | ||
84 | |||
85 | // void render_bootmagic_status(bool status) { | ||
86 | // /* Show Ctrl-Gui Swap options */ | ||
87 | // static const char PROGMEM logo[][2][3] = { | ||
88 | // {{0x97, 0x98, 0}, {0xb7, 0xb8, 0}}, | ||
89 | // {{0x95, 0x96, 0}, {0xb5, 0xb6, 0}}, | ||
90 | // }; | ||
91 | // if (status) { | ||
92 | // oled_write_ln_P(logo[0][0], false); | ||
93 | // oled_write_ln_P(logo[0][1], false); | ||
94 | // } else { | ||
95 | // oled_write_ln_P(logo[1][0], false); | ||
96 | // oled_write_ln_P(logo[1][1], false); | ||
97 | // } | ||
98 | //} | ||
99 | void render_bootmagic_status(void) { | ||
100 | /* Show Ctrl-Gui Swap options */ | ||
101 | static const char PROGMEM logo[][2][3] = { | ||
102 | {{0x97, 0x98, 0}, {0xb7, 0xb8, 0}}, | ||
103 | {{0x95, 0x96, 0}, {0xb5, 0xb6, 0}}, | ||
104 | }; | ||
105 | oled_write_P(PSTR("BTMGK"), false); | ||
106 | oled_write_P(PSTR(""), false); | ||
107 | if (!keymap_config.swap_lctl_lgui) { | ||
108 | oled_write_P(logo[1][0], false); | ||
109 | oled_write_P(PSTR(" "), false); | ||
110 | oled_write_P(logo[1][1], false); | ||
111 | } else { | ||
112 | oled_write_P(logo[0][0], false); | ||
113 | oled_write_P(PSTR(" "), false); | ||
114 | oled_write_P(logo[0][1], false); | ||
115 | } | ||
116 | oled_write_P(PSTR(" NKRO "), keymap_config.nkro); | ||
117 | oled_write_P(PSTR("WPM: "), false); | ||
118 | |||
119 | char wpm[6]; | ||
120 | itoa(get_current_wpm(), wpm, 10); | ||
121 | oled_write_ln(wpm, false); | ||
122 | } | ||
123 | |||
124 | void oled_task_user(void) { | ||
125 | if (is_master) { | ||
126 | oled_render_layer_state(); | ||
127 | oled_render_keylog(); | ||
128 | render_bootmagic_status(); | ||
129 | |||
130 | # ifdef LUNA_ENABLE | ||
131 | led_usb_state = host_keyboard_led_state(); | ||
132 | render_luna(0, 13); | ||
133 | # endif | ||
134 | } else { | ||
135 | # ifdef OCEAN_DREAM_ENABLE | ||
136 | render_stars(); | ||
137 | # endif | ||
138 | } | ||
139 | } | ||
140 | |||
141 | #endif // OLED_DRIVER_ENABLE | ||
diff --git a/users/snowe/oled_setup.h b/users/snowe/oled_setup.h new file mode 100644 index 000000000..031ce6bd0 --- /dev/null +++ b/users/snowe/oled_setup.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * Copyright 2021 Tyler Thrailkill (@snowe/@snowe2010) <tyler.b.thrailkill@gmail.com> | ||
3 | * | ||
4 | * This program is free software: you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation, either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #pragma once | ||
19 | |||
20 | #include "quantum.h" | ||
21 | #ifdef OLED_DRIVER_ENABLE | ||
22 | # include "oled_driver.h" | ||
23 | # define OLED_RENDER_WPM_COUNTER " WPM: " | ||
24 | #endif | ||
25 | #ifdef LUNA_ENABLE | ||
26 | # include "luna.h" | ||
27 | #endif | ||
28 | #ifdef OCEAN_DREAM_ENABLE | ||
29 | # include "ocean_dream.h" | ||
30 | #endif \ No newline at end of file | ||
diff --git a/users/snowe/readme.md b/users/snowe/readme.md new file mode 100644 index 000000000..ff45c9df2 --- /dev/null +++ b/users/snowe/readme.md | |||
@@ -0,0 +1,10 @@ | |||
1 | # Welcome | ||
2 | |||
3 | Welcome to my userspace. | ||
4 | |||
5 | There's nothing really outstanding here, except the [Ocean Dream](readme_ocean_dream.md) | ||
6 | animation I made. | ||
7 | |||
8 | A lot of the code for my wrappers/keymaps came from other users. | ||
9 | |||
10 | I will probably update this with more in-depth information later. | ||
diff --git a/users/snowe/readme_ocean_dream.md b/users/snowe/readme_ocean_dream.md new file mode 100644 index 000000000..ca15dd47c --- /dev/null +++ b/users/snowe/readme_ocean_dream.md | |||
@@ -0,0 +1,258 @@ | |||
1 | # Ocean Dream | ||
2 | |||
3 | Tapping away at your IMX Corne with Box Jades, you feel yourself | ||
4 | drifting off, into a soundscape of waves and rustling leaves. | ||
5 | You open your eyes only to find yourself in an _Ocean Dream_. | ||
6 | |||
7 | Introducing, **Ocean Dream**, an animation for keyboards with tall OLED | ||
8 | screens. Built for 128x32 screens, this animation should work for 128x64 | ||
9 | at least, though it hasn't been tested there. | ||
10 | |||
11 | Completely customizable, you can change everything about the animation, | ||
12 | from the number of falling stars, to how likely a star is to twinkle, and | ||
13 | even if the moon has phases or not. | ||
14 | |||
15 | # Installation | ||
16 | |||
17 | Installation is easy. | ||
18 | |||
19 | 1. Add `ocean.h` and `ocean.c` to your keyboard folder or userspace. | ||
20 | 2. In your `keymap.c` or wherever you handle your oled code, add | ||
21 | ```c | ||
22 | # ifdef OCEAN_DREAM_ENABLE | ||
23 | render_stars(); | ||
24 | # endif | ||
25 | ``` | ||
26 | to `oled_task_user(void)`, where you would like (see [my keymap](../../keyboards/crkbd/keymaps/snowe/keymap.c) for an example) | ||
27 | 3. In your `keymap.c` or wherever you handle your process_record code, | ||
28 | add an event that sets `is_calm` when you press `ctrl` | ||
29 | ```c | ||
30 | bool process_record_user(uint16_t keycode, keyrecord_t *record) { | ||
31 | switch (keycode) { | ||
32 | case KC_LCTL: | ||
33 | case KC_RCTL: | ||
34 | #ifdef OCEAN_DREAM_ENABLE | ||
35 | is_calm = (record->event.pressed) ? true : false; | ||
36 | #endif | ||
37 | break; | ||
38 | } | ||
39 | return true; | ||
40 | } | ||
41 | ``` | ||
42 | 4. In your `rules.mk` to make it easier to turn the animation on/off, add | ||
43 | ```makefile | ||
44 | ifeq ($(strip $(OLED_DRIVER_ENABLE)), yes) | ||
45 | #... your code here... | ||
46 | |||
47 | ifdef OCEAN_DREAM_ENABLE | ||
48 | ifeq ($(strip $(OCEAN_DREAM_ENABLE)), yes) | ||
49 | SRC += ocean_dream.c | ||
50 | OPT_DEFS += -DOCEAN_DREAM_ENABLE | ||
51 | endif | ||
52 | endif | ||
53 | ifndef OCEAN_DREAM_ENABLE | ||
54 | SRC += ocean_dream.c | ||
55 | OPT_DEFS += -DOCEAN_DREAM_ENABLE | ||
56 | endif | ||
57 | endif | ||
58 | ``` | ||
59 | |||
60 | You're done! Now you can enable **Ocean Dream** by simply turning on the OLED feature | ||
61 | ```makefile | ||
62 | OLED_DRIVER_ENABLE = yes | ||
63 | ``` | ||
64 | |||
65 | And if you want to disable it without turning off the OLED Driver you can simply set | ||
66 | ```makefile | ||
67 | OCEAN_DREAM_ENABLE = no | ||
68 | ``` | ||
69 | |||
70 | # Settings | ||
71 | |||
72 | **Ocean Dream** comes with several different animations, all individually configurable: | ||
73 | |||
74 | * 🌌 Stars that twinkle | ||
75 | * 🌠 Meteor showers that get more vibrant the faster you type | ||
76 | * 🌊 Waves that get rougher the faster you type | ||
77 | * 🏝 An island with a palm tree that blows in the wind the faster you type | ||
78 | * 🌗 A moon that goes through the moon phases (or not, your choice!) | ||
79 | |||
80 | Each feature can be individually turned on and off, with a simple `#define`. | ||
81 | |||
82 | You can see all the options and more documentation by looking at `ocean_dream.h`. | ||
83 | |||
84 | All options come enabled by default. | ||
85 | |||
86 | ## Global Flags: | ||
87 | |||
88 | ### Toggles: | ||
89 | |||
90 | You can toggle on/off any features using these flags: | ||
91 | |||
92 | * `ENABLE_MOON` // Uses 182 bytes | ||
93 | * `ENABLE_WAVE` // Uses 844 bytes | ||
94 | * `ENABLE_SHOOTING_STARS` // Uses 872 bytes | ||
95 | * `ENABLE_ISLAND` | ||
96 | * `ENABLE_STARS` // Uses 606 bytes | ||
97 | |||
98 | ### Global Configuration: | ||
99 | |||
100 | * `STARRY_NIGHT_ANIM_FRAME_DURATION` - configures how long each frame lasts in ms | ||
101 | * `NUMBER_OF_FRAMES` - configures the number of frames that constitute a single 'round trip' of animation. | ||
102 | Enables keeping animations in sync/timed with each other. | ||
103 | Probably shouldn't touch this, not sure how stuff will work if it's changed. | ||
104 | If changed should probably be multiple of 1, 2, 3, 4, and 5 | ||
105 | * `WIDTH` - for vertical displays, configures the width (the shortest measurement of your display). defaults to `OLED_DISPLAY_HEIGHT` | ||
106 | * `HEIGHT` - for vertical displays, configures the height (the longest measurement of your display). defaults to `OLED_DISPLAY_WIDTH` | ||
107 | |||
108 | ## Stars | ||
109 | |||
110 | ### Description | ||
111 | |||
112 | The 🌌 stars animation is a background of slowly twinkling stars. | ||
113 | The stars are built on a grid of sorts, where each cell of the grid | ||
114 | is 8x8 pixels with 1 star per cell. There is a probability of any | ||
115 | star twinkling on any given frame, decided by the corresponding flags. | ||
116 | |||
117 | ### Flags | ||
118 | |||
119 | Enabled with the `#define ENABLE_STARS` directive. | ||
120 | |||
121 | The stars come with several configuration options: | ||
122 | |||
123 | * `STARS_PER_LINE` - configures the number of stars per line. Defaulting to 4, this would | ||
124 | mean that you have 4 stars across each line (8x32 on a 128x32 display), where each star | ||
125 | is in a 8x8 grid | ||
126 | * `NUMBER_OF_STAR_LINES` - configures the number of lines to fill up with stars. | ||
127 | Defaults to 16, filling the whole display. | ||
128 | * `TWINKLE_PROBABILITY` - configures the probability of a star twinkling on a given frame. | ||
129 | * `STAR_ANIMATION_SPEED` - configures the number of frames you want to animate the star at. | ||
130 | Must be equal to or lower than `NUMBER_OF_FRAMES`. | ||
131 | Example: | ||
132 | ```c | ||
133 | #define NUMBER_OF_FRAMES 20 | ||
134 | #define STAR_ANIMATION_SPEED 5 | ||
135 | ``` | ||
136 | would result in the star animation happening every 4 frames. 20 would result in every frame, | ||
137 | 1 would be once every 20 frames. This essentially changes how fast stars will twinkle, but | ||
138 | does not change the probability of the stars twinkling. | ||
139 | |||
140 | ## Moon | ||
141 | |||
142 | ### Description | ||
143 | |||
144 | The 🌗 moon animation is an 8x8 animation of a moon, or, if you are running out of program memory, you | ||
145 | can set it to just a static crescent moon, with no animation. | ||
146 | |||
147 | ### Flags | ||
148 | |||
149 | Enabled with the `#define ENABLE_MOON` directive. | ||
150 | |||
151 | The moon comes with only a few configuration options: | ||
152 | |||
153 | * `STATIC_MOON` - include this directive if you want your moon to have no animation. It will simply be a static crescent | ||
154 | moon, only taking up 6 bytes of space. If you do not include this directive, then the moon will have an animation. | ||
155 | The default is a moon with animation. | ||
156 | * `MOON_LINE` - defines the line that the moon sits on. Default is `4`. (see [reference](#reference)) | ||
157 | * `MOON_COLUMN` - defines the column that the moon sits at. Default is `4`. (see [reference](#reference)) | ||
158 | * `ANIMATE_MOON_EVERY_N_FRAMES` - only enabled when `STATIC_MOON` is disabled, this affects how often the moon changes phases. | ||
159 | Example: | ||
160 | ```c | ||
161 | #define STARRY_NIGHT_ANIM_FRAME_DURATION 30 | ||
162 | #ifndef STATIC_MOON | ||
163 | # define ANIMATE_MOON_EVERY_N_FRAMES 100 | ||
164 | #endif | ||
165 | ``` | ||
166 | would result in the moon changing phases every 3000ms, or every 3 seconds. | ||
167 | |||
168 | ## Ocean | ||
169 | |||
170 | ### Description | ||
171 | |||
172 | The 🌊 ocean animation is a full width animation of ocean waves, where the waves get rougher the faster you type. | ||
173 | You can configure the boundaries for each degree of _wave ferocity_ as well as how fast the ocean/waves move. | ||
174 | |||
175 | ### Flags | ||
176 | |||
177 | * `OCEAN_LINE` - where to render the ocean at. Defaults to `14`. (see [reference](#reference)) | ||
178 | * `OCEAN_ANIMATION_SPEED` - configures the number of frames you want to animate the ocean at. | ||
179 | Must be equal to or lower than `NUMBER_OF_FRAMES`. | ||
180 | Example: | ||
181 | ```c | ||
182 | #define NUMBER_OF_FRAMES 20 | ||
183 | #define OCEAN_ANIMATION_SPEED 5 | ||
184 | ``` | ||
185 | would result in the ocean animation happening every 4 frames. 20 would result in every frame, | ||
186 | 1 would be once every 20 frames. This essentially changes how fast the waves will move. | ||
187 | * `WAVE_CALM` - Defines the WPM at which the _Wave Ferocity_ kicks up. | ||
188 | At any WPM between `WAVE_CALM` and `WAVE_HEAVY_STORM`, the waves will be just tiny ripples. | ||
189 | * `WAVE_HEAVY_STORM` - Defines the WPM at which the _Wave Ferocity_ kicks up to medium. | ||
190 | At any WPM between `WAVE_HEAVY_STORM` and `WAVE_HURRICANE`, the waves will be medium sized waves. | ||
191 | * `WAVE_HURRICANE` - Defines the WPM at which the _Wave Ferocity_ kicks up to the last notch. | ||
192 | At any WPM above `WAVE_HURRICANE`, the waves will be torrential. | ||
193 | |||
194 | ## Shooting Stars | ||
195 | |||
196 | The 🌠 shooting star animation is a full screen animation that renders a meteor shower based on your typing speed. The | ||
197 | faster you type, the more shooting stars there are! | ||
198 | |||
199 | You can configure many parts of the shooting stars, from shower size, to speed, to length of each trail, to how spaced | ||
200 | out they are. | ||
201 | |||
202 | Note: Each frame of a shooting star is only 2 pixels in length. This is a design decision, and could probably be changed | ||
203 | with a decent amount of work, but was chosen for looks and memory constraints. | ||
204 | |||
205 | ### Flags | ||
206 | |||
207 | * `SHOOTING_STAR_DELAY` - Decides number of frames to delay, based on modulus, e.g. 12 means 0-11 frames of delay between each shooting star | ||
208 | * `SHOOTING_STAR_FRAMES` - how long each shooting star will be. A size of `16` will result in shooting stars that are 32 pixels long | ||
209 | * `MAX_NUMBER_OF_SHOOTING_STARS` - maximum number of shooting stars that can be on screen at the same time | ||
210 | * `SHOOTING_STAR_WPM_INCREMENT` - every n WPM increase, add an extra star, up to MAX_NUMBER_OF_SHOOTING_STARS | ||
211 | Example: an increment of 5 would result in 1 shooting star at 5-9wpm, 2 at 10-14, etc. | ||
212 | * `SHOOTING_STAR_ANIMATION_SPEED` - configures the number of frames you want to animate the shooting stars at. | ||
213 | Must be equal to or lower than `NUMBER_OF_FRAMES`. | ||
214 | Example: | ||
215 | ```c | ||
216 | #define NUMBER_OF_FRAMES 20 | ||
217 | #define SHOOTING_STAR_ANIMATION_SPEED 5 | ||
218 | ``` | ||
219 | would result in the shooting star animation happening every 4 frames. 20 would result in every frame, | ||
220 | 1 would be once every 20 frames. This essentially changes how fast the stars move through the sky. | ||
221 | |||
222 | |||
223 | ## Island | ||
224 | |||
225 | The 🏝 island animation is a 32w x 16h animation of a small island with a single palm tree blowing in the wind. The faster | ||
226 | you type the harder the palm tree blows in the wind! | ||
227 | |||
228 | Since this animation has significant black space to the left side of the tree, certain design decisions were made to allow the | ||
229 | shooting stars to still show up in the sky there. This animation should work on any size screen >=32 pixels wide, and you | ||
230 | can place it anywhere on the screen, but above the ocean is recommended. | ||
231 | |||
232 | ### Flags | ||
233 | |||
234 | * `ISLAND_LINE` - where to render the island at. Defaults to `12`. The island is 2 lines tall. (see [reference](#reference)) | ||
235 | * `ISLAND_COLUMN` - where to render the island at. Defaults to `0`. The island is 32 pixels wide. (see [reference](#reference)) | ||
236 | * `ISLAND_CALM` - Defines the WPM at which the _Storm Ferocity_ kicks up. | ||
237 | At any WPM between `ISLAND_CALM` and `ISLAND_HEAVY_STORM`, the palm tree will just calmly blow in the wind. | ||
238 | * `ISLAND_HEAVY_STORM` - Defines the WPM at which the _Storm Ferocity_ kicks up. | ||
239 | At any WPM between `ISLAND_HEAVY_STORM` and `ISLAND_HURRICANE`, the palm tree will be blowing hard in the wind | ||
240 | * `ISLAND_HURRICANE` - Defines the WPM at which the _Storm Ferocity_ kicks up. | ||
241 | At any WPM above `ISLAND_HURRICANE`, the palm tree will almost be torn from its roots! | ||
242 | |||
243 | |||
244 | # Reference | ||
245 | |||
246 | Any reference to `_LINE` or `COLUMN` refers to setting a cursor position using `oled_set_cursor()`, which uses | ||
247 | `OLED_FONT_WIDTH` and `OLED_FONT_HEIGHT` internally. | ||
248 | This will be the top-leftmost pixel of the image, so `_LINE 1` would start at the 9th pixel down and `_COLUMN 1` | ||
249 | would be the 7th pixel to the right, starting from the topleftmost pixel on the screen. | ||
250 | |||
251 | This code has been untested with different font heights/widths, so you might have to adjust a bit to make it work if you | ||
252 | have modified those values. | ||
253 | |||
254 | # ToDo | ||
255 | |||
256 | - [ ] don't require `is_calm` as a keyboard event. Not sure if the code will work without it currently. | ||
257 | - [ ] make all the stars twinkle brightly based on keypresses rather than timed. Not just a movement twinkle, but a larger | ||
258 | 'full' twinkle, where the star actually gets bigger. This will be quite difficult, thus is left out of the v1. | ||
diff --git a/users/snowe/rules.mk b/users/snowe/rules.mk new file mode 100644 index 000000000..a6e152c1c --- /dev/null +++ b/users/snowe/rules.mk | |||
@@ -0,0 +1,27 @@ | |||
1 | |||
2 | |||
3 | ifeq ($(strip $(OLED_DRIVER_ENABLE)), yes) | ||
4 | SRC += oled_setup.c | ||
5 | |||
6 | ifdef OCEAN_DREAM_ENABLE | ||
7 | ifeq ($(strip $(OCEAN_DREAM_ENABLE)), yes) | ||
8 | SRC += ocean_dream.c | ||
9 | OPT_DEFS += -DOCEAN_DREAM_ENABLE | ||
10 | endif | ||
11 | endif | ||
12 | ifndef OCEAN_DREAM_ENABLE | ||
13 | SRC += ocean_dream.c | ||
14 | OPT_DEFS += -DOCEAN_DREAM_ENABLE | ||
15 | endif | ||
16 | |||
17 | ifdef LUNA_ENABLE | ||
18 | ifeq ($(strip $(LUNA_ENABLE)), yes) | ||
19 | SRC += luna.c | ||
20 | OPT_DEFS += -DLUNA_ENABLE | ||
21 | endif | ||
22 | endif | ||
23 | ifndef LUNA_ENABLE | ||
24 | SRC += luna.c | ||
25 | OPT_DEFS += -DLUNA_ENABLE | ||
26 | endif | ||
27 | endif | ||
diff --git a/users/snowe/snowe.h b/users/snowe/snowe.h new file mode 100644 index 000000000..4453b2646 --- /dev/null +++ b/users/snowe/snowe.h | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | Copyright 2021 Tyler Thrailkill <@snowe/@snowe2010> | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | |||
19 | #pragma once | ||
20 | #include QMK_KEYBOARD_H | ||
21 | |||
22 | #ifndef QMK_FIRMWARE_SNOWE_H | ||
23 | # define QMK_FIRMWARE_SNOWE_H ; | ||
24 | #endif // QMK_FIRMWARE_SNOWE_H | ||
25 | |||
26 | #include "wrappers.h" | ||
27 | #include "keycode_aliases.h" | ||
28 | |||
29 | #define IGNORE_MOD_TAP_INTERRUPT | ||
30 | #undef PERMISSIVE_HOLD | ||
31 | |||
32 | //#if defined(RGBLIGHT_ENABLE) | ||
33 | //# include "rgb_stuff.h" | ||
34 | //#endif | ||
35 | //#if defined(RGB_MATRIX_ENABLE) | ||
36 | //# include "rgb_matrix_stuff.h" | ||
37 | //#endif | ||
38 | #ifdef OLED_DRIVER_ENABLE | ||
39 | # include "oled_setup.h" | ||
40 | #endif | ||
41 | |||
42 | |||
43 | enum layers { _MAIN, _LOWER, _UPPER, _ADJUST }; | ||
diff --git a/users/snowe/wrappers.h b/users/snowe/wrappers.h new file mode 100644 index 000000000..485f8de54 --- /dev/null +++ b/users/snowe/wrappers.h | |||
@@ -0,0 +1,92 @@ | |||
1 | /* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com> | ||
2 | * 2021 Tyler Thrailkill (@snowe/@snowe2010) <tyler.b.thrailkill@gmail.com> | ||
3 | * | ||
4 | * This program is free software: you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation, either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #pragma once | ||
19 | #include "snowe.h" | ||
20 | |||
21 | /* | ||
22 | Since our quirky block definitions are basically a list of comma separated | ||
23 | arguments, we need a wrapper in order for these definitions to be | ||
24 | expanded before being used as arguments to the LAYOUT_xxx macro. | ||
25 | */ | ||
26 | #if (!defined(LAYOUT) && defined(KEYMAP)) | ||
27 | # define LAYOUT KEYMAP | ||
28 | #endif | ||
29 | |||
30 | //#define LAYOUT_ergodox_wrapper(...) LAYOUT_ergodox(__VA_ARGS__) | ||
31 | //#define LAYOUT_ergodox_pretty_wrapper(...) LAYOUT_ergodox_pretty(__VA_ARGS__) | ||
32 | #define KEYMAP_wrapper(...) LAYOUT(__VA_ARGS__) | ||
33 | #define LAYOUT_wrapper(...) LAYOUT(__VA_ARGS__) | ||
34 | //#define LAYOUT_ortho_4x12_wrapper(...) LAYOUT_ortho_4x12(__VA_ARGS__) | ||
35 | //#define LAYOUT_ortho_5x12_wrapper(...) LAYOUT_ortho_5x12(__VA_ARGS__) | ||
36 | //#define LAYOUT_gergo_wrapper(...) LAYOUT_gergo(__VA_ARGS__) | ||
37 | |||
38 | /* | ||
39 | Blocks for each of the four major keyboard layouts | ||
40 | Organized so we can quickly adapt and modify all of them | ||
41 | at once, rather than for each keyboard, one at a time. | ||
42 | And this allows for much cleaner blocks in the keymaps. | ||
43 | For instance Tap/Hold for Control on all of the layouts | ||
44 | |||
45 | NOTE: These are all the same length. If you do a search/replace | ||
46 | then you need to add/remove underscores to keep the | ||
47 | lengths consistent. | ||
48 | */ | ||
49 | |||
50 | #define _________________QWERTY_L1_________________ KC_Q, KC_W, KC_E, KC_R, KC_T | ||
51 | #define _________________QWERTY_L2_________________ KC_A, KC_S, KC_D, KC_F, KC_G | ||
52 | #define _________________QWERTY_L3_________________ KC_Z, KC_X, KC_C, KC_V, KC_B | ||
53 | |||
54 | #define _________________QWERTY_R1_________________ KC_Y, KC_U, KC_I, KC_O, KC_P | ||
55 | #define _________________QWERTY_R2_________________ KC_H, KC_J, KC_K, KC_L, KC_SCLN | ||
56 | #define _________________QWERTY_R3_________________ KC_N, KC_M, KC_COMM, KC_DOT, KC_SLASH | ||
57 | |||
58 | |||
59 | #define ________________NUMBER_LEFT________________ KC_1, KC_2, KC_3, KC_4, KC_5 | ||
60 | #define ________________NUMBER_RIGHT_______________ KC_6, KC_7, KC_8, KC_9, KC_0 | ||
61 | //#define ________________NUMBER_RIGHT_______________ KC_6, KC_7, TD(TD_8_UP), KC_9, KC_0 | ||
62 | #define _________________FUNC_LEFT_________________ KC_F1, KC_F2, KC_F3, KC_F4, KC_F5 | ||
63 | #define _________________FUNC_RIGHT________________ KC_F6, KC_F7, KC_F8, KC_F9, KC_F10 | ||
64 | |||
65 | #define ___________________BLANK___________________ _______, _______, _______, _______, _______ | ||
66 | |||
67 | |||
68 | #define _________________LOWER_L1__________________ KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC | ||
69 | #define _________________LOWER_L2__________________ _________________FUNC_LEFT_________________ | ||
70 | #define _________________LOWER_L3__________________ _________________FUNC_RIGHT________________ | ||
71 | |||
72 | #define _________________LOWER_R1__________________ KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN | ||
73 | #define _________________LOWER_R2__________________ _______, KC_UNDS, KC_PLUS, KC_LCBR, KC_RCBR | ||
74 | #define _________________LOWER_R3__________________ _______, KC_LEFT, KC_UP , KC_DOWN, KC_RGHT | ||
75 | |||
76 | |||
77 | #define _________________RAISE_L1__________________ ________________NUMBER_LEFT________________ | ||
78 | #define _________________RAISE_L2__________________ _______, KC_MINS, KC_EQL, KC_LBRC, KC_RBRC | ||
79 | #define _________________RAISE_L3__________________ ___________________BLANK___________________ | ||
80 | |||
81 | #define _________________RAISE_R1__________________ ________________NUMBER_RIGHT_______________ | ||
82 | #define _________________RAISE_R2__________________ KC_LEFT, KC_DOWN, KC_UP, KC_RGHT, _______ | ||
83 | #define _________________RAISE_R3__________________ _______, KC_HOME, KC_PGDN, KC_PGUP, KC_END | ||
84 | |||
85 | |||
86 | |||
87 | #define _________________ADJUST_L1_________________ RGB_MOD, RGB_HUI, RGB_SAI, RGB_VAI, RGB_TOG | ||
88 | #define _________________ADJUST_L2_________________ MU_TOG , CK_TOGG, AU_ON, AU_OFF, AG_NORM | ||
89 | #define _________________ADJUST_L3_________________ RGB_RMOD,RGB_HUD,RGB_SAD, RGB_VAD, _______ | ||
90 | #define _________________ADJUST_R1_________________ _______, _______, _______, _______, _______ | ||
91 | #define _________________ADJUST_R2_________________ RESET, CG_TOGG, _______, _______, _______ | ||
92 | #define _________________ADJUST_R3_________________ _______, KC_MNXT, KC_VOLU, KC_VOLD, KC_MPLY | ||