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
208 Decimal32 radians : = degrees / oneRadianInDegrees, tmpsin : = 0,
209 tmpcos : = 1, epsilon : = radians / PRECISION, i : = 0;
210 While((epsilon > 0 and i < radians) or (epsilon < 0 and i > radians)) Loop {
211 tmpsin += epsilon * tmpcos;
212 tmpcos -= epsilon * tmpsin;
213 i += epsilon;
214 }
215 EndWhile;
216 Return sineMemoisation[asm_f32("(f32.nearest (f32.load %degrees))")]
217 : = tmpsin;
218 }
219 EndFunction;
220
221 Function arcsin(Decimal32 x) Which Returns Decimal32 Does {
222 Return arctan(x / sqrt(1 - x * x)); }
224 EndFunction;
225
226 Function arccos(Decimal32 x) Which Returns Decimal32 Does {
227 Return 90 - arcsin(x); }
230 EndFunction;
231
232 Function cos(Decimal32 degrees) Which Returns Decimal32 Does {
233 Return sin(90 - degrees); }
236 EndFunction;
237
238 Function tan(Decimal32 degrees) Which Returns Decimal32 Does {
239 Return sin(degrees) / cos(degrees); }
241 EndFunction;
242
243 Function abs(Decimal32 x) Which Returns Decimal32 Does {
244 Return x < 0 ? -x : x;
245 }
246 EndFunction;
247
248 Function strlen(PointerToCharacter ptr) Which Returns Integer32 Does {
251 Return ValueAt(ptr) = 0 ? 0 : 1 + strlen(ptr + 1);
252 }
253 EndFunction;
254
255 Function strcat(PointerToCharacter first,
256 PointerToCharacter second) Which Returns Nothing Does {
257 first += strlen(first);
258 While ValueAt(second) Loop {
259 ValueAt(first) : = ValueAt(second);
260 first += 1;
261 second += 1;
262 }
263 EndWhile;
264 ValueAt(first) : = 0;
265 }
266 EndFunction;
267
268 Function updateClockToTime(Integer32 hour, Integer32 minute,
271 Integer32 second) Which Returns Nothing Does {
272 If((abs(atan2(sin(5), cos(5)) - 5) > 1) or
273 (abs(atan2(sin(95), cos(95)) - 95) > 1) or
274 (abs(atan2(sin(185), cos(185)) - 185) > 1) or
275 (abs(atan2(sin(275), cos(275)) - 275) > 1) or
276 (abs(arcsin(sin(60)) - 60) > 1) or (abs(arccos(cos(60)) - 60) > 1)) Then {
277 logString("The cyclometric functions seem not to work!\n");
278 logString("atan2(sin(5), cos(5))=");
279 logInteger(atan2(sin(5), cos(5)));
280 logString("\natan2(sin(95),cos(95))=");
281 logInteger(atan2(sin(95), cos(95)));
282 logString("\natan2(sin(185),cos(185))=");
283 logInteger(atan2(sin(185), cos(185)));
284 logString("\natan2(sin(275),cos(275))=");
285 logInteger(atan2(sin(275), cos(275)));
286 logString("\narcsin(sin(60))=");
287 logInteger(arcsin(sin(60)));
288 logString("\narccos(cos(60))=");
289 logInteger(arccos(cos(60)));
290 logString("\n\n");
291 }
292 EndIf;
293 Integer32 windowWidth : = 80, windowHeight : = 23, i : = 0;
294 PointerToCharacter lightGrayColor : = "#EEEEEE",
295 lightGreenColor : = "#CCFFCC";
296 While(i < windowWidth * windowHeight) Loop { If mod(i, windowWidth) = windowWidth - 1 Then { output[i] : = '\n'; }
299 Else { output[i] : = ' '; }
300 EndIf;
301 colors[i] : = lightGrayColor;
302 i += 1;
303 }
304 EndWhile;
305 Integer32 centerX : = windowWidth / 2, centerY : = windowHeight / 2,
306 clockRadius : = (centerX < centerY) ? centerX - 1
307 : centerY - 1;
308 i:
309 = 0;
310 While(i < windowWidth * windowHeight) Loop { Integer32 y : = i / windowWidth, x : = mod(i, windowWidth);
313 Decimal32 distance : = sqrt((x - centerX) * (x - centerX) +
314 (y - centerY) * (y - centerY)); If abs(distance - clockRadius) < 3. / 4 Then {
317 output[i] : = '*';
318 colors[i] : = lightGreenColor;
319 }
320 EndIf;
321 i += 1;
322 }
323 EndWhile;
324 PointerToCharacter redColor : = "#FFAAAA";
325 output[(centerY - clockRadius + 1) * windowWidth + centerX] : = '1';
327 output[(centerY - clockRadius + 1) * windowWidth + centerX + 1] : = '2';
328 colors[(centerY - clockRadius + 1) * windowWidth + centerX]
329 : = colors[(centerY - clockRadius + 1) * windowWidth + centerX + 1]
330 : = redColor;
331 output[(centerY + clockRadius - 1) * windowWidth + centerX] : = '6';
333 colors[(centerY + clockRadius - 1) * windowWidth + centerX] : = redColor;
334 output[centerY * windowWidth + centerX + clockRadius - 1] : = '3';
336 colors[centerY * windowWidth + centerX + clockRadius - 1] : = redColor;
337 output[centerY * windowWidth + centerX - clockRadius + 1] : = '9';
339 colors[centerY * windowWidth + centerX - clockRadius + 1] : = redColor;
340 Integer32 y : = centerY - (clockRadius - 1) * cos(360. / 12);
342 output[y * windowWidth + centerX + sin(360. / 12) * (clockRadius - 1)]
343 : = '1';
344 colors[y * windowWidth + centerX + sin(360. / 12) * (clockRadius - 1)]
345 : = redColor;
346 y:
348 = centerY - (clockRadius - 1.5) * cos(2 * 360. / 12);
349 output[y * windowWidth + centerX + sin(2 * 360. / 12) * (clockRadius - 1.5)]
350 : = '2';
351 colors[y * windowWidth + centerX + sin(2 * 360. / 12) * (clockRadius - 1.5)]
352 : = redColor;
353 y:
355 = centerY - (clockRadius - 1) * cos(4 * 360. / 12);
356 output[y * windowWidth + centerX + sin(4 * 360. / 12) * (clockRadius - 1) + 1]
357 : = '4';
358 colors[y * windowWidth + centerX + sin(4 * 360. / 12) * (clockRadius - 1) + 1]
359 : = redColor;
360 y:
362 = centerY - (clockRadius - 1) * cos(5 * 360. / 12);
363 output[y * windowWidth + centerX + sin(5 * 360. / 12) * (clockRadius - 1) + 1]
364 : = '5';
365 colors[y * windowWidth + centerX + sin(5 * 360. / 12) * (clockRadius - 1) + 1]
366 : = redColor;
367 y:
369 = centerY - (clockRadius - 1) * cos(7 * 360. / 12);
370 output[y * windowWidth + centerX + sin(7 * 360. / 12) * (clockRadius - 1)]
371 : = '7';
372 colors[y * windowWidth + centerX + sin(7 * 360. / 12) * (clockRadius - 1)]
373 : = redColor;
374 y:
376 = centerY - (clockRadius - 1) * cos(8 * 360. / 12);
377 output[y * windowWidth + centerX + sin(8 * 360. / 12) * (clockRadius - 1)]
378 : = '8';
379 colors[y * windowWidth + centerX + sin(8 * 360. / 12) * (clockRadius - 1)]
380 : = redColor;
381 y:
383 = centerY - (clockRadius - 1.5) * cos(10 * 360. / 12);
384 output[y * windowWidth + centerX + sin(10 * 360. / 12) * (clockRadius - 1.5) +
385 1] : = '1';
386 output[y * windowWidth + centerX + sin(10 * 360. / 12) * (clockRadius - 1.5) +
387 2] : = '0';
388 colors[y * windowWidth + centerX + sin(10 * 360. / 12) * (clockRadius - 1.5) +
389 1] : = colors[y * windowWidth + centerX +
390 sin(10 * 360. / 12) * (clockRadius - 1.5) + 2]
391 : = redColor;
392 y:
394 = centerY - (clockRadius - 1.5) * cos(11 * 360. / 12);
395 output[y * windowWidth + centerX + sin(11 * 360. / 12) * (clockRadius - 1.5) +
396 1] : = output[y * windowWidth + centerX +
397 sin(11 * 360. / 12) * (clockRadius - 1.5) + 2] : = '1';
398 colors[y * windowWidth + centerX + sin(11 * 360. / 12) * (clockRadius - 1.5) +
399 1] : = colors[y * windowWidth + centerX +
400 sin(11 * 360. / 12) * (clockRadius - 1.5) + 2]
401 : = redColor;
402 Integer32 j : = 0;
403 Decimal32 angle;
404 PointerToCharacter blueColor : = "#AAAAFF", yellowColor : = "#FFFFAA";
405 While j < 3 Loop {
406 PointerToCharacter currentColor;
407 If j = 0 Then {
408 angle:
409 = fmod(hour + minute / 60., 12) * (360. / 12);
410 currentColor:
411 = redColor;
412 }
413 ElseIf j = 1 Then {
414 angle:
415 = minute * (360. / 60);
416 currentColor:
417 = yellowColor;
418 }
419 Else {
420 angle:
421 = second * (360 / 60);
422 currentColor:
423 = blueColor;
424 }
425 EndIf;
426 Decimal32 endOfTheHandX
427 : = centerX +
428 sin(angle) * clockRadius / (j = 0 ? 2. : j = 1 ? 3. / 2 : 4. / 3),
429 endOfTheHandY : = centerY - cos(angle) * clockRadius /
430 (j = 0 ? 2. : j = 1 ? 3. / 2 : 4. / 3),
431 coefficientOfTheDirection
432 : = (endOfTheHandY - centerY) /
433 (abs(endOfTheHandX - centerX) = 0 ?
434 1. / 100
437 : endOfTheHandX - centerX);
438 logString("Drawing line between (");
439 logInteger(centerX);
440 logString(",");
441 logInteger(centerY);
442 logString(") and (");
443 logInteger(endOfTheHandX);
444 logString(",");
445 logInteger(endOfTheHandY);
446 logString(").\n");
447 i:
448 = 0;
449 While(i < windowWidth * windowHeight) Loop {
450 Decimal32 lowerBoundX
451 : = endOfTheHandX < centerX ? endOfTheHandX : Decimal32(centerX),
452 upperBoundX : = endOfTheHandX > centerX ? endOfTheHandX
453 : Decimal32(centerX),
454 lowerBoundY : = endOfTheHandY < centerY ? endOfTheHandY : centerY,
455 upperBoundY : = endOfTheHandY > centerY ? endOfTheHandY : centerY;
456 y:
457 = i / windowWidth;
458 Integer32 x : = mod(i, windowWidth), isXWithinBounds;
459 isXWithinBounds:
460 = lowerBoundX <= x <= upperBoundX;
461 Integer32 isYWithinBounds;
462 isYWithinBounds:
463 = lowerBoundY <= y <= upperBoundY;
464 If isXWithinBounds and isYWithinBounds Then {
465 Decimal32 expectedX, expectedY;
466 expectedY:
467 = (x - centerX) * coefficientOfTheDirection + centerY;
468 expectedX:
469 = (y - centerY) * (1 / coefficientOfTheDirection) + centerX;
470 If coefficientOfTheDirection = 1. / 0 Then {
471 expectedY:
472 = 1000; }
474 EndIf;
475 If coefficientOfTheDirection = 0 Then {
476 expectedX:
477 = 1000; }
479 EndIf;
480 logString("The point (");
481 logInteger(x);
482 logString(",");
483 logInteger(y);
484 logString(") is within bounds, expectedY is ");
485 logInteger(expectedY);
486 logString(" and expectedX is ");
487 logInteger(expectedX);
488 logString(".\n");
489 Character currentSign : = j = 0 ? 'h' : j = 1 ? 'm' : 's';
490 If((abs(upperBoundX - lowerBoundX) < 1 + 1 / PRECISION or
491 abs(upperBoundY - lowerBoundY) < 1 + 1 / PRECISION) and
492 output[i] = ' ') Then {
493 output[i] : = currentSign;
494 colors[i] : = currentColor;
495 }
496 EndIf;
497 If(abs(expectedX - x) < 3. / 4 or abs(expectedY - y) < 3. / 4) and
498 output[i] = ' ' Then {
499 output[i] : = currentSign;
500 colors[i] : = currentColor;
501 }
502 EndIf;
503 }
504 EndIf;
505 i += 1;
506 }
507 EndWhile;
508 j += 1;
509 }
510 EndWhile;
511 PointerToCharacter darkGreenColor : = "#AAFFAA";
513 i:
514 = 0;
515 While(i < windowWidth * windowHeight) Loop {
516 y:
517 = i / windowWidth;
518 Integer32 x : = mod(i, windowWidth);
519 If abs(windowHeight - 2 * ln(1 + abs((x - centerX) / 2.)) -
520 y)<1 - abs(x - centerX) / (centerX * 95. / 112) and x> 1. /
521 2 * centerX and x <
522 3. / 2 * centerX and output[i] =
523 ' ' Then { output[i] : = 'x';
526 colors[i] : = darkGreenColor;
527 }
528 EndIf;
529 i += 1;
530 }
531 EndWhile;
532 j:
535 = 0;
536 While j < 3 Loop {
537 i:
538 = windowWidth * (windowHeight - 1); While(i < windowWidth * windowHeight) Loop {
541 If j < 2 and (output[i - windowWidth] =
542 'x' and (output[i + 1] = 'x' or output[i - 1] = 'x'))
543 Then {
544 output[i] : = 'x';
545 colors[i] : = darkGreenColor;
546 }
547 ElseIf j =
548 2 and (output[i + 1] = ' ' and output[i - windowWidth] = 'x') Then {
549 output[i] : = ' ';
550 }
551 EndIf;
552 i += 1;
553 }
554 EndWhile;
555 j += 1;
556 }
557 EndWhile;
558 output[windowWidth * windowHeight - 2] : = '0' + mod(second, 10);
560 output[windowWidth * windowHeight - 3] : = '0' + second / 10;
561 colors[windowWidth * windowHeight - 2]
562 : = colors[windowWidth * windowHeight - 3] : = blueColor;
563 output[windowWidth * windowHeight - 4] : = ':';
564 output[windowWidth * windowHeight - 5] : = '0' + mod(minute, 10);
565 output[windowWidth * windowHeight - 6] : = '0' + minute / 10;
566 colors[windowWidth * windowHeight - 5]
567 : = colors[windowWidth * windowHeight - 6] : = yellowColor;
568 output[windowWidth * windowHeight - 7] : = ':';
569 output[windowWidth * windowHeight - 8] : = '0' + mod(hour, 10);
570 output[windowWidth * windowHeight - 9] : = '0' + hour / 10;
571 colors[windowWidth * windowHeight - 8]
572 : = colors[windowWidth * windowHeight - 9] : = redColor;
573 Character signature[100] : = {0};
575 PointerToCharacter signature : = AddressOf(signature[0]);
576 logString("Empty signature has length of: ");
579 logInteger(strlen(signature));
580 logString("\n");
581 strcat(signature, " Analog Clock for WebAssembly\n");
582 logString("The first row of the signature has length of: ");
583 logInteger(strlen(signature));
584 logString("\n");
585 strcat(signature, " Made in AEC by\n");
586 logString("The first two rows of signature have length: ");
587 logInteger(strlen(signature));
588 logString("\n");
589 strcat(signature, " Teo Samarzija");
590 logString("Signature has length of: ");
591 logInteger(strlen(signature));
592 logString("\n\n"); i:
594 = windowWidth * (windowHeight - 3);
595 j:
596 = 0;
597 PointerToCharacter modraColor : = "#AAFFFF"; While not(signature[j] = 0) Loop {
602 If signature[j] = '\n' Then {
603 i:
604 = (i / windowWidth + 1) * windowWidth;
605 }
606 ElseIf not(signature[j] = 0) Then {
607 output[i] : = signature[j];
608 colors[i] : = modraColor;
609 i += 1;
610 }
611 Else { output[i] : = ' '; }
612 EndIf;
613 j += 1;
614 }
615 EndWhile;
616 }
617 EndFunction;
618