1
5
6 Function logString(PointerToCharacter str) Which Returns Nothing Is External;
8 Function logInteger(Integer32 int) Which Returns Nothing Is External;
9
10 Character output[23 * 80];
12 PointerToCharacter colors[23 * 80];
16 Function getAddressOfOutput() Which Returns PointerToCharacter
17 Does { Return AddressOf(output[0]); }
23 EndFunction;
24
25 Function getAddressOfColors() Which Returns PointerToPointerToCharacter Does {
26 Return AddressOf(colors[0]);
27 }
28 EndFunction;
29
30 Decimal32 PRECISION : = 512; Integer32 USE_WEBASSEMBLY_SQRT_INSTRUCTION
44 : = 1; Function ln(Decimal32 x) Which Returns Decimal32 Does {
50 Decimal32 sum : = 0, epsilon : = (x - 1) / (5 * PRECISION), i : = 1;
52 While(epsilon > 0 and i < x) or (epsilon < 0 and i > x) Loop {
53 sum += epsilon / i;
54 i += epsilon;
55 }
56 EndWhile; Return sum;
62 }
63 EndFunction;
64
65 Function exp(Decimal32 x) Which Returns Decimal32 Does {
66 Decimal32 i : = 0, y : = 1, epsilon : = x / PRECISION;
68 While(epsilon > 0 and i < x) or (epsilon < 0 and i > x) Loop {
69 y += epsilon * y;
70 i += epsilon;
71 }
72 EndWhile;
73 Return y;
74 }
75 EndFunction;
76
77 Function sqrt(Decimal32 x) Which Returns Decimal32 Does {
78 If USE_WEBASSEMBLY_SQRT_INSTRUCTION Then {
79 Return asm_f32(
80 R"multiline((f32.sqrt
81 (f32.load
82 %x ;;The compiler will replace "%x" with assembly code representing a pointer to the variable "x".
83 )
84 ))multiline"); }
88 EndIf;
89 Decimal32 max
91 : = 80 * 80 + 24 * 24, min : = 0, i : = (min + max) / 2;
95 If(max * max < x) Then {
97 Return exp(
98 ln(x) /
99 2); }
101 EndIf;
102 While((max - min) > 1 / PRECISION) Loop {
103 If(i * i > x) Then {
104 max
111 : = i;
112 }
113 Else {
114 min:
115 = i;
116 }
117 EndIf;
118 i:
119 = (max + min) / 2;
120 }
121 EndWhile;
122 Return i;
123 }
124 EndFunction;
125
126 Function fmod(Decimal32 a, Decimal32 b) Which Returns Decimal32 Does {
127 Return(a - b * Integer32(a / b));
128 }
129 EndFunction;
130
131 Decimal32 oneRadianInDegrees
133 : = 180 / pi;
140 Function arctan(Decimal32 x) Which Returns Decimal32 Does {
141 Decimal32 sum : = 0, epsilon : = x / PRECISION, i : = 0;
143 While(i < x) Loop {
144 sum += epsilon / (1 + i * i);
145 i += epsilon;
146 }
147 EndWhile;
148 Return(sum * oneRadianInDegrees);
149 }
150 EndFunction;
151
152 Function atan2(Decimal32 y, Decimal32 x) Which Returns Decimal32 Does {
153 If(y = 0) Then {
154 If(x < 0) Then { Return 180; }
155 Else { Return 0; }
156 EndIf;
157 }
158 ElseIf(x = 0) Then {
159 If y < 0 Then { Return 270; }
160 Else { Return 90; }
161 EndIf;
162 }
163 Else {
164 If(x > 0 and y > 0) Then { Return arctan(y / x); }
165 ElseIf(x < 0 and y > 0) Then { Return 90 + arctan(-x / y); }
166 ElseIf(x < 0 and y < 0) Then { Return 180 + arctan(y / x); }
167 Else { Return 270 + arctan(-x / y); }
168 EndIf;
169 }
170 EndIf;
171 }
172 EndFunction;
173
174 Function cos(Decimal32 degrees)
175 Which Returns Decimal32 Is Declared;
178 Decimal32 sineMemoisation[91];
179
180 Function sin(Decimal32 degrees) Which Returns Decimal32 Does {
181 If(degrees < 0) Then { Return - sin(-degrees); }
182 EndIf;
183 If degrees > 90 Then { Return cos(degrees - 90); }
184 EndIf;
185 If not(sineMemoisation[asm_f32("(f32.nearest (f32.load %degrees))")] = 0)
186 Then { Return sineMemoisation[asm_f32("(f32.nearest (f32.load %degrees))")];
192 }
193 EndIf;
194
207 Decimal32 radians : = degrees / oneRadianInDegrees, tmpsin : = 0,
208 tmpcos : = 1, epsilon : = radians / PRECISION, i : = 0;
209 While((epsilon > 0 and i < radians) or (epsilon < 0 and i > radians)) Loop {
210 tmpsin += epsilon * tmpcos;
211 tmpcos -= epsilon * tmpsin;
212 i += epsilon;
213 }
214 EndWhile;
215 Return sineMemoisation[asm_f32("(f32.nearest (f32.load %degrees))")]
216 : = tmpsin;
217 }
218 EndFunction;
219
220 Function arcsin(Decimal32 x) Which Returns Decimal32 Does {
221 Return arctan(x / sqrt(1 - x * x)); }
223 EndFunction;
224
225 Function arccos(Decimal32 x) Which Returns Decimal32 Does {
226 Return 90 - arcsin(x); }
229 EndFunction;
230
231 Function cos(Decimal32 degrees) Which Returns Decimal32 Does {
232 Return sin(90 - degrees); }
235 EndFunction;
236
237 Function tan(Decimal32 degrees) Which Returns Decimal32 Does {
238 Return sin(degrees) / cos(degrees); }
240 EndFunction;
241
242 Function abs(Decimal32 x) Which Returns Decimal32 Does {
243 Return x < 0 ? -x : x;
244 }
245 EndFunction;
246
247 Function strlen(PointerToCharacter ptr) Which Returns Integer32 Does {
250 Return ValueAt(ptr) = 0 ? 0 : 1 + strlen(ptr + 1);
251 }
252 EndFunction;
253
254 Function strcat(PointerToCharacter first,
255 PointerToCharacter second) Which Returns Nothing Does {
256 first += strlen(first);
257 While ValueAt(second) Loop {
258 ValueAt(first) : = ValueAt(second);
259 first += 1;
260 second += 1;
261 }
262 EndWhile;
263 ValueAt(first) : = 0;
264 }
265 EndFunction;
266
267 Function updateClockToTime(Integer32 hour, Integer32 minute,
270 Integer32 second) Which Returns Nothing Does {
271 If((abs(atan2(sin(5), cos(5)) - 5) > 1) or
272 (abs(atan2(sin(95), cos(95)) - 95) > 1) or
273 (abs(atan2(sin(185), cos(185)) - 185) > 1) or
274 (abs(atan2(sin(275), cos(275)) - 275) > 1) or
275 (abs(arcsin(sin(60)) - 60) > 1) or (abs(arccos(cos(60)) - 60) > 1)) Then {
276 logString("\"atan2\" function seems not to work!\n");
277 logString("atan2(sin(5), cos(5))=");
278 logInteger(atan2(sin(5), cos(5)));
279 logString("\natan2(sin(95),cos(95))=");
280 logInteger(atan2(sin(95), cos(95)));
281 logString("\natan2(sin(185),cos(185))=");
282 logInteger(atan2(sin(185), cos(185)));
283 logString("\natan2(sin(275),cos(275))=");
284 logInteger(atan2(sin(275), cos(275)));
285 logString("\n\n\n");
286 }
287 EndIf;
288 Integer32 windowWidth : = 80, windowHeight : = 23, i : = 0;
289 PointerToCharacter lightGrayColor : = "#EEEEEE",
290 lightGreenColor : = "#CCFFCC";
291 While(i < windowWidth * windowHeight) Loop { If mod(i, windowWidth) = windowWidth - 1 Then { output[i] : = '\n'; }
294 Else { output[i] : = ' '; }
295 EndIf;
296 colors[i] : = lightGrayColor;
297 i += 1;
298 }
299 EndWhile;
300 Integer32 centerX : = windowWidth / 2, centerY : = windowHeight / 2,
301 clockRadius : = (centerX < centerY) ? centerX - 1
302 : centerY - 1;
303 i:
304 = 0;
305 While(i < windowWidth * windowHeight) Loop { Integer32 y : = i / windowWidth, x : = mod(i, windowWidth);
308 Decimal32 distance : = sqrt((x - centerX) * (x - centerX) +
309 (y - centerY) * (y - centerY)); If abs(distance - clockRadius) < 3. / 4 Then {
312 output[i] : = '*';
313 colors[i] : = lightGreenColor;
314 }
315 EndIf;
316 i += 1;
317 }
318 EndWhile;
319 PointerToCharacter redColor : = "#FFAAAA";
320 output[(centerY - clockRadius + 1) * windowWidth + centerX] : = '1';
322 output[(centerY - clockRadius + 1) * windowWidth + centerX + 1] : = '2';
323 colors[(centerY - clockRadius + 1) * windowWidth + centerX]
324 : = colors[(centerY - clockRadius + 1) * windowWidth + centerX + 1]
325 : = redColor;
326 output[(centerY + clockRadius - 1) * windowWidth + centerX] : = '6';
328 colors[(centerY + clockRadius - 1) * windowWidth + centerX] : = redColor;
329 output[centerY * windowWidth + centerX + clockRadius - 1] : = '3';
331 colors[centerY * windowWidth + centerX + clockRadius - 1] : = redColor;
332 output[centerY * windowWidth + centerX - clockRadius + 1] : = '9';
334 colors[centerY * windowWidth + centerX - clockRadius + 1] : = redColor;
335 Integer32 y : = centerY - (clockRadius - 1) * cos(360. / 12);
337 output[y * windowWidth + centerX + sin(360. / 12) * (clockRadius - 1)]
338 : = '1';
339 colors[y * windowWidth + centerX + sin(360. / 12) * (clockRadius - 1)]
340 : = redColor;
341 y:
343 = centerY - (clockRadius - 1.5) * cos(2 * 360. / 12);
344 output[y * windowWidth + centerX + sin(2 * 360. / 12) * (clockRadius - 1.5)]
345 : = '2';
346 colors[y * windowWidth + centerX + sin(2 * 360. / 12) * (clockRadius - 1.5)]
347 : = redColor;
348 y:
350 = centerY - (clockRadius - 1) * cos(4 * 360. / 12);
351 output[y * windowWidth + centerX + sin(4 * 360. / 12) * (clockRadius - 1) + 1]
352 : = '4';
353 colors[y * windowWidth + centerX + sin(4 * 360. / 12) * (clockRadius - 1) + 1]
354 : = redColor;
355 y:
357 = centerY - (clockRadius - 1) * cos(5 * 360. / 12);
358 output[y * windowWidth + centerX + sin(5 * 360. / 12) * (clockRadius - 1) + 1]
359 : = '5';
360 colors[y * windowWidth + centerX + sin(5 * 360. / 12) * (clockRadius - 1) + 1]
361 : = redColor;
362 y:
364 = centerY - (clockRadius - 1) * cos(7 * 360. / 12);
365 output[y * windowWidth + centerX + sin(7 * 360. / 12) * (clockRadius - 1)]
366 : = '7';
367 colors[y * windowWidth + centerX + sin(7 * 360. / 12) * (clockRadius - 1)]
368 : = redColor;
369 y:
371 = centerY - (clockRadius - 1) * cos(8 * 360. / 12);
372 output[y * windowWidth + centerX + sin(8 * 360. / 12) * (clockRadius - 1)]
373 : = '8';
374 colors[y * windowWidth + centerX + sin(8 * 360. / 12) * (clockRadius - 1)]
375 : = redColor;
376 y:
378 = centerY - (clockRadius - 1.5) * cos(10 * 360. / 12);
379 output[y * windowWidth + centerX + sin(10 * 360. / 12) * (clockRadius - 1.5) +
380 1] : = '1';
381 output[y * windowWidth + centerX + sin(10 * 360. / 12) * (clockRadius - 1.5) +
382 2] : = '0';
383 colors[y * windowWidth + centerX + sin(10 * 360. / 12) * (clockRadius - 1.5) +
384 1] : = colors[y * windowWidth + centerX +
385 sin(10 * 360. / 12) * (clockRadius - 1.5) + 2]
386 : = redColor;
387 y:
389 = centerY - (clockRadius - 1.5) * cos(11 * 360. / 12);
390 output[y * windowWidth + centerX + sin(11 * 360. / 12) * (clockRadius - 1.5) +
391 1] : = output[y * windowWidth + centerX +
392 sin(11 * 360. / 12) * (clockRadius - 1.5) + 2] : = '1';
393 colors[y * windowWidth + centerX + sin(11 * 360. / 12) * (clockRadius - 1.5) +
394 1] : = colors[y * windowWidth + centerX +
395 sin(11 * 360. / 12) * (clockRadius - 1.5) + 2]
396 : = redColor;
397 Integer32 j : = 0;
398 Decimal32 angle;
399 PointerToCharacter blueColor : = "#AAAAFF", yellowColor : = "#FFFFAA";
400 While j < 3 Loop {
401 PointerToCharacter currentColor;
402 If j = 0 Then {
403 angle:
404 = fmod(hour + minute / 60., 12) * (360. / 12);
405 currentColor:
406 = redColor;
407 }
408 ElseIf j = 1 Then {
409 angle:
410 = minute * (360. / 60);
411 currentColor:
412 = yellowColor;
413 }
414 Else {
415 angle:
416 = second * (360 / 60);
417 currentColor:
418 = blueColor;
419 }
420 EndIf;
421 Decimal32 endOfTheHandX
422 : = centerX +
423 sin(angle) * clockRadius / (j = 0 ? 2. : j = 1 ? 3. / 2 : 4. / 3),
424 endOfTheHandY : = centerY - cos(angle) * clockRadius /
425 (j = 0 ? 2. : j = 1 ? 3. / 2 : 4. / 3),
426 coefficientOfTheDirection
427 : = (endOfTheHandY - centerY) /
428 (abs(endOfTheHandX - centerX) = 0 ?
429 1. / 100
432 : endOfTheHandX - centerX);
433 logString("Drawing line between (");
434 logInteger(centerX);
435 logString(",");
436 logInteger(centerY);
437 logString(") and (");
438 logInteger(endOfTheHandX);
439 logString(",");
440 logInteger(endOfTheHandY);
441 logString(").\n");
442 i:
443 = 0;
444 While(i < windowWidth * windowHeight) Loop {
445 Decimal32 lowerBoundX
446 : = endOfTheHandX < centerX ? endOfTheHandX : Decimal32(centerX),
447 upperBoundX : = endOfTheHandX > centerX ? endOfTheHandX
448 : Decimal32(centerX),
449 lowerBoundY : = endOfTheHandY < centerY ? endOfTheHandY : centerY,
450 upperBoundY : = endOfTheHandY > centerY ? endOfTheHandY : centerY;
451 y:
452 = i / windowWidth;
453 Integer32 x : = mod(i, windowWidth), isXWithinBounds;
454 isXWithinBounds:
455 = (x > lowerBoundX or x = lowerBoundX) and
456 (x < upperBoundX or x = upperBoundX);
457 Integer32 isYWithinBounds;
458 isYWithinBounds:
459 = (y > lowerBoundY or y = lowerBoundY) and
460 (y < upperBoundY or y = upperBoundY);
461 If isXWithinBounds and isYWithinBounds Then {
462 Decimal32 expectedX, expectedY;
463 expectedY:
464 = (x - centerX) * coefficientOfTheDirection + centerY;
465 expectedX:
466 = (y - centerY) * (1 / coefficientOfTheDirection) + centerX;
467 If coefficientOfTheDirection = 1. / 0 Then {
468 expectedY:
469 = 1000; }
471 EndIf;
472 If coefficientOfTheDirection = 0 Then {
473 expectedX:
474 = 1000; }
476 EndIf;
477 logString("The point (");
478 logInteger(x);
479 logString(",");
480 logInteger(y);
481 logString(") is within bounds, expectedY is ");
482 logInteger(expectedY);
483 logString(" and expectedX is ");
484 logInteger(expectedX);
485 logString(".\n");
486 Character currentSign : = j = 0 ? 'h' : j = 1 ? 'm' : 's';
487 If((abs(upperBoundX - lowerBoundX) < 1 + 1 / PRECISION or
488 abs(upperBoundY - lowerBoundY) < 1 + 1 / PRECISION) and
489 output[i] = ' ') Then {
490 output[i] : = currentSign;
491 colors[i] : = currentColor;
492 }
493 EndIf;
494 If(abs(expectedX - x) < 3. / 4 or abs(expectedY - y) < 3. / 4) and
495 output[i] = ' ' Then {
496 output[i] : = currentSign;
497 colors[i] : = currentColor;
498 }
499 EndIf;
500 }
501 EndIf;
502 i += 1;
503 }
504 EndWhile;
505 j += 1;
506 }
507 EndWhile;
508 PointerToCharacter darkGreenColor : = "#AAFFAA";
510 i:
511 = 0;
512 While(i < windowWidth * windowHeight) Loop {
513 y:
514 = i / windowWidth;
515 Integer32 x : = mod(i, windowWidth);
516 If abs(windowHeight - 2 * ln(1 + abs((x - centerX) / 2.)) -
517 y)<1 - abs(x - centerX) / (centerX * 95. / 112) and x> 1. /
518 2 * centerX and x <
519 3. / 2 * centerX and output[i] =
520 ' ' Then { output[i] : = 'x';
523 colors[i] : = darkGreenColor;
524 }
525 EndIf;
526 i += 1;
527 }
528 EndWhile;
529 j:
532 = 0;
533 While j < 3 Loop {
534 i:
535 = windowWidth * (windowHeight - 1); While(i < windowWidth * windowHeight) Loop {
538 If j < 2 and (output[i - windowWidth] =
539 'x' and (output[i + 1] = 'x' or output[i - 1] = 'x'))
540 Then {
541 output[i] : = 'x';
542 colors[i] : = darkGreenColor;
543 }
544 ElseIf j =
545 2 and (output[i + 1] = ' ' and output[i - windowWidth] = 'x') Then {
546 output[i] : = ' ';
547 }
548 EndIf;
549 i += 1;
550 }
551 EndWhile;
552 j += 1;
553 }
554 EndWhile;
555 output[windowWidth * windowHeight - 2] : = '0' + mod(second, 10);
557 output[windowWidth * windowHeight - 3] : = '0' + second / 10;
558 colors[windowWidth * windowHeight - 2]
559 : = colors[windowWidth * windowHeight - 3] : = blueColor;
560 output[windowWidth * windowHeight - 4] : = ':';
561 output[windowWidth * windowHeight - 5] : = '0' + mod(minute, 10);
562 output[windowWidth * windowHeight - 6] : = '0' + minute / 10;
563 colors[windowWidth * windowHeight - 5]
564 : = colors[windowWidth * windowHeight - 6] : = yellowColor;
565 output[windowWidth * windowHeight - 7] : = ':';
566 output[windowWidth * windowHeight - 8] : = '0' + mod(hour, 10);
567 output[windowWidth * windowHeight - 9] : = '0' + hour / 10;
568 colors[windowWidth * windowHeight - 8]
569 : = colors[windowWidth * windowHeight - 9] : = redColor;
570 Character signature[100] : = {0};
572 PointerToCharacter signature : = AddressOf(signature[0]);
573 logString("Empty signature has length of: ");
576 logInteger(strlen(signature));
577 logString("\n");
578 strcat(signature, " Analog Clock for WebAssembly\n");
579 logString("The first row of the signature has length of: ");
580 logInteger(strlen(signature));
581 logString("\n");
582 strcat(signature, " Made in AEC by\n");
583 logString("The first two rows of signature have length: ");
584 logInteger(strlen(signature));
585 logString("\n");
586 strcat(signature, " Teo Samarzija");
587 logString("Signature has length of: ");
588 logInteger(strlen(signature));
589 logString(" \n\n"); i:
591 = windowWidth * (windowHeight - 3);
592 j:
593 = 0;
594 PointerToCharacter modraColor : = "#AAFFFF"; While not(signature[j] = 0) Loop {
599 If signature[j] = '\n' Then {
600 i:
601 = (i / windowWidth + 1) * windowWidth;
602 }
603 ElseIf not(signature[j] = 0) Then {
604 output[i] : = signature[j];
605 colors[i] : = modraColor;
606 i += 1;
607 }
608 Else { output[i] : = ' '; }
609 EndIf;
610 j += 1;
611 }
612 EndWhile;
613 }
614 EndFunction;
615