1
5
6 #target WASI
9 Function logString(PointerToCharacter str) Which Returns Nothing Is External;
11 Function logInteger(Integer32 int) Which Returns Nothing Is External;
12
13 Character output[23 * 80];
15 PointerToCharacter colors[23 * 80];
19 Function getAddressOfOutput() Which Returns PointerToCharacter
20 Does { Return AddressOf(output[0]); }
26 EndFunction;
27
28 Function getAddressOfColors() Which Returns PointerToPointerToCharacter Does {
29 Return AddressOf(colors[0]);
30 }
31 EndFunction;
32
33 Decimal32 PRECISION : = 512; Integer32 USE_WEBASSEMBLY_SQRT_INSTRUCTION
47 : = 1; Function ln(Decimal32 x) Which Returns Decimal32 Does {
53 Decimal32 sum : = 0, epsilon : = (x - 1) / (5 * PRECISION), i : = 1;
55 While(epsilon > 0 and i < x) or (epsilon < 0 and i > x) Loop {
56 sum += epsilon / i;
57 i += epsilon;
58 }
59 EndWhile; Return sum;
65 }
66 EndFunction;
67
68 Function exp(Decimal32 x) Which Returns Decimal32 Does {
69 Decimal32 i : = 0, y : = 1, epsilon : = x / PRECISION;
71 While(epsilon > 0 and i < x) or (epsilon < 0 and i > x) Loop {
72 y += epsilon * y;
73 i += epsilon;
74 }
75 EndWhile;
76 Return y;
77 }
78 EndFunction;
79
80 Function sqrt(Decimal32 x) Which Returns Decimal32 Does {
81 If USE_WEBASSEMBLY_SQRT_INSTRUCTION Then {
82 Return asm_f32(
83 R"multiline((f32.sqrt
84 (f32.load
85 %x ;;The compiler will replace "%x" with assembly code representing a pointer to the variable "x".
86 )
87 ))multiline"); }
91 EndIf;
92 Decimal32 max
94 : = 80 * 80 + 24 * 24, min : = 0, i : = (min + max) / 2;
98 If(max * max < x) Then {
100 Return exp(
101 ln(x) /
102 2); }
104 EndIf;
105 While((max - min) > 1 / PRECISION) Loop {
106 If(i * i > x) Then {
107 max
114 : = i;
115 }
116 Else {
117 min:
118 = i;
119 }
120 EndIf;
121 i:
122 = (max + min) / 2;
123 }
124 EndWhile;
125 Return i;
126 }
127 EndFunction;
128
129 Function fmod(Decimal32 a, Decimal32 b) Which Returns Decimal32 Does {
130 Return(a - b * Integer32(a / b));
131 }
132 EndFunction;
133
134 Decimal32 oneRadianInDegrees
136 : = 180 / pi;
143 Function arctan(Decimal32 x) Which Returns Decimal32 Does {
144 Decimal32 sum : = 0, epsilon : = x / PRECISION, i : = 0;
146 While(i < x) Loop {
147 sum += epsilon / (1 + i * i);
148 i += epsilon;
149 }
150 EndWhile;
151 Return(sum * oneRadianInDegrees);
152 }
153 EndFunction;
154
155 Function atan2(Decimal32 y, Decimal32 x) Which Returns Decimal32 Does {
156 If(y = 0) Then {
157 If(x < 0) Then { Return 180; }
158 Else { Return 0; }
159 EndIf;
160 }
161 ElseIf(x = 0) Then {
162 If y < 0 Then { Return 270; }
163 Else { Return 90; }
164 EndIf;
165 }
166 Else {
167 If(x > 0 and y > 0) Then { Return arctan(y / x); }
168 ElseIf(x < 0 and y > 0) Then { Return 90 + arctan(-x / y); }
169 ElseIf(x < 0 and y < 0) Then { Return 180 + arctan(y / x); }
170 Else { Return 270 + arctan(-x / y); }
171 EndIf;
172 }
173 EndIf;
174 }
175 EndFunction;
176
177 Function cos(Decimal32 degrees)
178 Which Returns Decimal32 Is Declared;
181 Decimal32 sineMemoisation[91];
182
183 Function sin(Decimal32 degrees) Which Returns Decimal32 Does {
184 If(degrees < 0) Then { Return - sin(-degrees); }
185 EndIf;
186 If degrees > 90 Then { Return cos(degrees - 90); }
187 EndIf;
188 If not(sineMemoisation[asm_f32("(f32.nearest (f32.load %degrees))")] = 0)
189 Then { Return sineMemoisation[asm_f32("(f32.nearest (f32.load %degrees))")];
195 }
196 EndIf;
197
211 Decimal32 radians : = degrees / oneRadianInDegrees, tmpsin : = 0,
212 tmpcos : = 1, epsilon : = radians / PRECISION, i : = 0;
213 While((epsilon > 0 and i < radians) or (epsilon < 0 and i > radians)) Loop {
214 tmpsin += epsilon * tmpcos;
215 tmpcos -= epsilon * tmpsin;
216 i += epsilon;
217 }
218 EndWhile;
219 Return sineMemoisation[asm_f32("(f32.nearest (f32.load %degrees))")]
220 : = tmpsin;
221 }
222 EndFunction;
223
224 Function arcsin(Decimal32 x) Which Returns Decimal32 Does {
225 Return arctan(x / sqrt(1 - x * x)); }
227 EndFunction;
228
229 Function arccos(Decimal32 x) Which Returns Decimal32 Does {
230 Return 90 - arcsin(x); }
233 EndFunction;
234
235 Function cos(Decimal32 degrees) Which Returns Decimal32 Does {
236 Return sin(90 - degrees); }
239 EndFunction;
240
241 Function tan(Decimal32 degrees) Which Returns Decimal32 Does {
242 Return sin(degrees) / cos(degrees); }
244 EndFunction;
245
246 Function abs(Decimal32 x) Which Returns Decimal32 Does {
247 Return x < 0 ? -x : x;
248 }
249 EndFunction;
250
251 Function strlen(PointerToCharacter ptr) Which Returns Integer32 Does {
254 Return ValueAt(ptr) = 0 ? 0 : 1 + strlen(ptr + 1);
255 }
256 EndFunction;
257
258 Function strcat(PointerToCharacter first,
259 PointerToCharacter second) Which Returns Nothing Does {
260 first += strlen(first);
261 While ValueAt(second) Loop {
262 ValueAt(first) : = ValueAt(second);
263 first += 1;
264 second += 1;
265 }
266 EndWhile;
267 ValueAt(first) : = 0;
268 }
269 EndFunction;
270
271 Function updateClockToTime(Integer32 hour, Integer32 minute,
274 Integer32 second) Which Returns Nothing Does {
275 If((abs(atan2(sin(5), cos(5)) - 5) > 1) or
276 (abs(atan2(sin(95), cos(95)) - 95) > 1) or
277 (abs(atan2(sin(185), cos(185)) - 185) > 1) or
278 (abs(atan2(sin(275), cos(275)) - 275) > 1) or
279 (abs(arcsin(sin(60)) - 60) > 1) or (abs(arccos(cos(60)) - 60) > 1)) Then {
280 logString("The cyclometric functions seem not to work!\n");
281 logString("atan2(sin(5), cos(5))=");
282 logInteger(atan2(sin(5), cos(5)));
283 logString("\natan2(sin(95),cos(95))=");
284 logInteger(atan2(sin(95), cos(95)));
285 logString("\natan2(sin(185),cos(185))=");
286 logInteger(atan2(sin(185), cos(185)));
287 logString("\natan2(sin(275),cos(275))=");
288 logInteger(atan2(sin(275), cos(275)));
289 logString("\narcsin(sin(60))=");
290 logInteger(arcsin(sin(60)));
291 logString("\narccos(cos(60))=");
292 logInteger(arccos(cos(60)));
293 logString("\n\n");
294 }
295 EndIf;
296 Integer32 windowWidth : = 80, windowHeight : = 23, i : = 0;
297 PointerToCharacter lightGrayColor : = "#EEEEEE",
298 lightGreenColor : = "#CCFFCC";
299 While(i < windowWidth * windowHeight) Loop { If mod(i, windowWidth) = windowWidth - 1 Then { output[i] : = '\n'; }
302 Else { output[i] : = ' '; }
303 EndIf;
304 colors[i] : = lightGrayColor;
305 i += 1;
306 }
307 EndWhile;
308 Integer32 centerX : = windowWidth / 2, centerY : = windowHeight / 2,
309 clockRadius : = (centerX < centerY) ? centerX - 1
310 : centerY - 1;
311 i:
312 = 0;
313 While(i < windowWidth * windowHeight) Loop { Integer32 y : = i / windowWidth, x : = mod(i, windowWidth);
316 Decimal32 distance : = sqrt((x - centerX) * (x - centerX) +
317 (y - centerY) * (y - centerY)); If abs(distance - clockRadius) < 3. / 4 Then {
320 output[i] : = '*';
321 colors[i] : = lightGreenColor;
322 }
323 EndIf;
324 i += 1;
325 }
326 EndWhile;
327 PointerToCharacter redColor : = "#FFAAAA";
328 output[(centerY - clockRadius + 1) * windowWidth + centerX] : = '1';
330 output[(centerY - clockRadius + 1) * windowWidth + centerX + 1] : = '2';
331 colors[(centerY - clockRadius + 1) * windowWidth + centerX]
332 : = colors[(centerY - clockRadius + 1) * windowWidth + centerX + 1]
333 : = redColor;
334 output[(centerY + clockRadius - 1) * windowWidth + centerX] : = '6';
336 colors[(centerY + clockRadius - 1) * windowWidth + centerX] : = redColor;
337 output[centerY * windowWidth + centerX + clockRadius - 1] : = '3';
339 colors[centerY * windowWidth + centerX + clockRadius - 1] : = redColor;
340 output[centerY * windowWidth + centerX - clockRadius + 1] : = '9';
342 colors[centerY * windowWidth + centerX - clockRadius + 1] : = redColor;
343 Integer32 y : = centerY - (clockRadius - 1) * cos(360. / 12);
345 output[y * windowWidth + centerX + sin(360. / 12) * (clockRadius - 1)]
346 : = '1';
347 colors[y * windowWidth + centerX + sin(360. / 12) * (clockRadius - 1)]
348 : = redColor;
349 y:
351 = centerY - (clockRadius - 1.5) * cos(2 * 360. / 12);
352 output[y * windowWidth + centerX + sin(2 * 360. / 12) * (clockRadius - 1.5)]
353 : = '2';
354 colors[y * windowWidth + centerX + sin(2 * 360. / 12) * (clockRadius - 1.5)]
355 : = redColor;
356 y:
358 = centerY - (clockRadius - 1) * cos(4 * 360. / 12);
359 output[y * windowWidth + centerX + sin(4 * 360. / 12) * (clockRadius - 1) + 1]
360 : = '4';
361 colors[y * windowWidth + centerX + sin(4 * 360. / 12) * (clockRadius - 1) + 1]
362 : = redColor;
363 y:
365 = centerY - (clockRadius - 1) * cos(5 * 360. / 12);
366 output[y * windowWidth + centerX + sin(5 * 360. / 12) * (clockRadius - 1) + 1]
367 : = '5';
368 colors[y * windowWidth + centerX + sin(5 * 360. / 12) * (clockRadius - 1) + 1]
369 : = redColor;
370 y:
372 = centerY - (clockRadius - 1) * cos(7 * 360. / 12);
373 output[y * windowWidth + centerX + sin(7 * 360. / 12) * (clockRadius - 1)]
374 : = '7';
375 colors[y * windowWidth + centerX + sin(7 * 360. / 12) * (clockRadius - 1)]
376 : = redColor;
377 y:
379 = centerY - (clockRadius - 1) * cos(8 * 360. / 12);
380 output[y * windowWidth + centerX + sin(8 * 360. / 12) * (clockRadius - 1)]
381 : = '8';
382 colors[y * windowWidth + centerX + sin(8 * 360. / 12) * (clockRadius - 1)]
383 : = redColor;
384 y:
386 = centerY - (clockRadius - 1.5) * cos(10 * 360. / 12);
387 output[y * windowWidth + centerX + sin(10 * 360. / 12) * (clockRadius - 1.5) +
388 1] : = '1';
389 output[y * windowWidth + centerX + sin(10 * 360. / 12) * (clockRadius - 1.5) +
390 2] : = '0';
391 colors[y * windowWidth + centerX + sin(10 * 360. / 12) * (clockRadius - 1.5) +
392 1] : = colors[y * windowWidth + centerX +
393 sin(10 * 360. / 12) * (clockRadius - 1.5) + 2]
394 : = redColor;
395 y:
397 = centerY - (clockRadius - 1.5) * cos(11 * 360. / 12);
398 output[y * windowWidth + centerX + sin(11 * 360. / 12) * (clockRadius - 1.5) +
399 1] : = output[y * windowWidth + centerX +
400 sin(11 * 360. / 12) * (clockRadius - 1.5) + 2] : = '1';
401 colors[y * windowWidth + centerX + sin(11 * 360. / 12) * (clockRadius - 1.5) +
402 1] : = colors[y * windowWidth + centerX +
403 sin(11 * 360. / 12) * (clockRadius - 1.5) + 2]
404 : = redColor;
405 Integer32 j : = 0;
406 Decimal32 angle;
407 PointerToCharacter blueColor : = "#AAAAFF", yellowColor : = "#FFFFAA";
408 While j < 3 Loop {
409 PointerToCharacter currentColor;
410 If j = 0 Then {
411 angle:
412 = fmod(hour + minute / 60., 12) * (360. / 12);
413 currentColor:
414 = redColor;
415 }
416 ElseIf j = 1 Then {
417 angle:
418 = minute * (360. / 60);
419 currentColor:
420 = yellowColor;
421 }
422 Else {
423 angle:
424 = second * (360 / 60);
425 currentColor:
426 = blueColor;
427 }
428 EndIf;
429 Decimal32 endOfTheHandX
430 : = centerX +
431 sin(angle) * clockRadius / (j = 0 ? 2. : j = 1 ? 3. / 2 : 4. / 3),
432 endOfTheHandY : = centerY - cos(angle) * clockRadius /
433 (j = 0 ? 2. : j = 1 ? 3. / 2 : 4. / 3),
434 coefficientOfTheDirection
435 : = (endOfTheHandY - centerY) /
436 (abs(endOfTheHandX - centerX) = 0 ?
437 1. / 100
440 : endOfTheHandX - centerX);
441 logString("Drawing line between (");
442 logInteger(centerX);
443 logString(",");
444 logInteger(centerY);
445 logString(") and (");
446 logInteger(endOfTheHandX);
447 logString(",");
448 logInteger(endOfTheHandY);
449 logString(").\n");
450 i:
451 = 0;
452 While(i < windowWidth * windowHeight) Loop {
453 Decimal32 lowerBoundX
454 : = endOfTheHandX < centerX ? endOfTheHandX : Decimal32(centerX),
455 upperBoundX : = endOfTheHandX > centerX ? endOfTheHandX
456 : Decimal32(centerX),
457 lowerBoundY : = endOfTheHandY < centerY ? endOfTheHandY : centerY,
458 upperBoundY : = endOfTheHandY > centerY ? endOfTheHandY : centerY;
459 y:
460 = i / windowWidth;
461 Integer32 x : = mod(i, windowWidth), isXWithinBounds;
462 isXWithinBounds:
463 = lowerBoundX <= x <= upperBoundX;
464 Integer32 isYWithinBounds;
465 isYWithinBounds:
466 = lowerBoundY <= y <= upperBoundY;
467 If isXWithinBounds and isYWithinBounds Then {
468 Decimal32 expectedX, expectedY;
469 expectedY:
470 = (x - centerX) * coefficientOfTheDirection + centerY;
471 expectedX:
472 = (y - centerY) * (1 / coefficientOfTheDirection) + centerX;
473 If coefficientOfTheDirection = 1. / 0 Then {
474 expectedY:
475 = 1000; }
477 EndIf;
478 If coefficientOfTheDirection = 0 Then {
479 expectedX:
480 = 1000; }
482 EndIf;
483 logString("The point (");
484 logInteger(x);
485 logString(",");
486 logInteger(y);
487 logString(") is within bounds, expectedY is ");
488 logInteger(expectedY);
489 logString(" and expectedX is ");
490 logInteger(expectedX);
491 logString(".\n");
492 Character currentSign : = j = 0 ? 'h' : j = 1 ? 'm' : 's';
493 If((abs(upperBoundX - lowerBoundX) < 1 + 1 / PRECISION or
494 abs(upperBoundY - lowerBoundY) < 1 + 1 / PRECISION) and
495 output[i] = ' ') Then {
496 output[i] : = currentSign;
497 colors[i] : = currentColor;
498 }
499 EndIf;
500 If(abs(expectedX - x) < 3. / 4 or abs(expectedY - y) < 3. / 4) and
501 output[i] = ' ' Then {
502 output[i] : = currentSign;
503 colors[i] : = currentColor;
504 }
505 EndIf;
506 }
507 EndIf;
508 i += 1;
509 }
510 EndWhile;
511 j += 1;
512 }
513 EndWhile;
514 PointerToCharacter darkGreenColor : = "#AAFFAA";
516 i:
517 = 0;
518 While(i < windowWidth * windowHeight) Loop {
519 y:
520 = i / windowWidth;
521 Integer32 x : = mod(i, windowWidth);
522 If abs(windowHeight - 2 * ln(1 + abs((x - centerX) / 2.)) -
523 y)<1 - abs(x - centerX) / (centerX * 95. / 112) and x> 1. /
524 2 * centerX and x <
525 3. / 2 * centerX and output[i] =
526 ' ' Then { output[i] : = 'x';
529 colors[i] : = darkGreenColor;
530 }
531 EndIf;
532 i += 1;
533 }
534 EndWhile;
535 j:
538 = 0;
539 While j < 3 Loop {
540 i:
541 = windowWidth * (windowHeight - 1); While(i < windowWidth * windowHeight) Loop {
544 If j < 2 and (output[i - windowWidth] =
545 'x' and (output[i + 1] = 'x' or output[i - 1] = 'x'))
546 Then {
547 output[i] : = 'x';
548 colors[i] : = darkGreenColor;
549 }
550 ElseIf j =
551 2 and (output[i + 1] = ' ' and output[i - windowWidth] = 'x') Then {
552 output[i] : = ' ';
553 }
554 EndIf;
555 i += 1;
556 }
557 EndWhile;
558 j += 1;
559 }
560 EndWhile;
561 output[windowWidth * windowHeight - 2] : = '0' + mod(second, 10);
563 output[windowWidth * windowHeight - 3] : = '0' + second / 10;
564 colors[windowWidth * windowHeight - 2]
565 : = colors[windowWidth * windowHeight - 3] : = blueColor;
566 output[windowWidth * windowHeight - 4] : = ':';
567 output[windowWidth * windowHeight - 5] : = '0' + mod(minute, 10);
568 output[windowWidth * windowHeight - 6] : = '0' + minute / 10;
569 colors[windowWidth * windowHeight - 5]
570 : = colors[windowWidth * windowHeight - 6] : = yellowColor;
571 output[windowWidth * windowHeight - 7] : = ':';
572 output[windowWidth * windowHeight - 8] : = '0' + mod(hour, 10);
573 output[windowWidth * windowHeight - 9] : = '0' + hour / 10;
574 colors[windowWidth * windowHeight - 8]
575 : = colors[windowWidth * windowHeight - 9] : = redColor;
576 Character signature[100] : = {0};
578 PointerToCharacter signature : = AddressOf(signature[0]);
579 logString("Empty signature has length of: ");
582 logInteger(strlen(signature));
583 logString("\n");
584 strcat(signature, " Analog Clock for WebAssembly\n");
585 logString("The first row of the signature has length of: ");
586 logInteger(strlen(signature));
587 logString("\n");
588 strcat(signature, " Made in AEC by\n");
589 logString("The first two rows of signature have length: ");
590 logInteger(strlen(signature));
591 logString("\n");
592 strcat(signature, " Teo Samarzija");
593 logString("Signature has length of: ");
594 logInteger(strlen(signature));
595 logString("\n\n"); i:
597 = windowWidth * (windowHeight - 3);
598 j:
599 = 0;
600 PointerToCharacter modraColor : = "#AAFFFF"; While not(signature[j] = 0) Loop {
605 If signature[j] = '\n' Then {
606 i:
607 = (i / windowWidth + 1) * windowWidth;
608 }
609 ElseIf not(signature[j] = 0) Then {
610 output[i] : = signature[j];
611 colors[i] : = modraColor;
612 i += 1;
613 }
614 Else { output[i] : = ' '; }
615 EndIf;
616 j += 1;
617 }
618 EndWhile;
619 }
620 EndFunction;
621