void run() { Vector screenSize(80, 48); int frames = 13125000 * 14 / (11 * 76 * 262); int maxRadius = 20; // Center of screen Vector2<double> c = Vector2Cast<double>(screenSize) / 2; // Positions of screen top-left relative to centre of each picture Array<Vector> p1s(frames); Array<Vector> p2s(frames); int minX = 0, maxX = 0; for (int t = 0; t < frames; ++t) { double f = static_cast<double>(t) / frames; double r = maxRadius; // *(1 - cos(f * tau)) / 2; Rotor2<double> z1(f * 6); Rotor2<double> z2(f * 7); Vector2<double> a1(r*cos(f*tau * 6), r*sin(f*tau * 7)); Vector2<double> a2(r*cos(f*tau * 5), r*sin(f*tau * 4)); // Positions of picture centres relative to screen top-left Vector p1 = -Vector2Cast<int>(c + a1); Vector p2 = -Vector2Cast<int>(c + a2); p1s[t] = p1; p2s[t] = p2; minX = min(min(minX, p1.x), p2.x); maxX = max(max(maxX, p1.x + screenSize.x), p2.x + screenSize.x); } int stride = (3 + maxX - minX) & ~3; // Offset in picture from start of screen to end int ss = (screenSize.y - 1)*stride + screenSize.x; Array<int> o1s(frames); Array<int> o2s(frames); int minO = 0, maxO = 0; for (int t = 0; t < frames; ++t) { Vector p1 = p1s[t]; Vector p2 = p2s[t]; // Offsets of screen top-left into pictures relative to pictures // center. int o1 = p1.y*stride + p1.x; int o2 = p2.y*stride + p2.x; int o1e = o1 + ss; int o2e = o2 + ss; // Picture bounds minO = min(min(minO, o1), o2); maxO = max(max(maxO, o1e), o2e); o1s[t] = o1; o2s[t] = o2; } minO &= -2; maxO = (maxO + 1) & -2; FileStream output = File("tables.asm").openWrite(); /* output.write("cpu 8086\n" "segment _DATA public class = DATA\n" "\n" "global _picture, _motion\n" "\n" "\n"); */ int d = ((-minO) / stride + 1)*stride + stride/2; int bytes = (maxO + 1 - minO) / 2; int xs = (minO + d) % stride; int ys = (minO - xs) / stride; console.write("First position: (" + decimal(xs) + ", " + decimal(ys) + ")\n"); xs = (maxO + d) % stride; ys = (maxO - xs) / stride; console.write("Last position: (" + decimal(xs) + ", " + decimal(ys) + ")\n"); console.write("Picture size: " + decimal(bytes) + "\n"); console.write("Motion size: " + decimal(4 * frames) + "\n"); output.write("frames equ " + decimal(frames) + "\n"); output.write("stride equ " + decimal(stride/2) + "\n"); output.write("p equ picture\n"); output.write( "p2 equ pictureEnd+(pictureEnd-picture)+(headerEnd-header)\n\n"); output.write("motion:"); for (int t = 0; t < frames; ++t) { int o1 = o1s[t] - minO; int o2 = o2s[t] - minO; int sp = o1 / 2; if ((o1 & 1) != 0) sp += bytes; int bp = o2 / 2; if ((o2 & 1) != 0) bp += bytes; if (t % 3 == 0) output.write("\n dw "); else output.write(", "); output.write("p+" + hex(sp, 4) + ", p+" + hex(bp, 4)); } int lastX = 20; output.write("\n\n"); int p2 = (maxO + 1 - minO) / 2; p2 += p2 - 1; output.write("transition:"); Array<bool> cleared(20 * 13); for (int p = 0; p < 20 * 13; ++p) cleared[p] = false; int pp = 0; for (int t = 0; t < 1000000; ++t) { int r = 999 - t / 1000; int theta = t % 1000; Vector2<double> z = Vector2<double>(r/20.0, 0)*Rotor2<double>(theta / 1000.0); Vector p = Vector2Cast<int>(z + Vector2<double>(10, 6)); if (p.x >= 0 && p.x < 20 && p.y >= 0 && p.y < 12) { int aa = p.y * 20 + p.x; if (cleared[aa]) continue; int a = p.y * 206 * 4 + p.x * 10; if (pp % 3 == 0) output.write("\n dw "); else output.write(", "); ++pp; output.write("p2+" + hex(a, 4) + ", "); if (p.y == 12) output.write("p2+" + hex(a, 4)); else output.write("p2+" + hex(a + 206*2, 4)); cleared[aa] = true; } } console.write("pp = " + decimal(pp) + " \n"); output.write("\n\npicture:"); for (int o = minO; o < maxO + 1; o += 2) { int x = (o + d) % stride; int y = (o + d - x) / stride - d/stride; if (lastX == 20) { output.write("\n db "); lastX = 0; } else output.write(", "); for (; lastX < x % 20; lastX += 2) output.write(" "); Vector p(x - stride / 2, y); int cL = colour(p); int cR = colour(p + Vector(1, 0)); int b = cL | (cR << 4); output.write(String(hex(b, 2))); lastX += 2; } output.write("\n"); output.write("pictureEnd:\n"); }
int malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) { int ret; size_t i; const char *f; #define APPEND_C(c) do { \ if (i < size) \ str[i] = (c); \ i++; \ } while (0) #define APPEND_S(s, slen) do { \ if (i < size) { \ size_t cpylen = (slen <= size - i) ? slen : size - i; \ memcpy(&str[i], s, cpylen); \ } \ i += slen; \ } while (0) #define APPEND_PADDED_S(s, slen, width, left_justify) do { \ /* Left padding. */ \ size_t pad_len = (width == -1) ? 0 : ((slen < (size_t)width) ? \ (size_t)width - slen : 0); \ if (left_justify == false && pad_len != 0) { \ size_t j; \ for (j = 0; j < pad_len; j++) \ APPEND_C(' '); \ } \ /* Value. */ \ APPEND_S(s, slen); \ /* Right padding. */ \ if (left_justify && pad_len != 0) { \ size_t j; \ for (j = 0; j < pad_len; j++) \ APPEND_C(' '); \ } \ } while (0) #define GET_ARG_NUMERIC(val, len) do { \ switch (len) { \ case '?': \ val = va_arg(ap, int); \ break; \ case '?' | 0x80: \ val = va_arg(ap, unsigned int); \ break; \ case 'l': \ val = va_arg(ap, long); \ break; \ case 'l' | 0x80: \ val = va_arg(ap, unsigned long); \ break; \ case 'q': \ val = va_arg(ap, long long); \ break; \ case 'q' | 0x80: \ val = va_arg(ap, unsigned long long); \ break; \ case 'j': \ val = va_arg(ap, intmax_t); \ break; \ case 't': \ val = va_arg(ap, ptrdiff_t); \ break; \ case 'z': \ val = va_arg(ap, ssize_t); \ break; \ case 'z' | 0x80: \ val = va_arg(ap, size_t); \ break; \ case 'p': /* Synthetic; used for %p. */ \ val = va_arg(ap, uintptr_t); \ break; \ default: not_reached(); \ } \ } while (0) i = 0; f = format; while (true) { switch (*f) { case '\0': goto label_out; case '%': { bool alt_form = false; bool zero_pad = false; bool left_justify = false; bool plus_space = false; bool plus_plus = false; int prec = -1; int width = -1; unsigned char len = '?'; f++; if (*f == '%') { /* %% */ APPEND_C(*f); break; } /* Flags. */ while (true) { switch (*f) { case '#': assert(alt_form == false); alt_form = true; break; case '0': assert(zero_pad == false); zero_pad = true; break; case '-': assert(left_justify == false); left_justify = true; break; case ' ': assert(plus_space == false); plus_space = true; break; case '+': assert(plus_plus == false); plus_plus = true; break; default: goto label_width; } f++; } /* Width. */ label_width: switch (*f) { case '*': width = va_arg(ap, int); f++; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { uintmax_t uwidth; set_errno(0); uwidth = malloc_strtoumax(f, (char **)&f, 10); assert(uwidth != UINTMAX_MAX || get_errno() != ERANGE); width = (int)uwidth; if (*f == '.') { f++; goto label_precision; } else goto label_length; break; } case '.': f++; goto label_precision; default: goto label_length; } /* Precision. */ label_precision: switch (*f) { case '*': prec = va_arg(ap, int); f++; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { uintmax_t uprec; set_errno(0); uprec = malloc_strtoumax(f, (char **)&f, 10); assert(uprec != UINTMAX_MAX || get_errno() != ERANGE); prec = (int)uprec; break; } default: break; } /* Length. */ label_length: switch (*f) { case 'l': f++; if (*f == 'l') { len = 'q'; f++; } else len = 'l'; break; case 'j': len = 'j'; f++; break; case 't': len = 't'; f++; break; case 'z': len = 'z'; f++; break; default: break; } /* Conversion specifier. */ switch (*f) { char *s; size_t slen; case 'd': case 'i': { intmax_t val JEMALLOC_CC_SILENCE_INIT(0); char buf[D2S_BUFSIZE]; GET_ARG_NUMERIC(val, len); s = d2s(val, (plus_plus ? '+' : (plus_space ? ' ' : '-')), buf, &slen); APPEND_PADDED_S(s, slen, width, left_justify); f++; break; } case 'o': { uintmax_t val JEMALLOC_CC_SILENCE_INIT(0); char buf[O2S_BUFSIZE]; GET_ARG_NUMERIC(val, len | 0x80); s = o2s(val, alt_form, buf, &slen); APPEND_PADDED_S(s, slen, width, left_justify); f++; break; } case 'u': { uintmax_t val JEMALLOC_CC_SILENCE_INIT(0); char buf[U2S_BUFSIZE]; GET_ARG_NUMERIC(val, len | 0x80); s = u2s(val, 10, false, buf, &slen); APPEND_PADDED_S(s, slen, width, left_justify); f++; break; } case 'x': case 'X': { uintmax_t val JEMALLOC_CC_SILENCE_INIT(0); char buf[X2S_BUFSIZE]; GET_ARG_NUMERIC(val, len | 0x80); s = x2s(val, alt_form, *f == 'X', buf, &slen); APPEND_PADDED_S(s, slen, width, left_justify); f++; break; } case 'c': { unsigned char val; char buf[2]; assert(len == '?' || len == 'l'); assert_not_implemented(len != 'l'); val = va_arg(ap, int); buf[0] = val; buf[1] = '\0'; APPEND_PADDED_S(buf, 1, width, left_justify); f++; break; } case 's': assert(len == '?' || len == 'l'); assert_not_implemented(len != 'l'); s = va_arg(ap, char *); slen = (prec == -1) ? strlen(s) : prec; APPEND_PADDED_S(s, slen, width, left_justify); f++; break; case 'p': { uintmax_t val; char buf[X2S_BUFSIZE]; GET_ARG_NUMERIC(val, 'p'); s = x2s(val, true, false, buf, &slen); APPEND_PADDED_S(s, slen, width, left_justify); f++; break; } default: not_implemented(); } break; } default: { APPEND_C(*f); f++; break; }} } label_out: if (i < size) str[i] = '\0'; else str[size - 1] = '\0'; ret = i; #undef APPEND_C #undef APPEND_S #undef APPEND_PADDED_S #undef GET_ARG_NUMERIC return (ret); }