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("\"atan2\" function seems 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("\n\n\n");
287 }
288 EndIf;
289 Integer32 windowWidth : = 80, windowHeight : = 23, i : = 0;
290 PointerToCharacter lightGrayColor : = "#EEEEEE",
291 lightGreenColor : = "#CCFFCC";
292 While(i < windowWidth * windowHeight) Loop { If mod(i, windowWidth) = windowWidth - 1 Then { output[i] : = '\n'; }
295 Else { output[i] : = ' '; }
296 EndIf;
297 colors[i] : = lightGrayColor;
298 i += 1;
299 }
300 EndWhile;
301 Integer32 centerX : = windowWidth / 2, centerY : = windowHeight / 2,
302 clockRadius : = (centerX < centerY) ? centerX - 1
303 : centerY - 1;
304 i:
305 = 0;
306 While(i < windowWidth * windowHeight) Loop { Integer32 y : = i / windowWidth, x : = mod(i, windowWidth);
309 Decimal32 distance : = sqrt((x - centerX) * (x - centerX) +
310 (y - centerY) * (y - centerY)); If abs(distance - clockRadius) < 3. / 4 Then {
313 output[i] : = '*';
314 colors[i] : = lightGreenColor;
315 }
316 EndIf;
317 i += 1;
318 }
319 EndWhile;
320 PointerToCharacter redColor : = "#FFAAAA";
321 output[(centerY - clockRadius + 1) * windowWidth + centerX] : = '1';
323 output[(centerY - clockRadius + 1) * windowWidth + centerX + 1] : = '2';
324 colors[(centerY - clockRadius + 1) * windowWidth + centerX]
325 : = colors[(centerY - clockRadius + 1) * windowWidth + centerX + 1]
326 : = redColor;
327 output[(centerY + clockRadius - 1) * windowWidth + centerX] : = '6';
329 colors[(centerY + clockRadius - 1) * windowWidth + centerX] : = redColor;
330 output[centerY * windowWidth + centerX + clockRadius - 1] : = '3';
332 colors[centerY * windowWidth + centerX + clockRadius - 1] : = redColor;
333 output[centerY * windowWidth + centerX - clockRadius + 1] : = '9';
335 colors[centerY * windowWidth + centerX - clockRadius + 1] : = redColor;
336 Integer32 y : = centerY - (clockRadius - 1) * cos(360. / 12);
338 output[y * windowWidth + centerX + sin(360. / 12) * (clockRadius - 1)]
339 : = '1';
340 colors[y * windowWidth + centerX + sin(360. / 12) * (clockRadius - 1)]
341 : = redColor;
342 y:
344 = centerY - (clockRadius - 1.5) * cos(2 * 360. / 12);
345 output[y * windowWidth + centerX + sin(2 * 360. / 12) * (clockRadius - 1.5)]
346 : = '2';
347 colors[y * windowWidth + centerX + sin(2 * 360. / 12) * (clockRadius - 1.5)]
348 : = redColor;
349 y:
351 = centerY - (clockRadius - 1) * cos(4 * 360. / 12);
352 output[y * windowWidth + centerX + sin(4 * 360. / 12) * (clockRadius - 1) + 1]
353 : = '4';
354 colors[y * windowWidth + centerX + sin(4 * 360. / 12) * (clockRadius - 1) + 1]
355 : = redColor;
356 y:
358 = centerY - (clockRadius - 1) * cos(5 * 360. / 12);
359 output[y * windowWidth + centerX + sin(5 * 360. / 12) * (clockRadius - 1) + 1]
360 : = '5';
361 colors[y * windowWidth + centerX + sin(5 * 360. / 12) * (clockRadius - 1) + 1]
362 : = redColor;
363 y:
365 = centerY - (clockRadius - 1) * cos(7 * 360. / 12);
366 output[y * windowWidth + centerX + sin(7 * 360. / 12) * (clockRadius - 1)]
367 : = '7';
368 colors[y * windowWidth + centerX + sin(7 * 360. / 12) * (clockRadius - 1)]
369 : = redColor;
370 y:
372 = centerY - (clockRadius - 1) * cos(8 * 360. / 12);
373 output[y * windowWidth + centerX + sin(8 * 360. / 12) * (clockRadius - 1)]
374 : = '8';
375 colors[y * windowWidth + centerX + sin(8 * 360. / 12) * (clockRadius - 1)]
376 : = redColor;
377 y:
379 = centerY - (clockRadius - 1.5) * cos(10 * 360. / 12);
380 output[y * windowWidth + centerX + sin(10 * 360. / 12) * (clockRadius - 1.5) +
381 1] : = '1';
382 output[y * windowWidth + centerX + sin(10 * 360. / 12) * (clockRadius - 1.5) +
383 2] : = '0';
384 colors[y * windowWidth + centerX + sin(10 * 360. / 12) * (clockRadius - 1.5) +
385 1] : = colors[y * windowWidth + centerX +
386 sin(10 * 360. / 12) * (clockRadius - 1.5) + 2]
387 : = redColor;
388 y:
390 = centerY - (clockRadius - 1.5) * cos(11 * 360. / 12);
391 output[y * windowWidth + centerX + sin(11 * 360. / 12) * (clockRadius - 1.5) +
392 1] : = output[y * windowWidth + centerX +
393 sin(11 * 360. / 12) * (clockRadius - 1.5) + 2] : = '1';
394 colors[y * windowWidth + centerX + sin(11 * 360. / 12) * (clockRadius - 1.5) +
395 1] : = colors[y * windowWidth + centerX +
396 sin(11 * 360. / 12) * (clockRadius - 1.5) + 2]
397 : = redColor;
398 Integer32 j : = 0;
399 Decimal32 angle;
400 PointerToCharacter blueColor : = "#AAAAFF", yellowColor : = "#FFFFAA";
401 While j < 3 Loop {
402 PointerToCharacter currentColor;
403 If j = 0 Then {
404 angle:
405 = fmod(hour + minute / 60., 12) * (360. / 12);
406 currentColor:
407 = redColor;
408 }
409 ElseIf j = 1 Then {
410 angle:
411 = minute * (360. / 60);
412 currentColor:
413 = yellowColor;
414 }
415 Else {
416 angle:
417 = second * (360 / 60);
418 currentColor:
419 = blueColor;
420 }
421 EndIf;
422 Decimal32 endOfTheHandX
423 : = centerX +
424 sin(angle) * clockRadius / (j = 0 ? 2. : j = 1 ? 3. / 2 : 4. / 3),
425 endOfTheHandY : = centerY - cos(angle) * clockRadius /
426 (j = 0 ? 2. : j = 1 ? 3. / 2 : 4. / 3),
427 coefficientOfTheDirection
428 : = (endOfTheHandY - centerY) /
429 (abs(endOfTheHandX - centerX) = 0 ?
430 1. / 100
433 : endOfTheHandX - centerX);
434 logString("Drawing line between (");
435 logInteger(centerX);
436 logString(",");
437 logInteger(centerY);
438 logString(") and (");
439 logInteger(endOfTheHandX);
440 logString(",");
441 logInteger(endOfTheHandY);
442 logString(").\n");
443 i:
444 = 0;
445 While(i < windowWidth * windowHeight) Loop {
446 Decimal32 lowerBoundX
447 : = endOfTheHandX < centerX ? endOfTheHandX : Decimal32(centerX),
448 upperBoundX : = endOfTheHandX > centerX ? endOfTheHandX
449 : Decimal32(centerX),
450 lowerBoundY : = endOfTheHandY < centerY ? endOfTheHandY : centerY,
451 upperBoundY : = endOfTheHandY > centerY ? endOfTheHandY : centerY;
452 y:
453 = i / windowWidth;
454 Integer32 x : = mod(i, windowWidth), isXWithinBounds;
455 isXWithinBounds:
456 = lowerBoundX <= x <= upperBoundX;
457 Integer32 isYWithinBounds;
458 isYWithinBounds:
459 = lowerBoundY <= y <= upperBoundY;
460 If isXWithinBounds and isYWithinBounds Then {
461 Decimal32 expectedX, expectedY;
462 expectedY:
463 = (x - centerX) * coefficientOfTheDirection + centerY;
464 expectedX:
465 = (y - centerY) * (1 / coefficientOfTheDirection) + centerX;
466 If coefficientOfTheDirection = 1. / 0 Then {
467 expectedY:
468 = 1000; }
470 EndIf;
471 If coefficientOfTheDirection = 0 Then {
472 expectedX:
473 = 1000; }
475 EndIf;
476 logString("The point (");
477 logInteger(x);
478 logString(",");
479 logInteger(y);
480 logString(") is within bounds, expectedY is ");
481 logInteger(expectedY);
482 logString(" and expectedX is ");
483 logInteger(expectedX);
484 logString(".\n");
485 Character currentSign : = j = 0 ? 'h' : j = 1 ? 'm' : 's';
486 If((abs(upperBoundX - lowerBoundX) < 1 + 1 / PRECISION or
487 abs(upperBoundY - lowerBoundY) < 1 + 1 / PRECISION) and
488 output[i] = ' ') Then {
489 output[i] : = currentSign;
490 colors[i] : = currentColor;
491 }
492 EndIf;
493 If(abs(expectedX - x) < 3. / 4 or abs(expectedY - y) < 3. / 4) and
494 output[i] = ' ' Then {
495 output[i] : = currentSign;
496 colors[i] : = currentColor;
497 }
498 EndIf;
499 }
500 EndIf;
501 i += 1;
502 }
503 EndWhile;
504 j += 1;
505 }
506 EndWhile;
507 PointerToCharacter darkGreenColor : = "#AAFFAA";
509 i:
510 = 0;
511 While(i < windowWidth * windowHeight) Loop {
512 y:
513 = i / windowWidth;
514 Integer32 x : = mod(i, windowWidth);
515 If abs(windowHeight - 2 * ln(1 + abs((x - centerX) / 2.)) -
516 y)<1 - abs(x - centerX) / (centerX * 95. / 112) and x> 1. /
517 2 * centerX and x <
518 3. / 2 * centerX and output[i] =
519 ' ' Then { output[i] : = 'x';
522 colors[i] : = darkGreenColor;
523 }
524 EndIf;
525 i += 1;
526 }
527 EndWhile;
528 j:
531 = 0;
532 While j < 3 Loop {
533 i:
534 = windowWidth * (windowHeight - 1); While(i < windowWidth * windowHeight) Loop {
537 If j < 2 and (output[i - windowWidth] =
538 'x' and (output[i + 1] = 'x' or output[i - 1] = 'x'))
539 Then {
540 output[i] : = 'x';
541 colors[i] : = darkGreenColor;
542 }
543 ElseIf j =
544 2 and (output[i + 1] = ' ' and output[i - windowWidth] = 'x') Then {
545 output[i] : = ' ';
546 }
547 EndIf;
548 i += 1;
549 }
550 EndWhile;
551 j += 1;
552 }
553 EndWhile;
554 output[windowWidth * windowHeight - 2] : = '0' + mod(second, 10);
556 output[windowWidth * windowHeight - 3] : = '0' + second / 10;
557 colors[windowWidth * windowHeight - 2]
558 : = colors[windowWidth * windowHeight - 3] : = blueColor;
559 output[windowWidth * windowHeight - 4] : = ':';
560 output[windowWidth * windowHeight - 5] : = '0' + mod(minute, 10);
561 output[windowWidth * windowHeight - 6] : = '0' + minute / 10;
562 colors[windowWidth * windowHeight - 5]
563 : = colors[windowWidth * windowHeight - 6] : = yellowColor;
564 output[windowWidth * windowHeight - 7] : = ':';
565 output[windowWidth * windowHeight - 8] : = '0' + mod(hour, 10);
566 output[windowWidth * windowHeight - 9] : = '0' + hour / 10;
567 colors[windowWidth * windowHeight - 8]
568 : = colors[windowWidth * windowHeight - 9] : = redColor;
569 Character signature[100] : = {0};
571 PointerToCharacter signature : = AddressOf(signature[0]);
572 logString("Empty signature has length of: ");
575 logInteger(strlen(signature));
576 logString("\n");
577 strcat(signature, " Analog Clock for WebAssembly\n");
578 logString("The first row of the signature has length of: ");
579 logInteger(strlen(signature));
580 logString("\n");
581 strcat(signature, " Made in AEC by\n");
582 logString("The first two rows of signature have length: ");
583 logInteger(strlen(signature));
584 logString("\n");
585 strcat(signature, " Teo Samarzija");
586 logString("Signature has length of: ");
587 logInteger(strlen(signature));
588 logString(" \n\n"); i:
590 = windowWidth * (windowHeight - 3);
591 j:
592 = 0;
593 PointerToCharacter modraColor : = "#AAFFFF"; While not(signature[j] = 0) Loop {
598 If signature[j] = '\n' Then {
599 i:
600 = (i / windowWidth + 1) * windowWidth;
601 }
602 ElseIf not(signature[j] = 0) Then {
603 output[i] : = signature[j];
604 colors[i] : = modraColor;
605 i += 1;
606 }
607 Else { output[i] : = ' '; }
608 EndIf;
609 j += 1;
610 }
611 EndWhile;
612 }
613 EndFunction;
614