Initial import

This commit is contained in:
Justine Tunney 2020-06-15 07:18:57 -07:00
commit c91b3c5006
14915 changed files with 590219 additions and 0 deletions

121
tool/viz/ascii2utf8.c Normal file
View file

@ -0,0 +1,121 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/errno.h"
#include "libc/stdio/stdio.h"
/**
@fileoverview Converts ASCII combining marks to UNICODE.
Getting started:
nroff -mandoc -rLL=72n -rLT=78n -Tutf8 <manpage.1 |
tool/viz/ascii2utf8.com
ASCII Bold:
- CHAR BACKSPACE CHAR c ++ "\b" ++ c
e.g. AABBCCDD 410841 420842 430843 440844
ASCII Underlines:
- CHAR BACKSPACE LOW LINE c ++ "\b_"
e.g. A_B_C_D_ 41085F 42085F 43085F 44085F
UNICODE Underlines:
- COMBINING LOW LINE U+0332 (\xCC\xB1)
e.g. A̲B̲C̲D̲ (ugly notches) 41CCB2 42CCB2 43CCB2 44CCB2
- COMBINING MACRON BELOW U+0331 (\xCC\xB1)
e.g. A̱ḆC̱Ḏ (too short) 41CCB1 42CCB1 43CCB1 44CCB1
- COMBINING DOUBLE MACRON BELOW U+035F (\xCD\x9F)
e.g. A͟B͟C͟D͟ (too long) 41CD9F 42CD9F 43CD9F 44CD9F
- DOUBLE PLUS COMBINING MACRON BELOW 3×U+035F + 1×U+0331
e.g. A͟B͟C͟Ḏ (too narrow) 41CCB1 42CCB1 43CCB1 44CD9F
- DOUBLE PLUS COMBINING MACRON LOW LINE [it's complicated]
e.g. A͟B͟C͟D̲ (𝑓𝑙𝑎𝑤𝑙𝑒𝑠𝑠) 41CD9F 42CD9F 43CD9F 44CCB2
*/
const wint_t kBackspace = '\b';
const wint_t kCombiningLowLine = L'\u0332';
const wint_t kCombiningDoubleMacronBelow = L'\u035f';
forceinline int PutChar(wint_t (*buf)[3], size_t *i, wint_t *cc, FILE *out) {
if (fputwc((*buf)[0], out) == -1) return -1;
if (*cc != -1) {
if (fputwc(*cc, out) == -1) return -1;
*cc = -1;
}
(*buf)[0] = (*buf)[1];
(*buf)[1] = (*buf)[2];
--*i;
return 0;
}
int CombineAsciiMarks(FILE *in, FILE *out) {
wint_t buf[3], wc = 0, cc = -1;
size_t i = 0;
for (;;) {
while (i < 3) {
if ((wc = fgetwc(in)) == -1) goto InputBreak;
buf[i++] = wc;
}
if (buf[1] == '\b' && cc == -1) {
if (buf[0] == buf[2]) { /* bold */
if (L'0' <= buf[0] && buf[0] <= L'9') {
buf[0] = L'𝟬' + (buf[0] - L'0');
i = 1;
} else if (L'A' <= buf[0] && buf[0] <= L'Z') {
buf[0] = L'𝐀' + (buf[0] - L'A');
i = 1;
} else if ('a' <= buf[0] && buf[0] <= L'z') {
buf[0] = L'𝗮' + (buf[0] - L'a');
i = 1;
} else {
i = 1;
}
} else if (buf[2] == '_') { /* underline */
cc = kCombiningLowLine;
i = 1;
} else if (buf[0] == '_') {
cc = kCombiningLowLine;
buf[0] = buf[2];
i = 1;
}
}
if (i == 3) {
if (PutChar(&buf, &i, &cc, out) == -1) goto OutputBreak;
}
}
InputBreak:
while (i) {
if (PutChar(&buf, &i, &cc, out) == -1) goto OutputBreak;
}
OutputBreak:
return (fclose(in) | fclose(out)) != -1 ? 0 : -1;
}
int main(int argc, char *argv[]) {
return CombineAsciiMarks(stdin, stdout) != -1 ? 0 : errno;
}

265
tool/viz/basicidea.c Normal file
View file

@ -0,0 +1,265 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "dsp/core/core.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/calls/hefty/spawn.h"
#include "libc/calls/ioctl.h"
#include "libc/calls/struct/winsize.h"
#include "libc/dce.h"
#include "libc/fmt/fmt.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/math.h"
#include "libc/mem/mem.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/exit.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/ok.h"
#include "libc/sysv/consts/termios.h"
#include "libc/x/x.h"
#define SQR(X) ((X) * (X))
#define DIST(X, Y) ((X) - (Y))
static int want24bit_;
const int kXtermCube[] = {0, 0137, 0207, 0257, 0327, 0377};
static int rgbdist(int a, int b, int c, int x, int y, int z) {
return SQR(DIST(a, x)) + SQR(DIST(b, y)) + SQR(DIST(c, z));
}
static int uncube(int x) {
return x < 48 ? 0 : x < 115 ? 1 : (x - 35) / 40;
}
static int DivideIntRound(int x, int y) {
return (x + y / 2) / y;
}
static int XtermQuantizeLuma(int Y) {
return DivideIntRound(Y - 8, 10);
}
static int XtermDequantizeLuma(int qY) {
if (0 < qY && qY < 24) {
return (qY * 10) + 8;
} else if (qY > 0) {
return 255;
} else {
return 0;
}
}
static int XtermEncodeLuma(int qY) {
if (0 < qY && qY < 24) {
return qY + 232;
} else if (qY > 0) {
return 231;
} else {
return 16;
}
}
static int XtermQuantizeChroma(int c) {
return DivideIntRound(c - 55, 40);
}
static int XtermDequantizeChroma(int qc) {
if (0 < qc && qc < 6) {
return (qc * 40) + 55;
} else if (qc > 0) {
return 255;
} else {
return 0;
}
}
static int XtermEncodeChromaComponent(int qC) {
if (0 < qC && qC < 6) {
return qC;
} else if (qC > 0) {
return 5;
} else {
return 0;
}
}
static int XtermEncodeChroma(int qR, int qG, int qB) {
int xt;
xt = 16;
xt += XtermEncodeChromaComponent(qR) * 6 * 6;
xt += XtermEncodeChromaComponent(qG) * 6;
xt += XtermEncodeChromaComponent(qB) * 1;
return xt;
}
/**
* Quantizes 24-bit sRGB to xterm256 code range [16,256).
*/
static int rgb2xterm256(unsigned char R, unsigned char G, unsigned char B) {
double y, r, g, b, yr, yg, yb, ry, gy, by, gamma;
int Y, qY, cY, qRY, qGY, qBY, qR, qG, qB, cR, cG, cB, xt;
gamma = 2.4;
yr = 871024 / 4096299.;
yg = 8788810 / 12288897.;
yb = 887015 / 12288897.;
r = rgb2linpc(R / 255., gamma);
g = rgb2linpc(G / 255., gamma);
b = rgb2linpc(B / 255., gamma);
y = yr * r + yg * g + yb * b;
ry = (r - y) / (1 - yr + yg + yb);
gy = (g - y) / (1 - yg + yr + yb);
by = (b - y) / (1 - yb + yg + yr);
Y = round(rgb2stdpc(y, gamma) * 255);
qRY = round(rgb2stdpc(ry, gamma) * 6 + 3);
qGY = round(rgb2stdpc(gy, gamma) * 6 + 3);
qBY = round(rgb2stdpc(by, gamma) * 6 + 3);
qY = XtermQuantizeLuma(Y);
qR = XtermQuantizeChroma(qRY);
qG = XtermQuantizeChroma(qGY);
qB = XtermQuantizeChroma(qBY);
cY = XtermDequantizeLuma(qY);
cR = XtermDequantizeChroma(qRY);
cG = XtermDequantizeChroma(qGY);
cB = XtermDequantizeChroma(qBY);
#if 0
LOGF("RGB(%3d,%3d,%3d) rgb(%f,%f,%f) y=%f", R, G, B, r, g, b, y);
LOGF("RGB(%3d,%3d,%3d) yΔrgb(%f,%f,%f) XCUBE(%d,%d,%d)", R, G, B, ry, gy, by,
qRY, qGY, qBY);
LOGF("RGB(%3d,%3d,%3d) cRGB(%d,%d,%d) cY=%d qY=%d Y=%d", R, G, B, cR, cG, cB,
cY, qY, Y);
#endif
if (rgbdist(cR, cG, cB, R, G, B) <= rgbdist(cY, cY, cY, R, G, B)) {
xt = XtermEncodeChroma(qR, qG, qB);
} else {
xt = XtermEncodeLuma(qY);
}
/* LOGF("xt=%d", xt); */
return xt;
}
/**
* Prints raw packed 8-bit RGB data from memory.
*/
static void PrintImage(long yn, long xn, unsigned char RGB[yn][xn][4]) {
long y, x;
for (y = 0; y < yn; y += 2) {
if (y) printf("\r\n");
for (x = 0; x < xn; ++x) {
if (want24bit_) {
printf("\033[48;2;%hhu;%hhu;%hhu;38;2;%hhu;%hhu;%hhum▄",
RGB[y + 0][x][0], RGB[y + 0][x][1], RGB[y + 0][x][2],
RGB[y + 1][x][0], RGB[y + 1][x][1], RGB[y + 1][x][2]);
} else {
printf(
"\033[48;5;%hhu;38;5;%hhum▄",
rgb2xterm256(RGB[y + 0][x][0], RGB[y + 0][x][1], RGB[y + 0][x][2]),
rgb2xterm256(RGB[y + 1][x][0], RGB[y + 1][x][1], RGB[y + 1][x][2]));
}
}
}
if (IsWindows()) {
printf("\033[0m\r\n");
} else {
printf("\033[0m\r");
}
}
/**
* Determines dimensions of teletypewriter.
*/
static void GetTermSize(unsigned *out_rows, unsigned *out_cols) {
struct winsize ws;
ws.ws_row = 20;
ws.ws_col = 80;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
ioctl(STDIN_FILENO, TIOCGWINSZ, &ws);
*out_rows = ws.ws_row;
*out_cols = ws.ws_col;
}
static void ReadAll(int fd, void *buf, size_t n) {
char *p;
ssize_t rc;
size_t got;
p = buf;
do {
CHECK_NE(-1, (rc = read(fd, p, n)));
got = rc;
CHECK(!(!got && n));
p += got;
n -= got;
} while (n);
}
static void LoadImageOrDie(const char *path, size_t size, long yn, long xn,
unsigned char RGB[yn][xn][4]) {
int pid, ws, fds[3];
const char *convert;
if (isempty((convert = getenv("CONVERT"))) &&
!(IsWindows() && access((convert = "\\msys64\\mingw64\\bin\\convert.exe"),
X_OK) != -1) &&
!(convert = commandv("convert"))) {
fputs("'convert' command not found\r\n"
"please install imagemagick\r\n",
stderr);
exit(1);
}
fds[0] = STDIN_FILENO;
fds[1] = -1;
fds[2] = STDERR_FILENO;
pid = spawnve(0, fds, convert,
(char *const[]){"convert", path, "-resize",
gc(xasprintf("%ux%u!", xn, yn)), "-colorspace",
"RGB", "-depth", "8", "rgba:-", NULL},
environ);
CHECK_NE(-1, pid);
ReadAll(fds[1], RGB, size);
CHECK_NE(-1, close(fds[1]));
CHECK_NE(-1, waitpid(pid, &ws, 0));
CHECK_EQ(0, WEXITSTATUS(ws));
}
int main(int argc, char *argv[]) {
int i;
void *rgb;
size_t size;
unsigned yn, xn;
cancolor();
GetTermSize(&yn, &xn);
yn *= 2;
size = yn * xn * 4;
CHECK_NOTNULL((rgb = valloc(size)));
for (i = 1; i < argc; ++i) {
if (strcmp(argv[i], "-t") == 0) {
want24bit_ = 1;
} else {
LoadImageOrDie(argv[i], size, yn, xn, rgb);
PrintImage(yn, xn, rgb);
}
}
return 0;
}

44
tool/viz/bin2asm.c Normal file
View file

@ -0,0 +1,44 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#define COLS 8
int main(int argc, char *argv[]) {
int c, col = 0;
unsigned char ch;
char16_t glyphs[COLS + 1];
while ((c = getchar()) != -1) {
if (col == 0) {
printf("\t.byte\t");
memset(glyphs, 0, sizeof(glyphs));
}
ch = c & 0xff;
glyphs[col] = kCp437[ch];
if (col) putchar(',');
printf("0x%02x", ch);
if (++col == COLS) {
col = 0;
printf("\t#%hs\n", glyphs);
}
}
return 0;
}

93
tool/viz/bing.c Normal file
View file

@ -0,0 +1,93 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "libc/sysv/consts/fileno.h"
#include "third_party/getopt/getopt.h"
/**
* @fileoverview Bing: Binary Glyphs.
* Intended for oldskool data science.
*/
int ispipe_;
int newlines_;
noreturn void ShowUsage(FILE *f, int rc) {
fputs(program_invocation_name, f);
fputs(": [-p] [-n] [FILE...]\n", f);
exit(rc);
}
void GetOpts(int argc, char *argv[]) {
int opt;
while ((opt = getopt(argc, argv, "hpn")) != -1) {
switch (opt) {
case 'p':
ispipe_ = true;
break;
case 'n':
newlines_ = true;
break;
case 'h':
ShowUsage(stdout, EXIT_SUCCESS);
default:
ShowUsage(stderr, EX_USAGE);
}
}
}
void bing(FILE *f) {
int c, c2;
while ((c = fgetc(f)) != -1) {
c2 = c == '\n' && newlines_ ? '\n' : kCp437[c & 0xff];
if (ispipe_) {
fputc(c, stdout);
fputwc(c2, stderr);
} else {
fputwc(c2, stdout);
}
}
fputc('\n', ispipe_ ? stderr : stdout);
}
int main(int argc, char *argv[]) {
FILE *f;
size_t i;
GetOpts(argc, argv);
if (optind < argc) {
for (i = optind; i < argc; ++i) {
if (!(f = fopen(argv[i], "rb"))) {
perror(argv[i]);
exit(EXIT_FAILURE);
}
bing(f);
fclose(f);
}
} else {
bing(stdin);
}
return 0;
}

104
tool/viz/comma.c Normal file
View file

@ -0,0 +1,104 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/fmt/fmt.h"
#include "libc/log/check.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "third_party/getopt/getopt.h"
#define USAGE \
" [FLAGS] [PATH|FLEXDEC...] [<<<FLEXDEC...\\n...]\n\
Turns numbers into decimal with commas.\n\
\n\
Values are tokenized by spaces. Anything that isn't an integer is\n\
passed through. We parse integers the same way the C compiler does\n\
so 0x,0b,0,etc. prefixes are fine. Unicode spacing characters are\n\
supported.\n\
\n\
Flags:\n\
-o PATH output path\n\
-F STR\n\
-T STR sets field tokenization charset [default is whitespace]\n\
-w FLEXDEC\n\
-n FLEXDEC set fixed number of columns [default is variable, based\n\
on line breaks]\n\
-?\n\
-h shows this information\n\
\n"
static size_t linecap_;
static FILE *in_, *out_;
static const char16_t *fieldtoks_;
static char *inpath_, *outpath_, *line_;
void PrintUsage(int rc, FILE *f) {
fputs("Usage: ", f);
fputs(program_invocation_name, f);
fputs(USAGE, f);
exit(rc);
}
void GetOpts(int *argc, char *argv[]) {
int opt;
outpath_ = "-";
fieldtoks_ = u" \t\v\n\r\f  ";
while ((opt = getopt(*argc, argv, "?ho:F:T:w:n:")) != -1) {
switch (opt) {
case 'o':
outpath_ = optarg;
break;
case 'F':
case 'T':
break;
case '?':
case 'h':
PrintUsage(EXIT_SUCCESS, stdout);
default:
PrintUsage(EX_USAGE, stderr);
}
}
if (optind == *argc) {
argv[(*argc)++] = "-";
}
}
void ProcessFile(void) {
while ((getline(&line_, &linecap_, in_)) != -1) {
// TODO(jart)
}
}
int main(int argc, char *argv[]) {
size_t i;
GetOpts(&argc, argv);
CHECK_NOTNULL((out_ = fopen(outpath_, "w")));
for (i = optind; i < argc; ++i) {
CHECK_NOTNULL((in_ = fopen((inpath_ = argv[i]), "r")));
ProcessFile();
CHECK_NE(-1, fclose_s(&in_));
}
CHECK_NE(-1, fclose_s(&out_));
free(line_);
return 0;
}

322
tool/viz/cpuid.c Normal file
View file

@ -0,0 +1,322 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/log/log.h"
#include "libc/nexgen32e/cpuid4.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/nexgen32e/rdtscp.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/nexgen32e/x86info.h"
#include "libc/runtime/gc.h"
#include "libc/stdio/stdio.h"
#include "libc/time/time.h"
#include "libc/x/x.h"
#include "tool/decode/lib/idname.h"
#include "tool/decode/lib/x86idnames.h"
#define RED (cancolor() ? "\x1b[91m" : "")
#define GREEN (cancolor() ? "\x1b[32m" : "")
#define RESET (cancolor() ? "\x1b[0m" : "")
#define CANIUSE(FEATURE) caniuse(#FEATURE, X86_HAVE(FEATURE))
#define SHOW(CONSTANT) show(#CONSTANT, CONSTANT)
static void caniuse(const char *feature, bool present) {
printf("%-20s%s%s%s\n", feature, present ? GREEN : RED,
present ? "present" : "unavailable", RESET);
}
static void show(const char *constant, long value) {
printf("%-20s%#lx\n", constant, value);
}
static void showvendor(void) {
printf("%.*s%.*s%.*s", 4, &KCPUIDS(0H, EBX), 4, &KCPUIDS(0H, EDX), 4,
&KCPUIDS(0H, ECX));
}
static void showmodel(void) {
if (getx86processormodel(kX86ProcessorModelKey)) {
printf(" %s",
findnamebyid(kX86MarchNames,
getx86processormodel(kX86ProcessorModelKey)->march));
}
}
static void showspeed(void) {
if (KCPUIDS(16H, EAX)) {
printf(" %.1f%s", KCPUIDS(16H, EAX) / 1000.0, "ghz");
}
}
static void showstrata(void) {
if (getx86processormodel(kX86ProcessorModelKey)) {
printf(" (%s %s)",
findnamebyid(kX86GradeNames,
getx86processormodel(kX86ProcessorModelKey)->grade),
"Grade");
}
}
void showcachesizes(void) {
unsigned i;
CPUID4_ITERATE(i, {
printf("%-19s%s%s %u-way %,7u byte cache w/%s %,5u sets of %u byte lines "
"shared across %u threads\n",
gc(xasprintf("Level %u%s", CPUID4_CACHE_LEVEL,
CPUID4_CACHE_TYPE == 1
? " data"
: CPUID4_CACHE_TYPE == 2 ? " code" : "")),
CPUID4_IS_FULLY_ASSOCIATIVE ? " fully-associative" : "",
CPUID4_COMPLEX_INDEXING ? " complexly-indexed" : "",
CPUID4_WAYS_OF_ASSOCIATIVITY, CPUID4_CACHE_SIZE_IN_BYTES,
CPUID4_PHYSICAL_LINE_PARTITIONS > 1
? gc(xasprintf(" %u physically partitioned"))
: "",
CPUID4_NUMBER_OF_SETS, CPUID4_SYSTEM_COHERENCY_LINE_SIZE,
CPUID4_MAX_THREADS_SHARING_CACHE);
});
}
int main(int argc, char *argv[]) {
long tsc_aux;
showvendor();
showmodel();
showspeed();
showstrata();
printf("\n");
if (X86_HAVE(HYPERVISOR)) {
unsigned eax, ebx, ecx, edx;
asm("push\t%%rbx\n\t"
"cpuid\n\t"
"mov\t%%ebx,%1\n\t"
"pop\t%%rbx"
: "=a"(eax), "=rm"(ebx), "=c"(ecx), "=d"(edx)
: "0"(0x40000000), "2"(0));
printf("Running inside %.4s%.4s%.4s (eax=%#x)\n", &ebx, &ecx, &edx, eax);
}
printf("\n");
SHOW(kX86CpuStepping);
SHOW(kX86CpuModelid);
SHOW(kX86CpuFamilyid);
SHOW(kX86CpuType);
SHOW(kX86CpuExtmodelid);
SHOW(kX86CpuExtfamilyid);
printf("\n");
tsc_aux = rdpid();
show("TSC_AUX", tsc_aux);
show(" → core", TSC_AUX_CORE(tsc_aux));
show(" → node", TSC_AUX_NODE(tsc_aux));
printf("\n");
printf("Caches\n");
printf("──────\n");
showcachesizes();
printf("\n");
printf("Features\n");
printf("────────\n");
CANIUSE(ACC);
CANIUSE(ACPI);
CANIUSE(ADX);
CANIUSE(AES);
CANIUSE(APIC);
CANIUSE(ARCH_CAPABILITIES);
CANIUSE(AVX);
printf("%-20s%s%s%s%s\n", "AVX2", X86_HAVE(AVX2) ? GREEN : RED,
X86_HAVE(AVX2) ? "present" : "unavailable", RESET,
(!X86_HAVE(AVX2) && ({
unsigned eax, ebx, ecx, edx;
asm("push\t%%rbx\n\t"
"cpuid\n\t"
"mov\t%%ebx,%1\n\t"
"pop\t%%rbx"
: "=a"(eax), "=rm"(ebx), "=c"(ecx), "=d"(edx)
: "0"(7), "2"(0));
(void)eax;
(void)ecx;
(void)edx;
!!(ebx & (1u << 5));
}))
? " (disabled by operating system)"
: "");
CANIUSE(AVX512BW);
CANIUSE(AVX512CD);
CANIUSE(AVX512DQ);
CANIUSE(AVX512ER);
CANIUSE(AVX512F);
CANIUSE(AVX512IFMA);
CANIUSE(AVX512PF);
CANIUSE(AVX512VBMI);
CANIUSE(AVX512VL);
CANIUSE(AVX512_4FMAPS);
CANIUSE(AVX512_4VNNIW);
CANIUSE(AVX512_BF16);
CANIUSE(AVX512_BITALG);
CANIUSE(AVX512_VBMI2);
CANIUSE(AVX512_VNNI);
CANIUSE(AVX512_VP2INTERSECT);
CANIUSE(AVX512_VPOPCNTDQ);
CANIUSE(BMI);
CANIUSE(BMI2);
CANIUSE(CID);
CANIUSE(CLDEMOTE);
CANIUSE(CLFLUSH);
CANIUSE(CLFLUSHOPT);
CANIUSE(CLWB);
CANIUSE(CMOV);
CANIUSE(CQM);
CANIUSE(CX16);
CANIUSE(CX8);
CANIUSE(DCA);
CANIUSE(DE);
CANIUSE(DS);
CANIUSE(DSCPL);
CANIUSE(DTES64);
CANIUSE(ERMS);
CANIUSE(EST);
CANIUSE(F16C);
CANIUSE(FDP_EXCPTN_ONLY);
CANIUSE(FLUSH_L1D);
CANIUSE(FMA);
CANIUSE(FPU);
CANIUSE(FSGSBASE);
CANIUSE(FXSR);
CANIUSE(GBPAGES);
CANIUSE(GFNI);
CANIUSE(HLE);
CANIUSE(HT);
CANIUSE(HYPERVISOR);
CANIUSE(IA64);
CANIUSE(INTEL_PT);
CANIUSE(INTEL_STIBP);
CANIUSE(INVPCID);
CANIUSE(LA57);
CANIUSE(LM);
CANIUSE(MCA);
CANIUSE(MCE);
CANIUSE(MD_CLEAR);
CANIUSE(MMX);
CANIUSE(MOVBE);
CANIUSE(MOVDIR64B);
CANIUSE(MOVDIRI);
CANIUSE(MP);
CANIUSE(MPX);
CANIUSE(MSR);
CANIUSE(MTRR);
CANIUSE(MWAIT);
CANIUSE(NX);
CANIUSE(OSPKE);
CANIUSE(OSXSAVE);
CANIUSE(PAE);
CANIUSE(PAT);
CANIUSE(PBE);
CANIUSE(PCID);
CANIUSE(PCLMUL);
CANIUSE(PCONFIG);
CANIUSE(PDCM);
CANIUSE(PGE);
CANIUSE(PKU);
CANIUSE(PN);
CANIUSE(POPCNT);
CANIUSE(PSE);
CANIUSE(PSE36);
CANIUSE(RDPID);
CANIUSE(RDRND);
CANIUSE(RDSEED);
CANIUSE(RDTSCP);
CANIUSE(RDT_A);
CANIUSE(RTM);
CANIUSE(SDBG);
CANIUSE(SELFSNOOP);
CANIUSE(SEP);
CANIUSE(SHA);
CANIUSE(SMAP);
CANIUSE(SMEP);
CANIUSE(SMX);
CANIUSE(SPEC_CTRL);
CANIUSE(SPEC_CTRL_SSBD);
CANIUSE(SSE);
CANIUSE(SSE2);
CANIUSE(SSE3);
CANIUSE(SSE4_1);
CANIUSE(SSE4_2);
CANIUSE(SSSE3);
CANIUSE(SYSCALL);
CANIUSE(TM2);
CANIUSE(TME);
CANIUSE(TSC);
CANIUSE(TSC_ADJUST);
CANIUSE(TSC_DEADLINE_TIMER);
CANIUSE(TSX_FORCE_ABORT);
CANIUSE(UMIP);
CANIUSE(VAES);
CANIUSE(VME);
CANIUSE(VMX);
CANIUSE(VPCLMULQDQ);
CANIUSE(WAITPKG);
CANIUSE(X2APIC);
CANIUSE(XSAVE);
CANIUSE(XTPR);
CANIUSE(ZERO_FCS_FDS);
printf("\n");
printf("AMD Stuff\n");
printf("─────────\n");
CANIUSE(3DNOW);
CANIUSE(3DNOWEXT);
CANIUSE(3DNOWPREFETCH);
CANIUSE(ABM);
CANIUSE(BPEXT);
CANIUSE(CMP_LEGACY);
CANIUSE(CR8_LEGACY);
CANIUSE(EXTAPIC);
CANIUSE(FMA4);
CANIUSE(FXSR_OPT);
CANIUSE(IBS);
CANIUSE(LAHF_LM);
CANIUSE(LWP);
CANIUSE(MISALIGNSSE);
CANIUSE(MMXEXT);
CANIUSE(MWAITX);
CANIUSE(NODEID_MSR);
CANIUSE(OSVW);
CANIUSE(OVERFLOW_RECOV);
CANIUSE(PERFCTR_CORE);
CANIUSE(PERFCTR_LLC);
CANIUSE(PERFCTR_NB);
CANIUSE(PTSC);
CANIUSE(SKINIT);
CANIUSE(SMCA);
CANIUSE(SSE4A);
CANIUSE(SUCCOR);
CANIUSE(SVM);
CANIUSE(TBM);
CANIUSE(TCE);
CANIUSE(TOPOEXT);
CANIUSE(WDT);
CANIUSE(XOP);
return 0;
}

149
tool/viz/deathstar.c Normal file
View file

@ -0,0 +1,149 @@
#include "dsp/tty/tty.h"
#include "libc/calls/struct/termios.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/math.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/sig.h"
#include "libc/time/time.h"
#include "libc/x/x.h"
/**
* @fileoverview demo code borrowed from Rosetta Code.
*/
#define FRAMERATE 23.976
struct Sphere {
double cx, cy, cz, r;
};
const char *kShades[] = {
"\e[48;5;232m ", "\e[48;5;233m ", "\e[48;5;234m ", "\e[48;5;235m ",
"\e[48;5;236m ", "\e[48;5;237m ", "\e[48;5;238m ", "\e[48;5;239m ",
"\e[48;5;240m ", "\e[48;5;241m ", "\e[48;5;242m ", "\e[48;5;243m ",
"\e[48;5;244m ", "\e[48;5;245m ", "\e[48;5;246m ", "\e[48;5;247m ",
"\e[48;5;248m ", "\e[48;5;249m ", "\e[48;5;250m ", "\e[48;5;251m ",
"\e[48;5;252m ", "\e[48;5;253m ", "\e[48;5;254m ", "\e[48;5;255m ",
};
jmp_buf jb_;
double light_[3] = {-50, 0, 50};
struct Sphere pos_ = {20, 20, 20, 20};
struct Sphere neg_ = {1, 1, -6, 20};
static void OnCtrlC(int sig) {
longjmp(jb_, 1);
}
static void Normalize(double v[3]) {
double len;
len = 1 / sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
v[0] *= len;
v[1] *= len;
v[2] *= len;
}
static double Dot(const double x[3], const double y[3]) {
return fabs(x[0] * y[0] + x[1] * y[1] + x[2] * y[2]);
}
/* check if a ray (x,y, -inf)->(x, y, inf) hits a sphere; if so, return
the intersecting z values. z1 is closer to the eye */
static int HitSphere(struct Sphere *s, double x, double y, double z[2]) {
double zsq;
x -= s->cx;
y -= s->cy;
zsq = s->r * s->r - (x * x + y * y);
if (zsq < 0) {
return 0;
} else {
zsq = sqrt(zsq);
z[0] = s->cz - zsq;
z[1] = s->cz + zsq;
return 1;
}
}
static void DrawSphere(double k, double ambient) {
int i, j, hit_result;
double x, y, vec[3], zb[2], zs[2];
for (i = floor(pos_.cy - pos_.r); i <= ceil(pos_.cy + pos_.r); i++) {
y = i + .5;
for (j = floor(pos_.cx - 2 * pos_.r); j <= ceil(pos_.cx + 2 * pos_.r);
j++) {
x = .5 * (j - pos_.cx) + .5 + pos_.cx;
if (!HitSphere(&pos_, x, y, zb)) {
/* ray lands in blank space, draw bg */
hit_result = 0;
} else if (!HitSphere(&neg_, x, y, zs)) {
/* ray hits pos_ sphere but not neg_, draw pos_ sphere surface */
hit_result = 1;
} else if (zs[0] > zb[0]) {
/* ray hits both, but pos_ front surface is closer */
hit_result = 1;
} else if (zs[1] > zb[1]) {
/* pos_ sphere surface is inside neg_ sphere, show bg */
hit_result = 0;
} else if (zs[1] > zb[0]) {
/* back surface on neg_ sphere is inside pos_ sphere,
the only place where neg_ sphere surface will be shown */
hit_result = 2;
} else {
hit_result = 1;
}
switch (hit_result) {
case 0:
fputs("\e[0m ", stdout);
continue;
case 1:
vec[0] = x - pos_.cx;
vec[1] = y - pos_.cy;
vec[2] = zb[0] - pos_.cz;
break;
default:
vec[0] = neg_.cx - x;
vec[1] = neg_.cy - y;
vec[2] = neg_.cz - zs[1];
break;
}
Normalize(vec);
fputs(
kShades[MIN(ARRAYLEN(kShades) - 1,
MAX(0, lround((1 - (pow(Dot(light_, vec), k) + ambient)) *
(ARRAYLEN(kShades) - 1))))],
stdout);
}
fputs("\e[0m\n", stdout);
}
fflush(stdout);
}
int main() {
double ang;
struct termios old;
if (cancolor()) {
ttyhidecursor(fileno(stdout));
if (!setjmp(jb_)) {
xsigaction(SIGINT, OnCtrlC, 0, 0, NULL);
ang = 0;
for (;;) {
printf("\e[H");
light_[1] = cos(ang * 2);
light_[2] = cos(ang);
light_[0] = sin(ang);
Normalize(light_);
ang += .05;
DrawSphere(1.5, .01);
usleep(1. / FRAMERATE * 1e6);
}
}
ttyshowcursor(fileno(stdout));
return 0;
} else {
return 1;
}
}

619
tool/viz/derasterize.c Normal file
View file

@ -0,0 +1,619 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "dsp/tty/itoa8.h"
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/hefty/spawn.h"
#include "libc/calls/ioctl.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/termios.h"
#include "libc/conv/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/math.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/str/tpenc.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "libc/x/x.h"
#include "third_party/avir/lanczos.h"
#include "third_party/getopt/getopt.h"
#include "third_party/stb/stb_image.h"
#include "third_party/stb/stb_image_resize.h"
#define HELPTEXT \
"\n\
NAME\n\
\n\
derasterize - convert pictures to text using unicode ANSI art\n\
\n\
SYNOPSIS\n\
\n\
derasterize [FLAGS] [PNG|JPG|ETC]...\n\
\n\
DESCRIPTION\n\
\n\
This program converts pictures into unicode text and ANSI colors so\n\
that images can be displayed within a terminal. It performs lots of\n\
AVX2 optimized math to deliver the best quality on modern terminals\n\
with 24-bit color support, e.g. Kitty, Gnome Terminal, CMD.EXE, etc\n\
\n\
The default output if fullscreen but can be changed:\n\
-w X\n\
-x X\n\
If X is positive, hardcode the width in tty cells to X\n\
If X is negative, remove as much from the fullscreen width\n\
X may be specified as base 10 decimal, octal, binary, or hex\n\
-h Y\n\
-y Y\n\
If Y is positive, hardcode the height in tty cells to Y\n\
If Y is negative, remove as much from the fullscreen height\n\
May be specified as base 10 decimal, octal, binary, or hex\n\
-m\n\
Use ImageMagick `convert` command to load/scale graphics\n\
-?\n\
-H\n\
Show this help information\n\
\n\
EXAMPLES\n\
\n\
$ ./derasterize.com samples/wave.png > wave.uaart\n\
$ cat wave.uaart\n\
\n\
AUTHORS\n\
\n\
Csdvrx <csdvrx@outlook.com>\n\
Justine Tunney <jtunney@gmail.com>\n\
"
int m_; /* -m [use imagemagick] */
int x_; /* -x WIDTH [in flexidecimal] */
int y_; /* -y HEIGHT [in flexidecimal] */
#define BEST 0
#define FAST 1
#define FASTER 2
#define MODE BEST
#if MODE == BEST
#define MC 9u /* log2(#) of color combos to consider */
#define GN 35u /* # of glyphs to consider */
#elif MODE == FAST
#define MC 6u
#define GN 35u
#elif MODE == FASTER
#define MC 4u
#define GN 25u
#endif
#define CN 3u /* # channels (rgb) */
#define YS 8u /* row stride -or- block height */
#define XS 4u /* column stride -or- block width */
#define GT 44u /* total glyphs */
#define BN (YS * XS) /* # scalars in block/glyph plane */
#define PHIPRIME 0x9E3779B1u
extern const uint32_t kGlyphs[];
extern const char16_t kRunes[];
/*───────────────────────────────────────────────────────────────────────────│─╗
derasterize § encoding
*/
/**
* Formats Thompson-Pike variable length integer to array.
*
* @param p needs at least 8 bytes
* @return p + number of bytes written, cf. mempcpy
* @note no NUL-terminator is added
*/
static char *tptoa(char *p, wchar_t x) {
unsigned long w;
for (w = tpenc(x); w; w >>= 010) *p++ = w & 0xff;
return p;
}
/*───────────────────────────────────────────────────────────────────────────│─╗
derasterize § colors
*/
static float frgb2lin(float x) {
float r1, r2;
r1 = x / 12.92f;
r2 = pow((x + 0.055) / (1 + 0.055), 2.4);
return x < 0.04045f ? r1 : r2;
}
static float frgb2std(float x) {
float r1, r2;
r1 = x * 12.92f;
r2 = 1.055 * pow(x, 1 / 2.4) - 0.055;
return x < 0.0031308f ? r1 : r2;
}
/**
* Converts 8-bit RGB samples to floating point.
*/
static void rgb2float(unsigned n, float *f, const unsigned char *u) {
unsigned i;
for (i = 0; i < n; ++i) f[i] = u[i];
for (i = 0; i < n; ++i) f[i] /= 255;
}
/**
* Converts floating point RGB samples to 8-bit.
*/
static void float2rgb(unsigned n, unsigned char *u, float *f) {
unsigned i;
for (i = 0; i < n; ++i) f[i] *= 256;
for (i = 0; i < n; ++i) f[i] = roundf(f[i]);
for (i = 0; i < n; ++i) u[i] = MAX(0, MIN(255, f[i]));
}
/**
* Converts standard RGB to linear RGB.
*
* This makes subtraction look good by flattening out the bias curve
* that PC display manufacturers like to use.
*/
static noinline void rgb2lin(unsigned n, float *f, const unsigned char *u) {
unsigned i;
rgb2float(n, f, u);
for (i = 0; i < n; ++i) f[i] = frgb2lin(f[i]);
}
/**
* Converts linear RGB to standard RGB.
*/
static noinline void rgb2std(unsigned n, unsigned char *u, float *f) {
unsigned i;
for (i = 0; i < n; ++i) f[i] = frgb2std(f[i]);
float2rgb(n, u, f);
}
/*───────────────────────────────────────────────────────────────────────────│─╗
derasterize § blocks
*/
struct Cell {
char16_t rune;
unsigned char bg[CN], fg[CN];
};
/**
* Serializes ANSI background, foreground, and UNICODE glyph to wire.
*/
static char *celltoa(char *p, struct Cell cell) {
*p++ = 033;
*p++ = '[';
*p++ = '4';
*p++ = '8';
*p++ = ';';
*p++ = '2';
*p++ = ';';
p = itoa8(p, cell.bg[0]);
*p++ = ';';
p = itoa8(p, cell.bg[1]);
*p++ = ';';
p = itoa8(p, cell.bg[2]);
*p++ = ';';
*p++ = '3';
*p++ = '8';
*p++ = ';';
*p++ = '2';
*p++ = ';';
p = itoa8(p, cell.fg[0]);
*p++ = ';';
p = itoa8(p, cell.fg[1]);
*p++ = ';';
p = itoa8(p, cell.fg[2]);
*p++ = 'm';
p = tptoa(p, cell.rune);
return p;
}
/**
* Picks 2**MC unique (bg,fg) pairs from product of lb.
*/
static unsigned combinecolors(unsigned char bf[1u << MC][2],
const unsigned char bl[CN][YS * XS]) {
uint64_t hv, ht[(1u << MC) * 2];
unsigned i, j, n, b, f, h, hi, bu, fu;
memset(ht, 0, sizeof(ht));
for (n = b = 0; b < BN && n < (1u << MC); ++b) {
bu = bl[2][b] << 020 | bl[1][b] << 010 | bl[0][b];
hi = 0;
hi = (((bu >> 000) & 0xff) + hi) * PHIPRIME;
hi = (((bu >> 010) & 0xff) + hi) * PHIPRIME;
hi = (((bu >> 020) & 0xff) + hi) * PHIPRIME;
for (f = b + 1; f < BN && n < (1u << MC); ++f) {
fu = bl[2][f] << 020 | bl[1][f] << 010 | bl[0][f];
h = hi;
h = (((fu >> 000) & 0xff) + h) * PHIPRIME;
h = (((fu >> 010) & 0xff) + h) * PHIPRIME;
h = (((fu >> 020) & 0xff) + h) * PHIPRIME;
h = h & 0xffff;
h = MAX(1, h);
hv = 0;
hv <<= 030;
hv |= fu;
hv <<= 030;
hv |= bu;
hv <<= 020;
hv |= h;
for (i = 0;; ++i) {
j = (h + i * (i + 1) / 2) & (ARRAYLEN(ht) - 1);
if (!ht[j]) {
ht[j] = hv;
bf[n][0] = b;
bf[n][1] = f;
n++;
break;
} else if (ht[j] == hv) {
break;
}
}
}
}
return n;
}
/**
* Computes distance between synthetic block and actual.
*/
#define ADJUDICATE(SYMBOL, ARCH) \
ARCH static float SYMBOL(unsigned b, unsigned f, unsigned g, \
const float lb[CN][YS * XS]) { \
unsigned i, k, gu; \
float p[BN], q[BN], fu, bu, r; \
memset(q, 0, sizeof(q)); \
for (k = 0; k < CN; ++k) { \
gu = kGlyphs[g]; \
bu = lb[k][b]; \
fu = lb[k][f]; \
for (i = 0; i < BN; ++i) p[i] = (gu & (1u << i)) ? fu : bu; \
for (i = 0; i < BN; ++i) p[i] -= lb[k][i]; \
for (i = 0; i < BN; ++i) p[i] *= p[i]; \
for (i = 0; i < BN; ++i) q[i] += p[i]; \
} \
r = 0; \
for (i = 0; i < BN; ++i) q[i] = sqrtf(q[i]); \
for (i = 0; i < BN; ++i) r += q[i]; \
return r; \
}
ADJUDICATE(adjudicate$avx2, microarchitecture("avx2,fma"))
ADJUDICATE(adjudicate$avx, microarchitecture("avx"))
ADJUDICATE(adjudicate$default, )
static float (*adjudicate$hook)(unsigned, unsigned, unsigned,
const float[CN][YS * XS]);
static float adjudicate2(unsigned b, unsigned f, unsigned g,
const float lb[CN][YS * XS]) {
if (!adjudicate$hook) {
if (X86_HAVE(AVX2) && X86_HAVE(FMA)) {
adjudicate$hook = adjudicate$avx2;
} else if (X86_HAVE(AVX)) {
adjudicate$hook = adjudicate$avx;
} else {
adjudicate$hook = adjudicate$default;
}
}
return adjudicate$hook(b, f, g, lb);
}
static float adjudicate(unsigned b, unsigned f, unsigned g,
const float lb[CN][YS * XS]) {
unsigned i, k, gu;
float p[BN], q[BN], fu, bu, r;
memset(q, 0, sizeof(q));
for (k = 0; k < CN; ++k) {
gu = kGlyphs[g];
bu = lb[k][b];
fu = lb[k][f];
for (i = 0; i < BN; ++i) p[i] = (gu & (1u << i)) ? fu : bu;
for (i = 0; i < BN; ++i) p[i] -= lb[k][i];
for (i = 0; i < BN; ++i) p[i] *= p[i];
for (i = 0; i < BN; ++i) q[i] += p[i];
}
r = 0;
for (i = 0; i < BN; ++i) q[i] = sqrtf(q[i]);
for (i = 0; i < BN; ++i) r += q[i];
return r;
}
/**
* Converts tiny bitmap graphic into unicode glyph.
*/
static struct Cell derasterize(unsigned char block[CN][YS * XS]) {
struct Cell cell;
unsigned i, n, b, f, g;
float r, best, lb[CN][YS * XS];
unsigned char bf[1u << MC][2];
rgb2lin(CN * YS * XS, lb[0], block[0]);
n = combinecolors(bf, block);
best = -1u;
cell.rune = 0;
for (i = 0; i < n; ++i) {
b = bf[i][0];
f = bf[i][1];
for (g = 0; g < GN; ++g) {
r = adjudicate(b, f, g, lb);
if (r < best) {
best = r;
cell.rune = kRunes[g];
cell.bg[0] = block[0][b];
cell.bg[1] = block[1][b];
cell.bg[2] = block[2][b];
cell.fg[0] = block[0][f];
cell.fg[1] = block[1][f];
cell.fg[2] = block[2][f];
if (!r) return cell;
}
}
}
return cell;
}
/*───────────────────────────────────────────────────────────────────────────│─╗
derasterize § graphics
*/
/**
* Turns packed 8-bit RGB graphic into ANSI UNICODE text.
*/
static char *RenderImage(char *v, unsigned yn, unsigned xn,
const unsigned char srgb[yn][YS][xn][XS][CN]) {
unsigned y, x, i, j, k;
unsigned char copy[YS][XS][CN] aligned(32);
unsigned char block[CN][YS * XS] aligned(32);
DCHECK_ALIGNED(32, v);
DCHECK_ALIGNED(32, srgb);
for (y = 0; y < yn; ++y) {
if (y) {
*v++ = 033;
*v++ = '[';
*v++ = '0';
*v++ = 'm';
*v++ = '\n';
}
for (x = 0; x < xn; ++x) {
for (i = 0; i < YS; ++i) {
memcpy(copy[i], srgb[y][i][x], XS * CN);
}
for (i = 0; i < YS; ++i) {
for (j = 0; j < XS; ++j) {
for (k = 0; k < CN; ++k) {
block[k][i * XS + j] = copy[i][j][k];
}
}
}
v = celltoa(v, derasterize(block));
}
}
return v;
}
/*───────────────────────────────────────────────────────────────────────────│─╗
derasterize § systems
*/
static void PrintImage(unsigned yn, unsigned xn,
const unsigned char rgb[yn][YS][xn][XS][CN]) {
size_t size;
char *v, *vt;
size = yn * (xn * (32 + (2 + (1 + 3) * 3) * 2 + 1 + 3)) * 1 + 5 + 1;
size = ROUNDUP(size, FRAMESIZE);
CHECK_NE(MAP_FAILED, (vt = mapanon(size)));
v = RenderImage(vt, yn, xn, rgb);
*v++ = '\r';
*v++ = 033;
*v++ = '[';
*v++ = '0';
*v++ = 'm';
CHECK_NE(-1, xwrite(1, vt, v - vt));
CHECK_NE(-1, munmap(vt, size));
}
/**
* Determines dimensions of teletypewriter.
*/
static void GetTermSize(unsigned out_rows[1], unsigned out_cols[1]) {
struct winsize ws;
ws.ws_row = 24;
ws.ws_col = 80;
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) {
ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
}
out_rows[0] = ws.ws_row;
out_cols[0] = ws.ws_col;
}
static int ReadAll(int fd, void *data, size_t size) {
char *p;
ssize_t rc;
size_t got, n;
p = data;
n = size;
do {
if ((rc = read(fd, p, n)) == -1) return -1;
assert((got = rc) || !n);
p += got;
n -= got;
} while (n);
return 0;
}
/**
* Loads and scales image via ImageMagick `convert` command.
*
* @param path is filename of graphic
* @param yn is desired height
* @param xn is desired width
* @param rgb is memory allocated by caller for image
*/
static void LoadFileViaImageMagick(const char *path, unsigned yn, unsigned xn,
unsigned char rgb[yn][YS][xn][XS][CN]) {
const char *convert;
int pid, ws, fds[3] = {STDIN_FILENO, -1, STDERR_FILENO};
if (!(convert = commandv("convert"))) {
fputs("error: `convert` command not found\n"
"try: apt-get install imagemagick\n",
stderr);
exit(EXIT_FAILURE);
}
CHECK_NE(-1,
(pid = spawnve(
0, fds, convert,
(char *const[]){"convert", path, "-resize",
xasprintf("%ux%u!", xn * XS, yn * YS), "-depth",
"8", "-colorspace", "sRGB", "rgb:-", NULL},
environ)));
CHECK_NE(-1, ReadAll(fds[STDOUT_FILENO], rgb, yn * YS * xn * XS * CN));
CHECK_NE(-1, close(fds[STDOUT_FILENO]));
CHECK_NE(-1, waitpid(pid, &ws, 0));
CHECK_EQ(0, WEXITSTATUS(ws));
}
static void LoadFile(const char *path, size_t yn, size_t xn, void *rgb) {
struct stat st;
size_t data2size, data3size;
void *map, *data, *data2, *data3;
int fd, gotx, goty, channels_in_file;
CHECK_NE(-1, (fd = open(path, O_RDONLY)), "%s", path);
CHECK_NE(-1, fstat(fd, &st));
CHECK_GT(st.st_size, 0);
CHECK_LE(st.st_size, INT_MAX);
LOGIFNEG1(fadvise(fd, 0, 0, MADV_WILLNEED | MADV_SEQUENTIAL));
CHECK_NE(MAP_FAILED,
(map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)));
CHECK_NOTNULL((data = stbi_load_from_memory(map, st.st_size, &gotx, &goty,
&channels_in_file, CN)),
"%s", path);
CHECK_NE(-1, munmap(map, st.st_size));
CHECK_NE(-1, close(fd));
#if 1
stbir_resize_uint8(data, gotx, goty, 0, rgb, xn * XS, yn * YS, 0, CN);
#else
CHECK_EQ(CN, 3);
data2size = ROUNDUP(sizeof(float) * goty * gotx * CN, FRAMESIZE);
data3size = ROUNDUP(sizeof(float) * yn * YS * xn * XS * CN, FRAMESIZE);
CHECK_NE(MAP_FAILED, (data2 = mapanon(data2size)));
CHECK_NE(MAP_FAILED, (data3 = mapanon(data3size)));
rgb2lin(goty * gotx * CN, data2, data);
lanczos3(yn * YS, xn * XS, data3, goty, gotx, data2, gotx * 3);
rgb2std(yn * YS * xn * XS * CN, rgb, data3);
CHECK_NE(-1, munmap(data2, data2size));
CHECK_NE(-1, munmap(data3, data3size));
#endif
free(data);
}
static int ParseNumberOption(const char *arg) {
long x;
x = strtol(arg, NULL, 0);
if (!(1 <= x && x <= INT_MAX)) {
fprintf(stderr, "invalid flexidecimal: %s\n\n", arg);
exit(EXIT_FAILURE);
}
return x;
}
static void PrintUsage(int rc, FILE *f) {
fputs(HELPTEXT, f);
exit(rc);
}
static void GetOpts(int argc, char *argv[]) {
int opt;
while ((opt = getopt(argc, argv, "?Hmx:y:w:h:")) != -1) {
switch (opt) {
case 'w':
case 'x':
x_ = ParseNumberOption(optarg);
break;
case 'h':
case 'y':
y_ = ParseNumberOption(optarg);
break;
case 'm':
m_ = 1;
break;
case '?':
case 'H':
PrintUsage(EXIT_SUCCESS, stdout);
default:
PrintUsage(EX_USAGE, stderr);
}
}
}
int main(int argc, char *argv[]) {
int i;
void *rgb;
size_t size;
char *option;
unsigned yd, xd;
__fast_math();
showcrashreports();
cancolor();
GetOpts(argc, argv);
// if sizes are given, 2 cases:
// - positive values: use that as the target size
// - negative values: add, for ex to offset the command prompt size
GetTermSize(&yd, &xd);
if (y_ <= 0) {
y_ += yd;
}
if (x_ <= 0) {
x_ += xd;
}
// FIXME: on the conversion stage should do 2Y because of halfblocks
// printf( "filename >%s<\tx >%d<\ty >%d<\n\n", filename, x_, y_);
size = y_ * YS * x_ * XS * CN;
CHECK_NE(MAP_FAILED, (rgb = mapanon(ROUNDUP(size, FRAMESIZE))));
for (i = optind; i < argc; ++i) {
if (!argv[i]) continue;
if (m_) {
LoadFileViaImageMagick(argv[i], y_, x_, rgb);
} else {
LoadFile(argv[i], y_, x_, rgb);
}
PrintImage(y_, x_, rgb);
}
munmap(rgb, ROUNDUP(size, FRAMESIZE));
return 0;
}

43
tool/viz/double2int.c Normal file
View file

@ -0,0 +1,43 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/conv/conv.h"
#include "libc/limits.h"
#include "libc/macros.h"
#include "libc/runtime/gc.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/x/x.h"
#include "third_party/dtoa/dtoa.h"
void double2int(const char *s) {
double b64;
uint64_t u64;
b64 = strtod(s, NULL);
memcpy(&u64, &b64, 8);
printf("0x%016lx\n", u64);
}
int main(int argc, char *argv[]) {
int i;
for (i = 1; i < argc; ++i) {
double2int(argv[i]);
}
return 0;
}

85
tool/viz/fold.c Normal file
View file

@ -0,0 +1,85 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/safemacros.h"
#include "libc/conv/conv.h"
#include "libc/errno.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "third_party/getopt/getopt.h"
int column_;
noreturn void usage(int rc, FILE *f) {
fputs("Usage: ", f);
fputs(program_invocation_name, f);
fputs(" [-w COLS] [FILE...]\n", f);
exit(rc);
}
void getopts(int argc, char *argv[]) {
int opt;
while ((opt = getopt(argc, argv, "?hw:")) != -1) {
switch (opt) {
case 'w':
column_ = strtol(optarg, NULL, 0);
break;
case '?':
case 'h':
usage(EXIT_SUCCESS, stdout);
default:
usage(EX_USAGE, stderr);
}
}
if (column_ <= 0) {
column_ = 64;
}
}
void fold(FILE *fin, FILE *fout) {
unsigned column = 0;
for (;;) {
wint_t wc = fgetwc(fin);
if (wc != -1) {
fputwc(wc, fout);
if (wc == '\n') {
column = 0;
} else if (++column == column_) {
fputc('\n', fout);
column = 0;
}
} else {
if (feof(fin)) {
return;
} else {
fprintf(stderr, "%s: %d\n", "fgetwc", errno);
exit(1);
}
}
}
}
int main(int argc, char *argv[]) {
getopts(argc, argv);
fold(stdin, stdout);
return 0;
}

314
tool/viz/generatematrix.c Normal file
View file

@ -0,0 +1,314 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/safemacros.h"
#include "libc/conv/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/math.h"
#include "libc/mem/mem.h"
#include "libc/rand/lcg.h"
#include "libc/rand/rand.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "libc/x/x.h"
#include "third_party/dtoa/dtoa.h"
#include "third_party/getopt/getopt.h"
#include "tool/viz/lib/formatstringtable.h"
typedef double (*round_f)(double);
typedef unsigned long (*rand_f)(void);
struct Range {
double a;
double b;
};
short xn_ = 8;
short yn_ = 8;
double digs_ = 6;
rand_f rand_;
round_f rounder_;
const char *path_ = "-";
const char *name_ = "M";
const char *type_ = "float";
struct Range r1_ = {LONG_MIN, LONG_MAX};
struct Range r2_ = {0, 1};
StringTableFormatter *formatter_ = FormatStringTableAsCode;
static noreturn void PrintUsage(int rc, FILE *f) {
fprintf(f, "Usage: %s%s", program_invocation_name, "\
[FLAGS] [FILE]\n\
\n\
Flags:\n\
-u unsigned\n\
-c char\n\
-s short\n\
-i int\n\
-l long\n\
-d double\n\
-b bytes [-uc]\n\
-g non-deterministic rng\n\
-S output assembly\n\
-W output whitespace\n\
-o PATH output path\n\
-x FLEX\n\
-w FLEX width\n\
-y FLEX\n\
-h FLEX height\n\
-N NAME name\n\
-T NAME type name\n\
-A FLEX min value\n\
-B FLEX max value\n\
-R FUNC round function for indexing\n\
-D FLEX decimal digits to printout\n\
-v increases verbosity\n\
-? shows this information\n\
\n");
exit(rc);
}
static bool StringEquals(const char *a, const char *b) {
return strcasecmp(a, b) == 0;
}
static noreturn void ShowInvalidArg(const char *name, const char *s,
const char *type) {
fprintf(stderr, "error: invalid %s %s: %s\n", type, name, s);
exit(EXIT_FAILURE);
}
static double ParseFlexidecimalOrDie(const char *name, const char *s,
double min, double max) {
double x;
s = firstnonnull(s, "NULL");
if (strchr(s, '.') || strchr(s, 'e')) {
x = strtod(s, NULL);
} else {
x = strtol(s, NULL, 0);
}
if (min <= x && x <= max) {
return x;
} else {
ShowInvalidArg(name, s, "flexidecimal");
}
}
static round_f ParseRoundingFunctionOrDie(const char *s) {
if (isempty(s) || StringEquals(s, "none") || StringEquals(s, "null")) {
return NULL;
} else if (StringEquals(s, "round")) {
return round;
} else if (StringEquals(s, "rint")) {
return rint;
} else if (StringEquals(s, "nearbyint")) {
return nearbyint;
} else if (StringEquals(s, "trunc")) {
return trunc;
} else if (StringEquals(s, "floor")) {
return floor;
} else if (StringEquals(s, "ceil")) {
return ceil;
} else {
ShowInvalidArg("round", s, "func");
}
}
static void ConfigureIntegralRange(const char *type, long min, long max) {
type_ = type;
r1_.a = min;
r1_.b = max;
r2_.a = min;
r2_.b = max;
if (!rounder_) rounder_ = round;
}
void GetOpts(int argc, char *argv[]) {
int opt;
bool want_unsigned, want_char, want_short, want_int, want_long, want_double;
want_unsigned = false;
want_char = false;
want_short = false;
want_int = false;
want_long = false;
want_double = false;
if (argc == 2 &&
(StringEquals(argv[1], "--help") || StringEquals(argv[1], "-help"))) {
PrintUsage(EXIT_SUCCESS, stdout);
}
while ((opt = getopt(argc, argv, "?vubcsildgSWo:x:w:y:h:N:A:B:C:E:T:R:D:")) !=
-1) {
switch (opt) {
case 'b':
want_unsigned = true;
want_char = true;
break;
case 'u':
want_unsigned = true;
break;
case 'c':
want_char = true;
break;
case 's':
want_short = true;
break;
case 'i':
want_int = true;
break;
case 'l':
want_long = true;
break;
case 'd':
want_double = true;
break;
case 'g':
rand_ = rand64;
break;
case 'N':
name_ = optarg;
break;
case 'o':
path_ = optarg;
break;
case 'S':
formatter_ = FormatStringTableAsAssembly;
break;
case 'W':
formatter_ = FormatStringTableBasic;
break;
case 't':
type_ = optarg;
break;
case 'x':
case 'w':
xn_ = ParseFlexidecimalOrDie("width", optarg, 1, SHRT_MAX);
break;
case 'y':
case 'h':
yn_ = ParseFlexidecimalOrDie("height", optarg, 1, SHRT_MAX);
break;
case 'D':
digs_ = ParseFlexidecimalOrDie("digs", optarg, 0, 15.95);
break;
case 'r':
rounder_ = ParseRoundingFunctionOrDie(optarg);
break;
case 'A':
r1_.a = ParseFlexidecimalOrDie("r1_.a", optarg, INT_MIN, INT_MAX);
break;
case 'B':
r1_.b = ParseFlexidecimalOrDie("r1_.b", optarg, INT_MIN, INT_MAX);
break;
case 'C':
r2_.a = ParseFlexidecimalOrDie("r2_.a", optarg, INT_MIN, INT_MAX);
break;
case 'E':
r2_.b = ParseFlexidecimalOrDie("r2_.b", optarg, INT_MIN, INT_MAX);
break;
case '?':
PrintUsage(EXIT_SUCCESS, stdout);
default:
PrintUsage(EX_USAGE, stderr);
}
}
if (want_unsigned && want_char) {
ConfigureIntegralRange("unsigned char", 0, 255);
} else if (want_char) {
ConfigureIntegralRange("signed char", -128, 127);
} else if (want_unsigned && want_short) {
ConfigureIntegralRange("unsigned short", USHRT_MIN, USHRT_MAX);
} else if (want_short) {
ConfigureIntegralRange("short", SHRT_MIN, SHRT_MAX);
} else if (want_unsigned && want_int) {
ConfigureIntegralRange("unsigned", UINT_MIN, UINT_MAX);
} else if (want_int) {
ConfigureIntegralRange("int", INT_MIN, INT_MAX);
} else if (want_unsigned && want_long) {
ConfigureIntegralRange("unsigned long", ULONG_MIN, ULONG_MAX);
} else if (want_long) {
ConfigureIntegralRange("long", LONG_MIN, LONG_MAX);
} else if (want_double) {
type_ = "double";
r1_.a = LONG_MIN;
r1_.b = LONG_MAX;
digs_ = 19;
}
}
static void *SetRandom(long n, long p[n]) {
long i;
uint64_t r;
if (rand_) {
for (r = 1, i = 0; i < n; ++i) {
p[i] = rand_();
}
} else {
for (r = 1, i = 0; i < n; ++i) {
p[i] = KnuthLinearCongruentialGenerator(&r) >> 32 |
KnuthLinearCongruentialGenerator(&r) >> 32 << 32;
}
}
return p;
}
static double ConvertRange(double x, double a, double b, double c, double d) {
return (d - c) / (b - a) * (x - a) + c;
}
static double Compand(long x, double a, double b, double c, double d) {
return ConvertRange(ConvertRange(x, LONG_MIN, LONG_MAX, a, b), a, b, c, d);
}
static void GenerateMatrixImpl(long I[yn_][xn_], double M[yn_][xn_], FILE *f) {
long y, x;
for (y = 0; y < yn_; ++y) {
for (x = 0; x < xn_; ++x) {
M[y][x] = Compand(I[y][x], r1_.a, r1_.b, r2_.a, r2_.b);
}
if (rounder_) {
for (x = 0; x < xn_; ++x) {
M[y][x] = rounder_(M[y][x]);
}
}
}
FormatMatrixDouble(yn_, xn_, M, fputs, f, formatter_, type_, name_, NULL,
digs_, round);
}
void GenerateMatrix(FILE *f) {
GenerateMatrixImpl(SetRandom(yn_ * xn_, gc(calloc(yn_ * xn_, sizeof(long)))),
gc(calloc(yn_ * xn_, sizeof(double))), f);
}
int main(int argc, char *argv[]) {
int i;
FILE *f;
showcrashreports();
GetOpts(argc, argv);
CHECK_NOTNULL((f = fopen(path_, "w")));
if (optind < argc) FATALF("TODO(jart): support input files");
GenerateMatrix(f);
return fclose(f);
}

View file

@ -0,0 +1,63 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/runtime/gc.h"
#include "libc/str/str.h"
#include "libc/x/x.h"
#include "third_party/stb/stb_image_write.h"
#define YN (1080 / YM)
#define XN (1920 / XM)
#define YM 2
#define XM 2
void *GenerateTortureImage(unsigned char RGB[YN][YM][XN][XM][3]) {
long y, x, i, j, b, r, g;
for (y = 0; y < YN; ++y) {
for (x = 0; x < XN; ++x) {
if ((y & 1) ^ (x & 1)) {
r = 255;
g = 255;
b = 0;
} else {
r = 0;
g = 0;
b = 255;
}
for (i = 0; i < YM; ++i) {
for (j = 0; j < XM; ++j) {
RGB[y][i][x][j][0] = r;
RGB[y][i][x][j][1] = g;
RGB[y][i][x][j][2] = b;
}
}
}
}
return RGB;
}
int main(int argc, char *argv[]) {
stbi_write_png(
gc(xasprintf("maxwell_%dx%d_%dx%d.png", XN * XM, YN * YM, XM, YM)),
XN * XM, YN * YM, 3,
GenerateTortureImage(
gc(xmemalign(32, sizeof(unsigned char) * XN * XM * YN * YM * 3))),
XN * XM * 3);
return 0;
}

82
tool/viz/int2float.c Normal file
View file

@ -0,0 +1,82 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/conv/conv.h"
#include "libc/limits.h"
#include "libc/macros.h"
#include "libc/runtime/gc.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/x/x.h"
float b32;
double b64;
long double b80;
uint32_t u32;
uint64_t u64;
intmax_t x;
void int2float(const char *s) {
x = strtoimax(s, NULL, 0);
if ((0 <= x && x <= UINT32_MAX) && !startswith(s, "-") &&
(!endswith(s, "l") && !endswith(s, "L"))) {
u32 = x;
memcpy(&b32, &u32, 4);
s = gc(xdtoa(b32));
if (!strchr(s, '.')) s = gc(xasprintf("%s.", s));
s = gc(xasprintf("%sf", s));
puts(s);
} else if ((0 <= x && x <= UINT64_MAX) && !startswith(s, "-")) {
u64 = x;
memcpy(&b64, &u64, 8);
s = gc(xdtoa(b64));
if (!strchr(s, '.')) s = gc(xasprintf("%s.", s));
puts(s);
} else if ((INT32_MIN <= x && x <= 0) &&
(!endswith(s, "l") && !endswith(s, "L"))) {
u32 = ABS(x);
memcpy(&b32, &u32, 4);
b32 = -b32;
s = gc(xdtoa(b32));
if (!strchr(s, '.')) s = gc(xasprintf("%s.", s));
s = gc(xasprintf("%sf", s));
puts(s);
} else if (INT64_MIN <= x && x <= 0) {
u64 = ABS(x);
memcpy(&b64, &u64, 8);
b64 = -b64;
s = gc(xdtoa(b64));
if (!strchr(s, '.')) s = gc(xasprintf("%s.", s));
puts(s);
} else {
memcpy(&b80, &x, 16);
s = gc(xdtoa(b80));
if (!strchr(s, '.')) s = gc(xasprintf("%s.", s));
s = gc(xasprintf("%sL", s));
puts(s);
}
}
int main(int argc, char *argv[]) {
int i;
for (i = 1; i < argc; ++i) {
int2float(argv[i]);
}
return 0;
}

115
tool/viz/invertblocks.c Normal file
View file

@ -0,0 +1,115 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/log/check.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "third_party/getopt/getopt.h"
static FILE *fi_, *fo_;
static char *inpath_, *outpath_;
noreturn void usage(int rc, FILE *f) {
fprintf(f, "%s%s%s\n", "Usage: ", program_invocation_name,
" [-o FILE] [FILE...]\n");
exit(rc);
}
void getopts(int *argc, char *argv[]) {
int opt;
outpath_ = "-";
while ((opt = getopt(*argc, argv, "?ho:")) != -1) {
switch (opt) {
case 'o':
outpath_ = optarg;
break;
case '?':
case 'h':
usage(EXIT_SUCCESS, stdout);
default:
usage(EX_USAGE, stderr);
}
}
if (optind == *argc) {
argv[(*argc)++] = "-";
}
}
void processfile(void) {
wint_t wc;
while ((wc = fgetwc(fi_)) != -1) {
switch (wc) {
case L'':
wc = L' ';
break;
case L'':
wc = L'';
break;
case L'':
wc = L'';
break;
case L'':
wc = L'';
break;
/* █ */
case L'':
wc = L'';
break;
case L'':
wc = L'';
break;
case L'':
wc = L'';
break;
case L'':
wc = L'';
break;
case L'':
wc = L'';
break;
case L'':
wc = L'';
break;
case L'':
wc = L'';
break;
case L'':
wc = L'';
break;
default:
break;
}
fputwc(wc, fo_);
}
}
int main(int argc, char *argv[]) {
size_t i;
getopts(&argc, argv);
CHECK_NOTNULL((fo_ = fopen(outpath_, "w")));
for (i = optind; i < argc; ++i) {
CHECK_NOTNULL((fi_ = fopen((inpath_ = argv[i]), "r")));
processfile();
CHECK_NE(-1, fclose_s(&fi_));
}
CHECK_NE(-1, fclose_s(&fo_));
return 0;
}

View file

@ -0,0 +1,41 @@
#ifndef COSMOPOLITAN_TOOL_VIZ_LIB_ANSITRINSICS_H_
#define COSMOPOLITAN_TOOL_VIZ_LIB_ANSITRINSICS_H_
#include "libc/limits.h"
#include "libc/macros.h"
#include "libc/str/str.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
static unsigned char avgb(unsigned char a, unsigned char b) {
return (a + b + 1) / 2;
}
static void pavgb(const unsigned char *restrict c,
const unsigned char *restrict b, unsigned char *restrict a) {
unsigned i;
for (i = 0; i < 16; ++i) a[i] = avgb(c[i], b[i]);
}
static void vpavgb(const unsigned char *restrict c,
const unsigned char *restrict b, unsigned char *restrict a) {
unsigned i;
for (i = 0; i < 32; ++i) a[i] = avgb(c[i], b[i]);
}
static void paddsw(const short c[8], const short b[8], short a[8]) {
size_t j;
for (j = 0; j < 8; ++j) {
a[j] = MIN(SHRT_MAX, MAX(SHRT_MIN, b[j] + c[j]));
}
}
static void vpaddsw(const short c[16], const short b[16], short a[16]) {
size_t j;
for (j = 0; j < 16; ++j) {
a[j] = MAX(SHRT_MIN, MIN(SHRT_MAX, b[j] + c[j]));
}
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_VIZ_LIB_ANSITRINSICS_H_ */

View file

@ -0,0 +1,101 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "dsp/core/twixt8.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/math.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/runtime/gc.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
#include "libc/tinymath/emod.h"
#include "libc/x/x.h"
#include "tool/viz/lib/bilinearscale.h"
static void ComputeScalingSolution(long dn, long sn, double r, double o,
unsigned char pct[dn + 1], int idx[dn + 1]) {
long i;
double x;
o -= .5;
o += (r - 1) / 2;
for (i = 0; i < dn + 1; ++i) {
x = o + i * r;
idx[i] = MIN(sn - 1, MAX(0, lround(x)));
pct[i] = lround((x - idx[i]) * 255) % 256;
}
}
static void BilinearScaler(long dcw, long dyw, long dxw,
unsigned char dst[dcw][dyw][dxw], long scw, long syw,
long sxw, const unsigned char src[scw][syw][sxw],
long c0, long cn, long dyn, long dxn, long syn,
long sxn, double ry, double rx, double oy, double ox,
int iy[dyn + 1], unsigned char py[dyn + 1],
int ix[dxn + 1], unsigned char px[dxn + 1],
unsigned char db[dxn], unsigned char sb[2][sxn]) {
long c, y, x, b;
ComputeScalingSolution(dxn, sxn, rx, ox, px, ix);
ComputeScalingSolution(dyn, syn, ry, oy, py, iy);
for (c = c0; c < cn; ++c) {
for (y = 0; y < dyn; ++y) {
memcpy(sb[0], src[c][iy[y + 0]], sxn);
memcpy(sb[1], src[c][iy[y + 1]], sxn);
for (x = 0; x < dxn; ++x) {
db[x] = twixt8(twixt8(sb[0][ix[x]], sb[0][ix[x + 1]], px[x]),
twixt8(sb[1][ix[x]], sb[1][ix[x + 1]], px[x]), py[y]);
}
memcpy(dst[c][y], db, dxn);
}
}
}
void *BilinearScale(long dcw, long dyw, long dxw,
unsigned char dst[dcw][dyw][dxw], long scw, long syw,
long sxw, const unsigned char src[scw][syw][sxw], long c0,
long cn, long dyn, long dxn, long syn, long sxn, double ry,
double rx, double oy, double ox) {
if (dyn > 0 && dxn > 0) {
if (syn > 0 && sxn > 0) {
DCHECK_LE(c0, cn);
DCHECK_LE(cn, scw);
DCHECK_LE(cn, dcw);
DCHECK_LE(syn, syw);
DCHECK_LE(sxn, sxw);
DCHECK_LE(dyn, dyw);
DCHECK_LE(dxn, dxw);
DCHECK_LT(bsrl(cn) + bsrl(syn) + bsrl(sxn), 32);
DCHECK_LT(bsrl(cn) + bsrl(dyn) + bsrl(dxn), 32);
BilinearScaler(dcw, dyw, dxw, dst, scw, syw, sxw, src, c0, cn, dyn, dxn,
syn, sxn, ry, rx, oy, ox,
gc(xmemalign(64, ROUNDUP(sizeof(int) * (dyn + 1), 64))),
gc(xmemalign(64, ROUNDUP(dyn + 1, 64))),
gc(xmemalign(64, ROUNDUP(sizeof(int) * (dxn + 1), 64))),
gc(xmemalign(64, ROUNDUP(dxn + 1, 64))),
gc(xmemalign(64, ROUNDUP(dxn, 64))),
gc(xmemalign(64, ROUNDUP(sxn, 64) * 2)));
} else {
memset(dst[c0], 0, &dst[cn][0][0] - &dst[c0][0][0]);
}
}
return dst;
}

View file

@ -0,0 +1,14 @@
#ifndef COSMOPOLITAN_TOOL_VIZ_LIB_BILINEARSCALE_H_
#define COSMOPOLITAN_TOOL_VIZ_LIB_BILINEARSCALE_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void *BilinearScale(long dcw, long dyw, long dxw,
unsigned char dst[dcw][dyw][dxw], long scw, long syw,
long sxw, const unsigned char src[scw][syw][sxw], long,
long, long, long, long, long, double, double, double,
double);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_VIZ_LIB_BILINEARSCALE_H_ */

30
tool/viz/lib/boxblur.c Normal file
View file

@ -0,0 +1,30 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "tool/viz/lib/convolve.h"
#include "tool/viz/lib/graphic.h"
void boxblur(struct Graphic *g) {
static const float kBoxBlurKernel[3][3] = {
{+1.0, +1.0, +1.0},
{+1.0, +1.0, +1.0},
{+1.0, +1.0, +1.0},
};
convolve(g->yn, g->xn, g->b.p, 3, kBoxBlurKernel, 9.0, 0);
}

40
tool/viz/lib/convoindex.c Normal file
View file

@ -0,0 +1,40 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/mem/mem.h"
#include "tool/viz/lib/convolution.h"
/**
* Creates padded array of array indices.
*
* This can be used to virtualize the memory of a matrix in one
* dimension, to make it easy to avoid out-of-bounds access.
*
* @return value needs free(retval - leftpad)
*/
unsigned *convoindex(unsigned leftpad, unsigned n, unsigned rightpad) {
unsigned i, j, *p;
if ((p = malloc(sizeof(unsigned) * (leftpad + n + rightpad)))) {
i = 0;
for (j = 0; j < leftpad; ++j) p[i++] = 0;
for (j = 0; j < n; ++j) p[i++] = j;
for (j = 0; j < rightpad; ++j) p[i++] = n - 1;
}
return p;
}

View file

@ -0,0 +1,67 @@
#ifndef COSMOPOLITAN_TOOL_VIZ_LIB_CONVOLUTION_H_
#define COSMOPOLITAN_TOOL_VIZ_LIB_CONVOLUTION_H_
#include "dsp/core/q.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
/* clang-format off */
#define CONVROUND(X) ((int)lrint(X))
#define CONVOLVE1X1(COEFFICIENT, DY, DX) (COEFFICIENT * (img[iy[y DY]][ix[x DX]]))
#define CONVOLVE1X12(IMG, COEFFICIENT, DY, DX) (COEFFICIENT * IMG[iy[y DY]][ix[x DX]])
#define CONVOLVE3X3(NORMALIZER, \
C00, C01, C02, \
C10, C11, C12, \
C20, C21, C22) \
(NORMALIZER * \
(CONVOLVE1X1(C00,-1,-1)+CONVOLVE1X1(C01,-1,+0)+CONVOLVE1X1(C02,-1,+1)+ \
CONVOLVE1X1(C10,+0,-1)+CONVOLVE1X1(C11,+0,+0)+CONVOLVE1X1(C12,+0,+1)+ \
CONVOLVE1X1(C20,+1,-1)+CONVOLVE1X1(C21,+1,+0)+CONVOLVE1X1(C22,+1,+1)))
#define CONVOLVE3X6(NORMALIZER, \
C00, C01, C02, \
C10, C11, C12, \
C20, C21, C22) \
(NORMALIZER * \
(CONVOLVE1X1(C00/2.f,-1,-1)+CONVOLVE1X1(C01/2.f,-1,+0)+CONVOLVE1X1(C02/2.f,-1,+1)+ \
CONVOLVE1X1(C00/2.f,-1,-1)+CONVOLVE1X1(C01/2.f,-1,+0)+CONVOLVE1X1(C02/2.f,-1,+1)+ \
CONVOLVE1X1(C10/2.f,+0,-1)+CONVOLVE1X1(C11/2.f,+0,+0)+CONVOLVE1X1(C12/2.f,+0,+1)+ \
CONVOLVE1X1(C10/2.f,+0,-1)+CONVOLVE1X1(C11/2.f,+0,+0)+CONVOLVE1X1(C12/2.f,+0,+1)+ \
CONVOLVE1X1(C20/2.f,+1,-1)+CONVOLVE1X1(C21/2.f,+1,+0)+CONVOLVE1X1(C22/2.f,+1,+1)+ \
CONVOLVE1X1(C20/2.f,+1,-1)+CONVOLVE1X1(C21/2.f,+1,+0)+CONVOLVE1X1(C22/2.f,+1,+1)))
/* clang-format on */
#define CONVOLVE5X5(M, NORM, IMG, C00, C01, C02, C03, C04, C10, C11, C12, C13, \
C14, C20, C21, C22, C23, C24, C30, C31, C32, C33, C34, \
C40, C41, C42, C43, C44) \
QRS(M, (CONVOLVE1X12(IMG, CONVROUND((NORM * C00) * (1 << M)), -2, -2) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C01) * (1 << M)), -2, -1) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C02) * (1 << M)), -2, +0) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C03) * (1 << M)), -2, +1) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C04) * (1 << M)), -2, +2) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C10) * (1 << M)), -1, -2) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C11) * (1 << M)), -1, -1) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C12) * (1 << M)), -1, +0) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C13) * (1 << M)), -1, +1) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C14) * (1 << M)), -1, +2) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C20) * (1 << M)), +0, -2) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C21) * (1 << M)), +0, -1) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C22) * (1 << M)), +0, +0) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C23) * (1 << M)), +0, +1) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C24) * (1 << M)), +0, +2) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C30) * (1 << M)), +1, -2) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C31) * (1 << M)), +1, -1) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C32) * (1 << M)), +1, +0) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C33) * (1 << M)), +1, +1) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C34) * (1 << M)), +1, +2) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C40) * (1 << M)), +2, -2) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C41) * (1 << M)), +2, -1) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C42) * (1 << M)), +2, +0) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C43) * (1 << M)), +2, +1) + \
CONVOLVE1X12(IMG, CONVROUND((NORM * C44) * (1 << M)), +2, +2)))
unsigned *convoindex(unsigned, unsigned, unsigned) mallocesque;
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_VIZ_LIB_CONVOLUTION_H_ */

42
tool/viz/lib/convolve.h Normal file
View file

@ -0,0 +1,42 @@
#ifndef COSMOPOLITAN_TOOL_VIZ_LIB_CONVOLVE_H_
#define COSMOPOLITAN_TOOL_VIZ_LIB_CONVOLVE_H_
#include "libc/bits/xmmintrin.h"
#include "libc/str/str.h"
#include "tool/viz/lib/graphic.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
forceinline void convolve(unsigned yn, unsigned xn, __m128 img[yn][xn], int KW,
const float kernel[KW][KW], float C1, float C2) {
/* TODO(jart): nontemporal herringbone strategy */
float f;
struct Graphic g;
unsigned y, x, i, j;
__v4sf p, kflip[KW][KW], (*tmp)[yn][xn];
for (i = 0; i < KW; ++i) {
for (j = 0; j < KW; ++j) {
f = kernel[i][j] / C1;
kflip[KW - i - 1][KW - j - 1] = (__v4sf){f, f, f, f};
}
}
memset(&g, 0, sizeof(g));
resizegraphic(&g, yn, xn);
tmp = g.b.p;
for (y = 0; y < yn - KW; ++y) {
for (x = 0; x < xn - KW; ++x) {
memset(&p, 0, sizeof(p));
for (i = 0; i < KW; ++i) {
for (j = 0; j < KW; ++j) {
p += img[y + i][x + j] * kflip[i][j] + C2;
}
}
memcpy(&(*tmp)[y + KW / 2][x + KW / 2], &p, sizeof(p));
}
}
memcpy(img, tmp, yn * xn * sizeof(img[0][0]));
bfree(&g.b);
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_VIZ_LIB_CONVOLVE_H_ */

124
tool/viz/lib/dither.c Normal file
View file

@ -0,0 +1,124 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "dsp/tty/quant.h"
#include "libc/bits/hilbert.h"
#include "libc/bits/morton.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/math.h"
#include "libc/mem/mem.h"
#include "libc/runtime/gc.h"
#include "libc/str/str.h"
#include "tool/viz/lib/graphic.h"
#include "tool/viz/lib/knobs.h"
#define CLAMP(X) MIN(255, MAX(0, X))
struct Dither {
struct {
int m5[32 * 32][2];
int m4[16 * 16][2];
int m3[8 * 8][2];
int m2[4 * 4][2];
int m1[2 * 2][2];
int m0[2 * 2][2];
} memory;
struct Chunk {
long b;
void *c;
} chunks[6];
} kDither;
static struct Chunk ChunkInit(long b, int c[b * b][2]) {
long i;
axdx_t h;
for (i = 0; i < b * b; ++i) {
h = unhilbert(b, i);
c[i][0] = h.ax;
c[i][1] = h.dx;
}
return (struct Chunk){b, c};
}
static optimizesize void DitherInit(struct Dither *d) {
d->chunks[0] = ChunkInit(1 << 0, d->memory.m0);
d->chunks[1] = ChunkInit(1 << 1, d->memory.m1);
d->chunks[2] = ChunkInit(1 << 2, d->memory.m2);
d->chunks[3] = ChunkInit(1 << 3, d->memory.m3);
d->chunks[4] = ChunkInit(1 << 4, d->memory.m4);
d->chunks[5] = ChunkInit(1 << 5, d->memory.m5);
}
static int GetQuantError(unsigned char r, unsigned char g, unsigned char b) {
struct TtyRgb q = tty2rgb(rgb2tty(r, g, b));
return ((r - q.r) + (g - q.g) + (b - q.b)) / 3;
}
static int SerpentineDitherSq2(long yw, long xw, unsigned char rgb[3][yw][xw],
long y, long x, long b, const int ci[b * b][2],
int e) {
long i;
for (i = 0; i < b * b; ++i) {
e = GetQuantError((rgb[0][y + ci[i][0]][x + ci[i][1]] =
CLAMP(rgb[0][y + ci[i][0]][x + ci[i][1]] + e)),
(rgb[1][y + ci[i][0]][x + ci[i][1]] =
CLAMP(rgb[1][y + ci[i][0]][x + ci[i][1]] + e)),
(rgb[2][y + ci[i][0]][x + ci[i][1]] =
CLAMP(rgb[2][y + ci[i][0]][x + ci[i][1]] + e))) *
15 / 16;
}
return e;
}
static void SerpentineDither(long yw, long xw, unsigned char rgb[3][yw][xw],
long yn, long xn, long y, long x, long r,
const struct Dither *d) {
void *c;
long b, e, i, j, n, m;
e = 0;
b = d->chunks[r].b;
c = d->chunks[r].c;
n = (yn - y) / b;
m = (xn - x) / b;
for (i = 0; i < n; ++i) {
for (j = 0; j < m; ++j) {
e = SerpentineDitherSq2(yw, xw, rgb, y + i * b, x + j * b, b, c, 0);
}
}
if (r) {
SerpentineDither(yw, xw, rgb, yn, xn, y + 0 * 0, x + m * b, r - 1, d);
SerpentineDither(yw, xw, rgb, yn, xn, y + n * b, x + 0 * 0, r - 1, d);
SerpentineDither(yw, xw, rgb, yn, xn, y + n * b, x + m * b, r - 1, d);
}
}
/**
* Makes color banding go away a little in low color modes.
*/
void dither(long yw, long xw, unsigned char rgb[3][yw][xw], long yn, long xn) {
static bool once;
if (!once) {
DitherInit(&kDither);
once = true;
}
SerpentineDither(yw, xw, rgb, yn, xn, 0, 0, ARRAYLEN(kDither.chunks) - 1,
&kDither);
}

View file

@ -0,0 +1,54 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
/ Duplicates chrominance samples horizontally, e.g.
/
/ 12345678--------
/ 1122334455667788
/
/ @param %edi is size of %rsi array in bytes
/ @param %rsi is char[edi/16][16] output and %rsi==%rdx is OK
/ @param %rdx is char[edi/16][8] input
/ @return %rax is %rsi
doublechrominance:
.leafprologue
.profilable
shr $1,%edi # backwards algorithm
jbe 1f # do nothing if !n || n%2
mov %edi,%ecx
shr $4,%ecx
shl $4,%ecx
0: cmp %edi,%ecx
je 0f
dec %edi
movzbl (%rdx,%rdi),%eax
mov %al,(%rsi,%rdi,2)
mov %al,1(%rsi,%rdi,2)
jmp 0b
0: sub $8,%edi
movq (%rdx,%rdi),%xmm0
punpcklbw %xmm0,%xmm0
movdqu %xmm0,(%rsi,%rdi,2)
jnz 0b
1: mov %rsi,%rax
.leafepilogue
.endfn doublechrominance,globl
.yoink __FILE__

31
tool/viz/lib/emboss.c Normal file
View file

@ -0,0 +1,31 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "tool/viz/lib/convolve.h"
#include "tool/viz/lib/graphic.h"
/* clang-format off */
void emboss(struct Graphic *g) {
static const float kEmbossKernel[3][3] = {
{-2.0, -1.0, +0.0},
{-1.0, +1.0, +1.0},
{+0.0, +1.0, +2.0},
};
convolve(g->yn, g->xn, g->b.p, 3, kEmbossKernel, 1, 0);
}

View file

@ -0,0 +1,59 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/math.h"
#include "libc/mem/mem.h"
#include "libc/runtime/gc.h"
#include "libc/x/x.h"
#include "tool/viz/lib/formatstringtable.h"
#include "tool/viz/lib/stringbuilder.h"
static void *ConvertByteMatrixToStringTable(long yn, long xn, char *T[yn][xn],
const unsigned char M[yn][xn]) {
long y, x;
assert(yn && xn && !T[0][0]);
for (y = 0; y < yn; ++y) {
for (x = 0; x < xn; ++x) {
T[y][x] = xasprintf("%d", M[y][x]);
}
}
return T;
}
void FormatMatrixByte(long yn, long xn, const unsigned char M[yn][xn],
int emit(), void *arg, StringTableFormatter formatter,
const char *param1, const char *param2,
const char *param3) {
FreeStringTableCells(
yn, xn,
formatter(yn, xn,
ConvertByteMatrixToStringTable(
yn, xn, gc(calloc(yn * xn, sizeof(char *))), M),
emit, arg, param1, param2, param3));
}
char *StringifyMatrixByte(long yn, long xn, const unsigned char M[yn][xn],
StringTableFormatter formatter, const char *param1,
const char *param2, const char *param3) {
struct StringBuilder *sb = NewStringBuilder();
FormatMatrixByte(yn, xn, M, StringBuilderAppend, sb, formatter, param1,
param2, param3);
return FreeStringBuilder(sb);
}

View file

@ -0,0 +1,65 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/conv/conv.h"
#include "libc/math.h"
#include "libc/mem/mem.h"
#include "libc/runtime/gc.h"
#include "libc/x/x.h"
#include "tool/viz/lib/formatstringtable.h"
#include "tool/viz/lib/stringbuilder.h"
static void *ConvertMatrixToStringTable(long yn, long xn, char *T[yn][xn],
const double M[yn][xn], double digs,
double rounder(double)) {
double f;
long y, x;
assert(yn && xn && !T[0][0]);
for (y = 0; y < yn; ++y) {
for (x = 0; x < xn; ++x) {
T[y][x] = xdtoa(RoundDecimalPlaces(M[y][x], digs, rounder));
}
}
return T;
}
void FormatMatrixDouble(long yn, long xn, const double M[yn][xn], int emit(),
void *arg, StringTableFormatter formatter,
const char *param1, const char *param2,
const char *param3, double digs,
double rounder(double)) {
FreeStringTableCells(
yn, xn,
formatter(
yn, xn,
ConvertMatrixToStringTable(
yn, xn, gc(calloc(yn * xn, sizeof(char *))), M, digs, rounder),
emit, arg, param1, param2, param3));
}
char *StringifyMatrixDouble(long yn, long xn, const double M[yn][xn],
StringTableFormatter formatter, const char *param1,
const char *param2, const char *param3, double digs,
double rounder(double)) {
struct StringBuilder *sb = NewStringBuilder();
FormatMatrixDouble(yn, xn, M, StringBuilderAppend, sb, formatter, param1,
param2, param3, digs, rounder);
return FreeStringBuilder(sb);
}

View file

@ -0,0 +1,57 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/math.h"
#include "libc/runtime/gc.h"
#include "libc/x/x.h"
#include "tool/viz/lib/formatstringtable.h"
static void *ConvertFloatToDoubleMatrix(long yn, long xn, double Md[yn][xn],
const float Mf[yn][xn]) {
long y, x;
for (y = 0; y < yn; ++y) {
for (x = 0; x < xn; ++x) {
Md[y][x] = Mf[y][x];
}
}
return Md;
}
void FormatMatrixFloat(long yn, long xn, const float M[yn][xn], int emit(),
void *arg, StringTableFormatter formatter,
const char *param1, const char *param2,
const char *param3, double digs,
double rounder(double)) {
FormatMatrixDouble(yn, xn,
ConvertFloatToDoubleMatrix(
yn, xn, gc(xcalloc(yn * xn, sizeof(double))), M),
emit, arg, formatter, param1, param2, param3, digs,
rounder);
}
char *StringifyMatrixFloat(long yn, long xn, const float M[yn][xn],
StringTableFormatter formatter, const char *param1,
const char *param2, const char *param3, double digs,
double rounder(double)) {
return StringifyMatrixDouble(
yn, xn,
ConvertFloatToDoubleMatrix(yn, xn, gc(xcalloc(yn * xn, sizeof(double))),
M),
formatter, param1, param2, param3, digs, rounder);
}

View file

@ -0,0 +1,59 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/math.h"
#include "libc/mem/mem.h"
#include "libc/runtime/gc.h"
#include "libc/x/x.h"
#include "tool/viz/lib/formatstringtable.h"
#include "tool/viz/lib/stringbuilder.h"
static void *ConvertShortMatrixToStringTable(long yn, long xn, char *T[yn][xn],
const short M[yn][xn]) {
long y, x;
assert(yn && xn && !T[0][0]);
for (y = 0; y < yn; ++y) {
for (x = 0; x < xn; ++x) {
T[y][x] = xasprintf("%d", M[y][x]);
}
}
return T;
}
void FormatMatrixShort(long yn, long xn, const short M[yn][xn], int emit(),
void *arg, StringTableFormatter formatter,
const char *param1, const char *param2,
const char *param3) {
FreeStringTableCells(
yn, xn,
formatter(yn, xn,
ConvertShortMatrixToStringTable(
yn, xn, gc(xcalloc(yn * xn, sizeof(char *))), M),
emit, arg, param1, param2, param3));
}
char *StringifyMatrixShort(long yn, long xn, const short M[yn][xn],
StringTableFormatter formatter, const char *param1,
const char *param2, const char *param3) {
struct StringBuilder *sb = NewStringBuilder();
FormatMatrixShort(yn, xn, M, StringBuilderAppend, sb, formatter, param1,
param2, param3);
return FreeStringBuilder(sb);
}

View file

@ -0,0 +1,126 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/conv/itoa.h"
#include "libc/runtime/gc.h"
#include "libc/str/str.h"
#include "libc/unicode/unicode.h"
#include "libc/x/x.h"
#include "tool/viz/lib/formatstringtable.h"
#define STREQ(A, B) (strcasecmp(A, B) == 0)
static int GetArrayAlignment(long yn, long xn, int w, int align) {
/* abi guaranteed to 16 after which gcc / clang disagree */
int i, r;
r = i = align;
while ((i *= 2) <= __BIGGEST_ALIGNMENT__) {
if (yn * xn * w >= i) {
r = i;
}
}
return r;
}
static const char *GetStorageSpecifier(const char *type, int *out_width,
int *out_align) {
if (STREQ(type, "unsigned char") || STREQ(type, "char") ||
STREQ(type, "signed char")) {
*out_width = 1;
*out_align = 1;
return "byte";
} else if (STREQ(type, "unsigned short") || STREQ(type, "short") ||
STREQ(type, "signed short")) {
*out_width = 2;
*out_align = 2;
return "short";
} else if (STREQ(type, "unsigned int") || STREQ(type, "unsigned") ||
STREQ(type, "int") || STREQ(type, "signed int")) {
*out_width = 4;
*out_align = 4;
return "long";
} else if (STREQ(type, "unsigned long") || STREQ(type, "unsigned") ||
STREQ(type, "long") || STREQ(type, "signed long")) {
*out_width = 8;
*out_align = 8;
return "quad";
} else if (STREQ(type, "float")) {
*out_width = 4;
*out_align = 4;
return "float";
} else if (STREQ(type, "double")) {
*out_width = 8;
*out_align = 8;
return "double";
} else {
*out_width = __BIGGEST_ALIGNMENT__;
*out_align = __BIGGEST_ALIGNMENT__;
return type;
}
}
static void EmitSection(long yn, long xn, int w, int arrayalign, int emit(),
void *a) {
char alignstr[20];
uint64toarray_radix10(arrayalign, alignstr);
if (arrayalign <= 8 && yn * xn * w == 8) {
emit("\t.rodata.cst", a);
emit("8\n", a);
} else if (arrayalign <= 16 && yn * xn * w == 16) {
emit("\t.rodata.cst", a);
emit("16\n", a);
} else if (arrayalign <= 32 && yn * xn * w == 32) {
emit("\t.rodata.cst", a);
emit("32\n", a);
} else if (arrayalign <= 64 && yn * xn * w == 64) {
emit("\t.rodata.cst", a);
emit("64\n", a);
} else {
emit("\t.rodata\n", a);
emit("\t.align\t", a);
emit(alignstr, a);
emit("\n", a);
}
}
void *FormatStringTableAsAssembly(long yn, long xn, const char *const T[yn][xn],
int emit(), void *a, const char *type,
const char *name, const char *scope) {
int w, align;
const char *storage;
char ynstr[20], xnstr[20];
name = firstnonnull(name, "M");
storage = GetStorageSpecifier(firstnonnull(type, "long"), &w, &align);
uint64toarray_radix10(yn, ynstr);
uint64toarray_radix10(xn, xnstr);
EmitSection(yn, xn, w, GetArrayAlignment(yn, xn, w, align), emit, a);
emit(name, a);
emit(":", a);
if (strwidth(name) >= 8) emit("\n", a);
FormatStringTable(yn, xn, T, emit, a, gc(xstrcat("\t.", storage, "\t")), ",",
"\n");
emit("\t.endobj\t", a);
emit(name, a);
emit(",", a);
emit(firstnonnull(scope, "globl"), a);
emit("\n\t.previous\n", a);
return (/* unconst */ void *)T;
}

View file

@ -0,0 +1,28 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "tool/viz/lib/formatstringtable.h"
void *FormatStringTableForAssertion(long yn, long xn,
const char *const T[yn][xn], int emit(),
void *a, const char *ignored1,
const char *ignored2,
const char *ignored3) {
return FormatStringTable(yn, xn, T, emit, a, "\n", " ", "");
}

View file

@ -0,0 +1,26 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "tool/viz/lib/formatstringtable.h"
void *FormatStringTableBasic(long yn, long xn, const char *const T[yn][xn],
int emit(), void *a, const char *ignored1,
const char *ignored2, const char *ignored3) {
return FormatStringTable(yn, xn, T, emit, a, "", " ", "\n");
}

View file

@ -0,0 +1,41 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/safemacros.h"
#include "libc/conv/itoa.h"
#include "tool/viz/lib/formatstringtable.h"
void *FormatStringTableAsCode(long yn, long xn, const char *const T[yn][xn],
int emit(), void *arg, const char *type,
const char *name, const char *ignored) {
char ynstr[20], xnstr[20];
uint64toarray_radix10(yn, ynstr);
uint64toarray_radix10(xn, xnstr);
emit(type, arg);
emit(" ", arg);
emit(firstnonnull(name, "M"), arg);
emit("[", arg);
emit(ynstr, arg);
emit("][", arg);
emit(xnstr, arg);
emit("] = {", arg);
FormatStringTable(yn, xn, T, emit, arg, "\n {", ", ", "},");
emit("\n};\n", arg);
return (/* unconst */ void *)T;
}

View file

@ -0,0 +1,66 @@
#ifndef COSMOPOLITAN_TOOL_VIZ_LIB_FORMATSTRINGTABLE_TESTLIB_H_
#define COSMOPOLITAN_TOOL_VIZ_LIB_FORMATSTRINGTABLE_TESTLIB_H_
#include "libc/macros.h"
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
#include "tool/viz/lib/formatstringtable.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
/**
* Tests matrix contains expected content w/ string compare.
*
* @param M is 2D double array
* @param WANT is a multi-line string of formatted matrix
*/
#define EXPECT_DBLMATRIXEQ(DIGS, RND, YN, XN, M, WANT, ...) \
EXPECT_MATRIXEQ_(__FILE__, __LINE__, __FUNCTION__, YN, XN, M, #M, WANT, \
StringifyMatrixDouble, NULL, NULL, NULL, DIGS, RND)
/**
* Tests matrix contains expected content w/ string compare.
*
* @param M is 2D float array
* @param WANT is a multi-line string of formatted matrix
*/
#define EXPECT_FLTMATRIXEQ(DIGS, RND, YN, XN, M, WANT, ...) \
EXPECT_MATRIXEQ_(__FILE__, __LINE__, __FUNCTION__, YN, XN, M, #M, WANT, \
StringifyMatrixFloat, NULL, NULL, NULL, DIGS, RND)
/**
* Tests matrix contains expected content w/ string compare.
*
* @param M is 2D unsigned char array
* @param WANT is a multi-line string of formatted matrix
*/
#define EXPECT_BYTEMATRIXEQ(YN, XN, XW, M, WANT, ...) \
EXPECT_MATRIXEQ_(__FILE__, __LINE__, __FUNCTION__, YN, XN, M, #M, WANT, \
StringifyMatrixByte, NULL, NULL, NULL)
/**
* Tests matrix contains expected content w/ string compare.
*
* @param M is 2D unsigned short array
* @param WANT is a multi-line string of formatted matrix
*/
#define EXPECT_SHRTMATRIXEQ(YN, XN, M, WANT, ...) \
EXPECT_MATRIXEQ_(__FILE__, __LINE__, __FUNCTION__, YN, XN, M, #M, WANT, \
StringifyMatrixShort, NULL, NULL, NULL)
#define EXPECT_MATRIXEQ_(FILE, LINE, FUNC, YN, XN, M, MC, WANT, F, ...) \
do { \
char *Got; \
const char *Want; \
Want = (WANT); \
Got = F(YN, XN, M, FormatStringTableForAssertion, __VA_ARGS__); \
if (testlib_strequals(sizeof(char), Want, Got)) { \
testlib_free(Got); \
} else { \
TESTLIB_ONFAIL(FILE, FUNC); \
TESTLIB_SHOWERROR(testlib_showerror_expect_matrixeq, LINE, "...", MC, \
testlib_formatstr(sizeof(char), Want, -1), \
testlib_formatstr(sizeof(char), Got, -1), ""); \
} \
} while (0)
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_VIZ_LIB_FORMATSTRINGTABLE_TESTLIB_H_ */

View file

@ -0,0 +1,60 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/safemacros.h"
#include "libc/unicode/unicode.h"
#include "tool/viz/lib/formatstringtable.h"
void *FreeStringTableCells(long yn, long xn, char *T[yn][xn]) {
long y, x;
for (y = 0; y < yn; ++y) {
for (x = 0; x < xn; ++x) {
free_s(&T[y][x]);
}
}
return T;
}
static unsigned GetBiggestCellWidth(long yn, long xn,
const char *const T[yn][xn]) {
long w, y, x;
for (w = y = 0; y < yn; ++y) {
for (x = 0; x < xn; ++x) {
w = max(w, strwidth(T[y][x]));
}
}
return w;
}
void *FormatStringTable(long yn, long xn, const char *const T[yn][xn],
int emit(), void *a, const char *startrow,
const char *comma, const char *endrow) {
long w, y, x, i, n;
w = GetBiggestCellWidth(yn, xn, T);
for (y = 0; y < yn; ++y) {
emit(startrow, a);
for (x = 0; x < xn; ++x) {
if (x) emit(comma, a);
for (n = w - strwidth(T[y][x]), i = 0; i < n; ++i) emit(" ", a);
emit(T[y][x], a);
}
emit(endrow, a);
}
return (/* unconst */ void *)T;
}

View file

@ -0,0 +1,49 @@
#ifndef COSMOPOLITAN_TOOL_VIZ_LIB_FORMATSTRINGTABLE_H_
#define COSMOPOLITAN_TOOL_VIZ_LIB_FORMATSTRINGTABLE_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
typedef void *StringTableFormatter(long yn, long xn, const char *const[yn][xn],
int emit(), void *, const char *,
const char *, const char *);
StringTableFormatter FormatStringTable;
StringTableFormatter FormatStringTableBasic;
StringTableFormatter FormatStringTableAsCode;
StringTableFormatter FormatStringTableAsAssembly;
StringTableFormatter FormatStringTableForAssertion;
void *FreeStringTableCells(long yn, long xn, char *[yn][xn]);
void FormatMatrixDouble(long yn, long xn, const double[yn][xn], int emit(),
void *, StringTableFormatter, const char *,
const char *, const char *, double,
double rounder(double));
void FormatMatrixFloat(long yn, long xn, const float[yn][xn], int emit(),
void *, StringTableFormatter, const char *, const char *,
const char *, double, double rounder(double));
void FormatMatrixByte(long yn, long xn, const unsigned char[yn][xn], int emit(),
void *, StringTableFormatter, const char *, const char *,
const char *);
void FormatMatrixShort(long yn, long xn, const short[yn][xn], int emit(),
void *, StringTableFormatter, const char *, const char *,
const char *);
char *StringifyMatrixDouble(long yn, long xn, const double[yn][xn],
StringTableFormatter, const char *, const char *,
const char *, double,
double rounder(double)) mallocesque;
char *StringifyMatrixFloat(long yn, long xn, const float[yn][xn],
StringTableFormatter, const char *, const char *,
const char *, double,
double rounder(double)) mallocesque;
char *StringifyMatrixByte(long yn, long xn, const unsigned char[yn][xn],
StringTableFormatter, const char *, const char *,
const char *) mallocesque;
char *StringifyMatrixShort(long yn, long xn, const short[yn][xn],
StringTableFormatter, const char *, const char *,
const char *) mallocesque;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_VIZ_LIB_FORMATSTRINGTABLE_H_ */

71
tool/viz/lib/gaussian.c Normal file
View file

@ -0,0 +1,71 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/xmmintrin.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
#include "tool/viz/lib/convolution.h"
#include "tool/viz/lib/graphic.h"
/**
* Blurs image.
* @see https://en.wikipedia.org/wiki/Kernel_(image_processing)
*/
long gaussian(long yn, long xn, unsigned char img[3][yn][xn]) {
#if 0
long rc, c, y, x, b;
unsigned *iy, *ix;
unsigned char(*ta)[3][xn];
iy = convoindex(2, yn, 2);
ix = convoindex(2, xn, 2);
ta = memalign(32, xn * 3);
if (ta && ix && iy) {
iy += 2;
ix += 2;
for (c = 0; c < 3; ++c) {
for (y = 0; y < yn + 3; ++y) {
if (y >= 3) memcpy(img[c][y - 3], (*ta)[y % 3], xn);
if (y < yn) {
for (x = 0; x < xn; ++x) {
b = CONVOLVE5X5(/* clang-format off */
15, (1 / 256.), img[c],
1, 4, 6, 4, 1,
4, 16, 24, 16, 4,
6, 24, 36, 24, 6,
4, 16, 24, 16, 4,
1, 4, 6, 4, 1
/* clang-format on */);
(*ta)[y % 3][x] = MIN(255, MAX(0, b));
}
}
}
}
rc = 0;
} else {
rc = enomem();
}
free(ta);
if (ix) free(ix - 2);
if (iy) free(iy - 2);
return rc;
#endif
return 0;
}

View file

@ -0,0 +1,33 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "dsp/tty/quant.h"
#include "libc/bits/xmmintrin.h"
#include "libc/macros.h"
#include "tool/viz/lib/graphic.h"
void getxtermcodes(struct TtyRgb *p, const struct Graphic *g) {
unsigned y, x;
unsigned char(*img)[3][g->yn][g->xn] = g->b.p;
for (y = 0; y < g->yn; ++y) {
for (x = 0; x < g->xn; ++x) {
*p++ = rgb2tty((*img)[0][y][x], (*img)[1][y][x], (*img)[2][y][x]);
}
}
}

545
tool/viz/lib/glyphs.c Normal file
View file

@ -0,0 +1,545 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
// The modes below use various unicodes for 'progresssive' pixelization:
// each mode supersets the previous to increase resolution more and more.
// Ideally, a fully dense mapping of the (Y*X) space defined by kGlyph size
// would produce a picture perfect image, but at the cost of sampling speed.
// Therefore, supersets are parcimonious: they only add the minimal set of
// missing shapes that can increase resolution.
// Ideally, this should be based on a study of the residual, but some logic
// can go a long way: after some block pixelization, will need diagonals
// FIXME: then shouldn't box drawing go right after braille?
// TODO: explain the differences between each mode:
// Mode A is full, empty, half blocks top and bottom: , █,▄,▀
// Mode B superset: with quadrants: ▐,▌,▝,▙,▗,▛,▖,▜,▘,▟,▞,▚,
// Mode C superset: with fractional eights along X and Y
// _,▁,▂,▃,▄,▅,▆,▇ :█:▉,▊,▋,▌,▍,▎,▏
// Mode X use box drawing, mode X use diagonal blocks, mode X use braille etc
#define W(B, S) B##U << S
#define G(AA, AB, AC, AD, BA, BB, BC, BD, CA, CB, CC, CD, DA, DB, DC, DD, EA, \
EB, EC, ED, FA, FB, FC, FD, GA, GB, GC, GD, HA, HB, HC, HD) \
(W(AA, 000) | W(AB, 001) | W(AC, 002) | W(AD, 003) | W(BA, 004) | \
W(BB, 005) | W(BC, 006) | W(BD, 007) | W(CA, 010) | W(CB, 011) | \
W(CC, 012) | W(CD, 013) | W(DA, 014) | W(DB, 015) | W(DC, 016) | \
W(DD, 017) | W(EA, 020) | W(EB, 021) | W(EC, 022) | W(ED, 023) | \
W(FA, 024) | W(FB, 025) | W(FC, 026) | W(FD, 027) | W(GA, 030) | \
W(GB, 031) | W(GC, 032) | W(GD, 033) | W(HA, 034) | W(HB, 035) | \
W(HC, 036) | W(HD, 037))
// The glyph size it set by the resolution of the most precise mode, ex:
// - Mode C: along the X axis, need >= 8 steps for the 8 fractional width
// FIXME: now we can only use 4 chars instead of the extra ▉,▊,▋,▌,▍,▎,▏
//
// - Mode X: along the Y axis, need >= 8 steps to separate the maximal 6 dots
// from the space left below, seen by overimposing an underline ⠿_
// along the 3 dots, the Y axis is least 1,0,1,0,1,0,0,1 so 8 steps
//
// Problem: fonts are taller than wider, and terminals are tradionally 80x24, so
// - we shouldn't use square glyphs, 8x16 seems to be the minimal size
// - we should adapt the conversion to BMP to avoid accidental Y downsampling
const uint32_t kGlyphs[] = /* clang-format off */ {
/* U+0020 ' ' empty block [ascii:20,cp437:20] */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* U+2588 '█' full block [cp437] */
G(1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1),
/* U+2584 '▄' lower half block [cp437:dc] */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1),
/* U+2580 '▀' upper half block [cp437] */
G(1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0),
// Mode B
/* U+2590 '▐' right half block [cp437:de] */
G(0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1),
/* U+258c '▌' left half block [cp437] */
G(1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0),
/* U+259d '▝' quadrant upper right */
G(0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* U+2599 '▙' quadrant upper left and lower left and lower right */
G(1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,0),
/* U+2597 '▗' quadrant lower right */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1),
/* U+259b '▛' quadrant upper left and upper right and lower left */
G(1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,1),
/* U+2596 '▖' quadrant lower left */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0),
/* U+259c '▜' quadrant upper left and upper right and lower right */
G(1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,0),
/* U+2598 '▘' quadrant upper left */
G(1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* U+259F '▟' quadrant upper right and lower left and lower right */
G(0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,0),
/* U+259e '▞' quadrant upper right and lower left */
G(0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1,
1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0),
/* U+259a '▚' quadrant upper left and lower right */
G(1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0,
0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,0),
// Mode C
/* U+2594 '▔' upper one eighth block */
G(1,1,1,1,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* U+2581 '▁' lower one eighth block */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,1),
/* U+2582 '▂' lower one quarter block */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,1,
1,1,1,1),
/* U+2583 '▃' lower three eighths block */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,1,
1,1,1,1,
1,1,1,1),
/* U+2585 '▃' lower five eighths block */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1),
/* U+2586 '▆' lower three quarters block */
G(0,0,0,0,
0,0,0,0,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1),
/* U+2587 '▇' lower seven eighths block */
G(0,0,0,0,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1),
/* U+258e '▎' left one quarter block */
G(1,0,0,0,
1,0,0,0,
1,0,0,0,
1,0,0,0,
1,0,0,0,
1,0,0,0,
1,0,0,0,
1,0,0,0),
/* U+258a '▊' left three quarters block */
G(1,1,1,0,
1,1,1,0,
1,1,1,0,
1,1,1,0,
1,1,1,0,
1,1,1,0,
1,1,1,0,
1,1,1,0),
/* ▁ *\
2501box drawings heavy horizontal
\* */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,1,
1,1,1,1,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* ▁ *\
25019box drawings heavy quadruple dash horizontal
\* */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
1,0,1,0,
0,1,0,1,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* ▁ *\
2503box drawings heavy vertical
\* */
G(0,1,1,0,
0,1,1,0,
0,1,1,0,
0,1,1,0,
0,1,1,0,
0,1,1,0,
0,1,1,0,
0,1,1,0),
/* ▁ *\
254bbox drawings heavy vertical and horizontal
\* */
G(0,1,1,0,
0,1,1,0,
0,1,1,0,
1,1,1,1,
1,1,1,1,
0,1,1,0,
0,1,1,0,
0,1,1,0),
/* ▁ *\
2579box drawings heavy up
\* */
G(0,1,1,0,
0,1,1,0,
0,1,1,0,
0,1,1,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* ▁ *\
257abox drawings heavy right
\* */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,1,1,
0,0,1,1,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* ▁ *\
257bbox drawings heavy down
\* */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,1,1,0,
0,1,1,0,
0,1,1,0,
0,1,1,0),
/* ▁ *\
2578box drawings heavy left
\* */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,0,0,
1,1,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* ▁ *\
250fbox drawings heavy down and right
\* */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,1,1,1,
0,1,1,1,
0,1,1,0,
0,1,1,0,
0,1,1,0),
/* ▁ *\
251bbox drawings heavy up and left
\* */
G(0,1,1,0,
0,1,1,0,
0,1,1,0,
1,1,1,0,
1,1,1,0,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* ▁ *\
2513box drawings heavy down and left
\* */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,0,
1,1,1,0,
0,1,1,0,
0,1,1,0,
0,1,1,0),
/* ▁ *\
2517box drawings heavy up and right
\* */
G(0,1,1,0,
0,1,1,0,
0,1,1,0,
0,1,1,1,
0,1,1,1,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* ▁ *\
25E2black lower right triangle
\* */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,1,
0,0,1,1,
1,1,1,1,
0,0,0,0,
0,0,0,0),
/* ▁ *\
25E3black lower left triangle
\* */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
1,0,0,0,
1,1,0,0,
1,1,1,1,
0,0,0,0,
0,0,0,0),
/* ▁ *\
25E4black upper right triangle
\* */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,1,
0,0,1,1,
0,0,0,1,
0,0,0,0,
0,0,0,0),
/* ▁ *\
25E5black upper left triangle
\* */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,1,
1,1,0,0,
1,0,0,0,
0,0,0,0,
0,0,0,0),
/* ▁ *\
2500box drawings double horizontal
\* */
G(0,0,0,0,
0,0,0,0,
1,1,1,1,
0,0,0,0,
1,1,1,1,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* ▁ *\
23BBhorizontal scan line 3
\* */
G(0,0,0,0,
0,0,0,0,
1,1,1,1,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* ▁ *\
23BDhorizontal scan line 9
\* */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,1,
0,0,0,0,
0,0,0,0),
} /* clang-format on */;
const char16_t kRunes[] = {
u' ', /* 0020 empty block [ascii:20,cp437:20] */
u'', /* 2588 full block [cp437] */
u'', /* 2584 lower half block [cp437:dc] */
u'', /* 2580 upper half block [cp437] */
u'', /* 2590 right half block [cp437:de] */
u'', /* 258C left half block */
u'', /* 259D quadrant upper right */
u'', /* 2599 quadrant upper left and lower left and lower right */
u'', /* 2597 quadrant lower right */
u'', /* 259B quadrant upper left and upper right and lower left */
u'', /* 2596 quadrant lower left */
u'', /* 259C quadrant upper left and upper right and lower right */
u'', /* 2598 quadrant upper left */
u'', /* 259F quadrant upper right and lower left and lower right */
u'', /* 259E quadrant upper right and lower left */
u'', /* 259A quadrant upper left and lower right */
u'', /* 2594 upper one eighth block */
u'', /* 2581 lower one eighth block */
u'', /* 2582 lower one quarter block */
u'', /* 2583 lower three eighths block */
u'', /* 2585 lower five eighths block */
u'', /* 2586 lower three quarters block */
u'', /* 2587 lower seven eighths block */
u'', /* 258E left one quarter block */
u'', /* 258A left three quarters block */
u'', /* 2501 box drawings heavy horizontal */
u'', /* 2509 box drawings heavy quadruple dash horizontal */
u'', /* 2503 box drawings heavy vertical */
u'', /* 254B box drawings heavy vertical & horiz. */
u'', /* 2579 box drawings heavy up */
u'', /* 257A box drawings heavy right */
u'', /* 257B box drawings heavy down */
u'', /* 2578 box drawings heavy left */
u'', /* 250F box drawings heavy down and right */
u'', /* 251B box drawings heavy up and left */
u'', /* 2513 box drawings heavy down and left */
u'', /* 2517 box drawings heavy up and right */
u'', /* 25E2 black lower right triangle */
u'', /* 25E3 black lower left triangle */
u'', /* 25E4 black upper right triangle */
u'', /* 25E5 black upper left triangle */
u'', /* 2550 box drawings double horizontal */
u'', /* 23BB horizontal scan line 3 */
u'', /* 23BD horizontal scan line 9 */
};

58
tool/viz/lib/graphic.h Normal file
View file

@ -0,0 +1,58 @@
#ifndef COSMOPOLITAN_TOOL_VIZ_LIB_GRAPHIC_H_
#define COSMOPOLITAN_TOOL_VIZ_LIB_GRAPHIC_H_
#include "dsp/tty/quant.h"
#include "libc/runtime/buffer.h"
#include "libc/runtime/gc.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct Graphic {
union {
struct GuardedBuffer b;
char *bytes;
float (*lum)[2][8];
float (*rgba)[2][2];
};
unsigned yn, xn;
unsigned ys, xs;
unsigned bs, es;
};
void dither(long yw, long xw, unsigned char[3][yw][xw], long, long);
struct Graphic *resizegraphic(struct Graphic *, size_t, size_t);
void getxtermcodes(struct TtyRgb *, const struct Graphic *);
void ycbcr2lum(struct Graphic *, uint8_t *, uint8_t *, uint8_t *, size_t,
size_t, size_t);
long sharpen(long cn, long yw, long xw, unsigned char[cn][yw][xw], long, long);
long unsharp(long cn, long yw, long xw, unsigned char[cn][yw][xw], long, long);
long gaussian(long yn, long xn, unsigned char[3][yn][xn]);
void sobel(struct Graphic *);
extern void (*ycbcr2rgb)(struct Graphic *, uint8_t *, uint8_t *, uint8_t *,
size_t, size_t, size_t);
void emboss(struct Graphic *);
void boxblur(struct Graphic *);
double perlin3(double, double, double);
void stdgamma(unsigned n, __m128 rgba[n]);
void lingamma(unsigned n, __m128 rgba[n]);
void OldBilinearScale(size_t dyw, size_t dxw, __v4sf dst[dyw][dxw], size_t syw,
size_t sxw, __v4sf src[syw][sxw], size_t dyn, size_t dxn,
size_t syn, size_t sxn);
int MagicScale(unsigned dyn, unsigned dxn, __v4sf dst[dyn][dxn], unsigned syn,
unsigned sxn, __v4sf src[syn][sxn]);
void interlace(size_t dyn, size_t dxn, float dst[dyn][dxn][4], size_t syn,
size_t sxn, size_t ssw, unsigned char reds[syn][ssw],
unsigned char greens[syn][ssw], unsigned char blues[syn][ssw]);
void WriteToFrameBuffer(size_t dyn, size_t dxn, unsigned char dst[dyn][dxn][4],
size_t syn, size_t sxn, float src[syn][sxn][4],
size_t yn, size_t xn);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_VIZ_LIB_GRAPHIC_H_ */

35
tool/viz/lib/halfblit.c Normal file
View file

@ -0,0 +1,35 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/log/check.h"
#include "tool/viz/lib/halfblit.h"
void *halfblit(size_t n, void *block) {
unsigned y, x;
char(*dst)[n << 0][n << 0] = block;
char(*src)[n << 1][n << 1] = block;
DCHECK_GE(n, 2);
DCHECK_ALIGNED(16, block);
for (y = 0; y < n; ++y) {
for (x = 0; x < n; ++x) {
(*dst)[y][x] = (*src)[y][x];
}
}
return block;
}

10
tool/viz/lib/halfblit.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef COSMOPOLITAN_TOOL_VIZ_LIB_HALFBLIT_H_
#define COSMOPOLITAN_TOOL_VIZ_LIB_HALFBLIT_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void *halfblit(size_t, void *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_VIZ_LIB_HALFBLIT_H_ */

21
tool/viz/lib/knobs.h Normal file
View file

@ -0,0 +1,21 @@
#ifndef COSMOPOLITAN_TOOL_VIZ_LIB_KNOBS_H_
#define COSMOPOLITAN_TOOL_VIZ_LIB_KNOBS_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern bool pf1_;
extern bool pf2_;
extern bool pf3_;
extern bool pf4_;
extern bool pf5_;
extern bool pf6_;
extern bool pf7_;
extern bool pf8_;
extern bool pf9_;
extern bool pf10_;
extern bool pf11_;
extern bool pf12_;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_VIZ_LIB_KNOBS_H_ */

106
tool/viz/lib/perlin3.c Normal file
View file

@ -0,0 +1,106 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/macros.h"
#include "libc/math.h"
#include "tool/viz/lib/graphic.h"
static int perm[513];
static double lerp(double t, double a, double b) { return a + t * (b - a); }
static double fade(double t) {
return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
}
static double grad(int hash, double x, double y, double z) {
int h;
double u, v;
h = hash & 15;
u = h < 8 ? x : y;
v = h < 4 ? y : (h == 12 || h == 14) ? x : z;
return ((h & 1) ? -u : u) + ((h & 2) ? -v : v);
}
/**
* Perlin's improved noise algorithm.
*
* @see http://mrl.nyu.edu/~perlin/noise/
* @note it's bryce3d cgi basically
*/
double perlin3(double x, double y, double z) /* clang-format off */ {
double u, v, w;
int X, Y, Z, AA, AB, BA, BB;
X = floor(x);
Y = floor(y);
Z = floor(z);
X &= 0xff;
Y &= 0xff;
Z &= 0xff;
x -= floor(x);
y -= floor(y);
z -= floor(z);
u = fade(x);
v = fade(y);
w = fade(z);
AA = perm[perm[X ] + Y ] + Z;
AB = perm[perm[X ] + Y + 1] + Z;
BA = perm[perm[X + 1] + Y ] + Z;
BB = perm[perm[X + 1] + Y + 1] + Z;
return lerp(w, lerp(v, lerp(u, grad(perm[AA ], x , y , z ),
grad(perm[BA ], x - 1, y , z )),
lerp(u, grad(perm[AB ], x , y - 1, z ),
grad(perm[BB ], x - 1, y - 1, z ))),
lerp(v, lerp(u, grad(perm[AA + 1], x , y , z - 1),
grad(perm[BA + 1], x - 1, y , z - 1)),
lerp(u, grad(perm[AB + 1], x , y - 1, z - 1),
grad(perm[BB + 1], x - 1, y - 1, z - 1))));
} /* clang-format on */
static const uint8_t kPerm[] = {
151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7,
225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190,
6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117,
35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136,
171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158,
231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46,
245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209,
76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86,
164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5,
202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16,
58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44,
154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253,
19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97,
228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51,
145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184,
84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93,
222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156,
180,
};
static nooptimize textstartup void init(void) {
unsigned i;
for (i = 0; i < 256; ++i) {
perm[i] = kPerm[i];
perm[i + 256] = kPerm[i];
}
}
INITIALIZER(400, _init_perlin3, init());

View file

@ -0,0 +1,38 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/bits/xmmintrin.h"
#include "libc/runtime/buffer.h"
#include "tool/viz/lib/graphic.h"
/**
* Allocates graphic.
*
* @param g should be zero initialized before first call
* @note bfree(g->b) needs to be called later
*/
struct Graphic *resizegraphic(struct Graphic *g, size_t yn, size_t xn) {
/* assert(xn % 2 == 0); */ /* todo: ughhh this whole thing is wrong */
yn &= ~1;
balloc(&g->b, 64, yn * xn * sizeof(__m128) + /* wut */ PAGESIZE);
g->yn = yn;
g->xn = xn;
return g;
}

12
tool/viz/lib/scale.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef COSMOPOLITAN_TOOL_VIZ_LIB_SCALE_H_
#define COSMOPOLITAN_TOOL_VIZ_LIB_SCALE_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void *Scale(long dcw, long dyw, long dxw, float dst[dcw][dyw][dxw], long scw,
long syw, long sxw, const float src[scw][syw][sxw], long, long,
long, long, long, long, double, double, double, double);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_VIZ_LIB_SCALE_H_ */

71
tool/viz/lib/sharpen.c Normal file
View file

@ -0,0 +1,71 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "dsp/core/ks8.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/time.h"
#include "libc/x/x.h"
#include "tool/viz/lib/convolution.h"
#include "tool/viz/lib/graphic.h"
#define SHARPEN(...) KS8(0, 0, 0, 0, -1, -1, 5, -1, -1, 0, 0, 0, __VA_ARGS__)
long sharpen(long cn, long yw, long xw, unsigned char p[cn][yw][xw], long yn,
long xn) {
long rc, c, y, x;
short(*ta)[3][xn];
unsigned *iy, *ix;
if (yn >= 3 && xn > 0) {
ta = memalign(32, sizeof(short) * xn * 3);
iy = convoindex(1, yn, 1);
ix = convoindex(1, xn, 1);
if (ta && iy && ix) {
iy += 1;
ix += 1;
for (c = 0; c < 3; ++c) {
for (y = 0; y < yn + 3; ++y) {
if (y >= 3) {
for (x = 0; x < xn; ++x) {
p[c][y - 3][x] = MIN(255, MAX(0, (*ta)[y % 3][x]));
}
}
if (y < yn) {
for (x = 0; x < xn; ++x) {
(*ta)[y % 3][x] =
SHARPEN(p[c][iy[y - 1]][x], p[c][y][ix[x - 1]], p[c][y][x],
p[c][y][ix[x + 1]], p[c][iy[y + 1]][x]);
}
}
}
}
rc = 0;
} else {
rc = enomem();
}
free(ta);
if (ix) free(ix - 1);
if (iy) free(iy - 1);
} else {
rc = einval();
}
return rc;
}

76
tool/viz/lib/sobel.c Normal file
View file

@ -0,0 +1,76 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/macros.h"
#include "libc/math.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/runtime/runtime.h"
#include "tool/viz/lib/convolve.h"
#include "tool/viz/lib/graphic.h"
#define LCB {
#define RCB }
#define BROADCAST(X) LCB X, X, X, X RCB
#define FLIP(A, B, C) LCB C, B, A RCB
forceinline void ConvolveGradient(unsigned yn, unsigned xn,
float (*img)[yn][xn][4], unsigned KW,
const float (*ky)[KW][KW][4],
const float (*kx)[KW][KW][4]) {
size_t size;
unsigned y, x, i, j, k;
float py[4], px[4], (*tmp)[yn][xn][4];
tmp = mapanon((size = ROUNDUP(sizeof(float) * 4 * xn * yn, FRAMESIZE)));
for (y = 0; y < yn - KW + 1; ++y) {
for (x = 0; x < xn - KW + 1; ++x) {
for (k = 0; k < 4; ++k) py[k] = 0;
for (k = 0; k < 4; ++k) px[k] = 0;
for (i = 0; i < KW; ++i) {
for (j = 0; j < KW; ++j) {
for (k = 0; k < 4; ++k) {
py[k] += (*ky)[i][j][k] * (*img)[y + i][x + j][k];
px[k] += (*kx)[i][j][k] * (*img)[y + i][x + j][k];
}
}
}
for (k = 0; k < 4; ++k) {
(*tmp)[y + KW / 2][x + KW / 2][k] = sqrt(py[k] * py[k] + px[k] * px[k]);
}
}
}
memcpy(img, tmp, sizeof(float) * 4 * xn * yn);
munmap(tmp, size);
}
void sobel(struct Graphic* g) {
static const float kSobelEmbossKernelY[3][3][4] =
FLIP(FLIP(BROADCAST(+1), BROADCAST(+2), BROADCAST(+1)),
FLIP(BROADCAST(+0), BROADCAST(+0), BROADCAST(+0)),
FLIP(BROADCAST(-1), BROADCAST(-2), BROADCAST(-1)));
static const float kSobelEmbossKernelX[3][3][4] =
FLIP(FLIP(BROADCAST(-1), BROADCAST(+0), BROADCAST(+1)),
FLIP(BROADCAST(-2), BROADCAST(+0), BROADCAST(+2)),
FLIP(BROADCAST(-1), BROADCAST(+0), BROADCAST(+1)));
if (g->yn >= 3 && g->xn >= 3) {
ConvolveGradient(g->yn, g->xn, g->b.p, 3, &kSobelEmbossKernelY,
&kSobelEmbossKernelX);
}
}

View file

@ -0,0 +1,56 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/log/check.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/x/x.h"
#include "tool/viz/lib/stringbuilder.h"
static noinline void StringBuilderGrow(size_t need, struct StringBuilder *sb) {
size_t n2;
n2 = MAX(16, sb->n);
while (sb->i + need > n2) n2 += n2 >> 1;
sb->p = xrealloc(sb->p, n2);
sb->n = n2;
}
struct StringBuilder *NewStringBuilder(void) {
return xcalloc(1, sizeof(struct StringBuilder));
}
int StringBuilderAppend(const char *s, struct StringBuilder *sb) {
size_t size;
CHECK_LE(sb->i, sb->n);
size = strlen(s);
if (sb->i + size + 1 > sb->n) StringBuilderGrow(size + 1, sb);
memcpy(sb->p + sb->i, s, size + 1);
sb->i += size;
return 0;
}
char *FreeStringBuilder(struct StringBuilder *sb) {
char *res;
CHECK_LE(sb->i, sb->n);
CHECK_EQ('\0', sb->p[sb->i]);
res = xrealloc(sb->p, sb->i + 1);
free(sb);
return res;
}

View file

@ -0,0 +1,21 @@
#ifndef COSMOPOLITAN_TOOL_VIZ_LIB_STRINGBUILDER_H_
#define COSMOPOLITAN_TOOL_VIZ_LIB_STRINGBUILDER_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct StringBuilder {
size_t i, n;
char *p;
};
struct StringBuilder *NewStringBuilder(void) mallocesque returnsnonnull;
int StringBuilderAppend(const char *, struct StringBuilder *)
paramsnonnull((2));
char *FreeStringBuilder(struct StringBuilder *) mallocesque returnsnonnull
paramsnonnull();
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_VIZ_LIB_STRINGBUILDER_H_ */

View file

@ -0,0 +1,29 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.text.unlikely
testlib_showerror_expect_matrixeq:
push $FALSE
pushstr "EXPECT_MATRIXEQ"
pushstr "="
jmp testlib_showerror_jump
.endfn testlib_showerror_expect_matrixeq,globl,hidden
.previous

73
tool/viz/lib/unsharp.c Normal file
View file

@ -0,0 +1,73 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/time.h"
#include "libc/x/x.h"
#include "tool/viz/lib/convolution.h"
#include "tool/viz/lib/graphic.h"
/**
* Enhances image detail.
* @see https://en.wikipedia.org/wiki/Kernel_(image_processing)
*/
long unsharp(long cn, long yw, long xw, unsigned char img[cn][yw][xw], long yn,
long xn) {
long rc, c, y, x;
unsigned *iy, *ix;
short(*t)[3][xn] = xmemalign(64, sizeof(short) * xn * 3);
iy = convoindex(2, yn, 2);
ix = convoindex(2, xn, 2);
if (t && ix && iy) {
iy += 2;
ix += 2;
for (c = 0; c < 3; ++c) {
for (y = 0; y < yn + 3; ++y) {
if (y >= 3) {
for (x = 0; x < xn; ++x) {
img[c][y - 3][x] = MIN(255, MAX(0, (*t)[y % 3][x]));
}
memset((*t)[y % 3], 0, sizeof(short) * xn);
}
if (y < yn) {
for (x = 0; x < xn; ++x) {
(*t)[y % 3][x] = CONVOLVE5X5(/* clang-format off */
7, (-1 / 256.), img[c],
1, 4, 6, 4, 1,
4, 16, 24, 16, 4,
6, 24,-476, 24, 6,
4, 16, 24, 16, 4,
1, 4, 6, 4, 1
/* clang-format on */);
}
}
}
}
rc = 0;
} else {
rc = enomem();
}
free(t);
if (ix) free(ix - 2);
if (iy) free(iy - 2);
return rc;
}

120
tool/viz/lib/vizlib.mk Normal file
View file

@ -0,0 +1,120 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += TOOL_VIZ_LIB
TOOL_VIZ_LIB_ARTIFACTS += TOOL_VIZ_LIB_A
TOOL_VIZ_LIB = $(TOOL_VIZ_LIB_A_DEPS) $(TOOL_VIZ_LIB_A)
TOOL_VIZ_LIB_A = o/$(MODE)/tool/viz/lib/vizlib.a
TOOL_VIZ_LIB_A_HDRS = $(filter %.h,$(TOOL_VIZ_LIB_A_FILES))
TOOL_VIZ_LIB_A_SRCS_S = $(filter %.S,$(TOOL_VIZ_LIB_A_FILES))
TOOL_VIZ_LIB_A_SRCS_C = $(filter %.c,$(TOOL_VIZ_LIB_A_FILES))
TOOL_VIZ_LIB_A_CHECKS = $(TOOL_VIZ_LIB_A).pkg
TOOL_VIZ_LIB_A_FILES := \
$(wildcard tool/viz/lib/*) \
$(wildcard tool/viz/lib/thunks/*)
TOOL_VIZ_LIB_A_SRCS = \
$(TOOL_VIZ_LIB_A_SRCS_S) \
$(TOOL_VIZ_LIB_A_SRCS_C)
TOOL_VIZ_LIB_A_OBJS = \
$(TOOL_VIZ_LIB_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(TOOL_VIZ_LIB_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(TOOL_VIZ_LIB_A_SRCS_C:%.c=o/$(MODE)/%.o)
TOOL_VIZ_LIB_A_DIRECTDEPS = \
DSP_TTY \
DSP_CORE \
DSP_SCALE \
LIBC_INTRIN \
LIBC_ALG \
LIBC_BITS \
LIBC_CALLS \
LIBC_CONV \
LIBC_FMT \
LIBC_SYSV \
LIBC_UNICODE \
LIBC_TESTLIB \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_LOG \
LIBC_TIME \
LIBC_TINYMATH \
LIBC_STDIO \
LIBC_STUBS \
LIBC_STR \
LIBC_X \
THIRD_PARTY_AVIR \
THIRD_PARTY_DTOA \
THIRD_PARTY_DLMALLOC
TOOL_VIZ_LIB_A_DEPS := \
$(call uniq,$(foreach x,$(TOOL_VIZ_LIB_A_DIRECTDEPS),$($(x))))
o/$(MODE)/tool/viz/lib/pmaddubsw.o: \
OVERRIDE_CFLAGS += \
-fvect-cost-model=unlimited
o/$(MODE)/tool/viz/lib/scale.o \
o/$(MODE)/tool/viz/lib/writetoframebuffer.o \
o/$(MODE)/tool/viz/lib/lab.o \
o/$(MODE)/tool/viz/lib/xyz.o \
o/$(MODE)/tool/viz/lib/doublechrominance.o \
o/$(MODE)/tool/viz/lib/doublechrominance.o \
o/$(MODE)/tool/viz/lib/doublechrominance.o \
o/$(MODE)/tool/viz/lib/interlace.o \
o/$(MODE)/tool/viz/lib/bilinearscale.o \
o/$(MODE)/tool/viz/lib/oldbilinearscale.o \
o/$(MODE)/tool/viz/lib/boxblur.o \
o/$(MODE)/tool/viz/lib/dither.o \
o/$(MODE)/tool/viz/lib/emboss.o \
o/$(MODE)/tool/viz/lib/getxtermcodes.o \
o/$(MODE)/tool/viz/lib/lingamma.o \
o/$(MODE)/tool/viz/lib/perlin3.o \
o/$(MODE)/tool/viz/lib/resizegraphic.o: \
OVERRIDE_CFLAGS += \
-DSTACK_FRAME_UNLIMITED \
$(MATHEMATICAL)
#o/$(MODE)/tool/viz/lib/scale.o \
o/$(MODE)/tool/viz/lib/writetoframebuffer.o \
o/$(MODE)/tool/viz/lib/interlace.o \
o/$(MODE)/tool/viz/lib/magicscale.o \
o/$(MODE)/tool/viz/lib/halfblit.o \
o/$(MODE)/tool/viz/lib/byte2float.o \
o/$(MODE)/tool/viz/lib/ycbcr2rgb2.o \
o/$(MODE)/tool/viz/lib/magickernel.o \
o/$(MODE)/tool/viz/lib/lolquist.o \
o/$(MODE)/tool/viz/lib/getxtermcodes.o \
o/$(MODE)/tool/viz/lib/unsharp.o \
o/$(MODE)/tool/viz/lib/gaussian.o: \
CC = $(CLANG)
o/$(MODE)/tool/viz/lib/printmatrix.o: \
OVERRIDE_CFLAGS += \
$(IEEE_MATH)
$(TOOL_VIZ_LIB_A): \
tool/viz/lib/ \
$(TOOL_VIZ_LIB_A).pkg \
$(TOOL_VIZ_LIB_A_OBJS)
$(TOOL_VIZ_LIB_A).pkg: \
$(TOOL_VIZ_LIB_A_OBJS) \
$(foreach x,$(TOOL_VIZ_LIB_A_DIRECTDEPS),$($(x)_A).pkg)
$(TOOL_VIZ_LIB_A_OBJS): tool/viz/lib/vizlib.mk
TOOL_VIZ_LIB_LIBS = $(foreach x,$(TOOL_VIZ_LIB_ARTIFACTS),$($(x)))
TOOL_VIZ_LIB_SRCS = $(foreach x,$(TOOL_VIZ_LIB_ARTIFACTS),$($(x)_SRCS))
TOOL_VIZ_LIB_HDRS = $(foreach x,$(TOOL_VIZ_LIB_ARTIFACTS),$($(x)_HDRS))
TOOL_VIZ_LIB_BINS = $(foreach x,$(TOOL_VIZ_LIB_ARTIFACTS),$($(x)_BINS))
TOOL_VIZ_LIB_CHECKS = $(foreach x,$(TOOL_VIZ_LIB_ARTIFACTS),$($(x)_CHECKS))
TOOL_VIZ_LIB_OBJS = $(foreach x,$(TOOL_VIZ_LIB_ARTIFACTS),$($(x)_OBJS))
TOOL_VIZ_LIB_TESTS = $(foreach x,$(TOOL_VIZ_LIB_ARTIFACTS),$($(x)_TESTS))
.PHONY: o/$(MODE)/tool/viz/lib
o/$(MODE)/tool/viz/lib: $(TOOL_VIZ_LIB_CHECKS)

View file

@ -0,0 +1,42 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
#include "tool/viz/lib/graphic.h"
void WriteToFrameBuffer(size_t dyn, size_t dxn, unsigned char dst[dyn][dxn][4],
size_t syn, size_t sxn, float src[syn][sxn][4],
size_t yn, size_t xn) {
int ipix[4];
float fpix[4];
unsigned y, x, k, upix[4];
for (y = 0; y < yn; ++y) {
for (x = 0; x < xn; ++x) {
for (k = 0; k < 4; ++k) fpix[k] = src[y][x][k];
for (k = 0; k < 4; ++k) fpix[k] *= 255;
for (k = 0; k < 4; ++k) ipix[k] = fpix[k] + .5f;
for (k = 0; k < 4; ++k) upix[k] = MAX(0, ipix[k]);
for (k = 0; k < 4; ++k) upix[k] = MIN(255, upix[k]);
dst[y][x][0] = upix[2];
dst[y][x][1] = upix[1];
dst[y][x][2] = upix[0];
dst[y][x][3] = 0;
}
}
}

34
tool/viz/lib/ycbcr.h Normal file
View file

@ -0,0 +1,34 @@
#ifndef COSMOPOLITAN_TOOL_VIZ_LIB_YCBCR_H_
#define COSMOPOLITAN_TOOL_VIZ_LIB_YCBCR_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct YCbCr;
extern const double kBt601Primaries[3];
extern const double kBt709Primaries[3];
extern long magikarp_latency_;
extern long ycbcr2rgb_latency_;
void Y2Rgb(long yn, long xn, unsigned char[restrict 3][yn][xn], long yys,
long yxs, const unsigned char[restrict yys][yxs], const int[4][4],
const unsigned char[256]);
void YCbCr2Rgb(long yn, long xn, unsigned char[restrict 3][yn][xn], long yys,
long yxs, const unsigned char[restrict yys][yxs], long cys,
long cxs, const unsigned char[restrict cys][cxs],
const unsigned char[restrict cys][cxs], const int[4][4],
const int[3][4], const unsigned char[256]);
void YCbCrFree(struct YCbCr **);
void YCbCrInit(struct YCbCr **, bool, int, double, const double[3],
const double[3]);
void *YCbCr2RgbScale(long dyn, long dxn, unsigned char[restrict 3][dyn][dxn],
long yys, long yxs, unsigned char[restrict yys][yxs],
long cys, long cxs, unsigned char[restrict cys][cxs],
unsigned char[restrict cys][cxs], long, long, long, long,
double, double, double, double, struct YCbCr **);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_VIZ_LIB_YCBCR_H_ */

395
tool/viz/lib/ycbcr2rgb3.c Normal file
View file

@ -0,0 +1,395 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "dsp/core/c11.h"
#include "dsp/core/c1331.h"
#include "dsp/core/c1331s.h"
#include "dsp/core/c161.h"
#include "dsp/core/core.h"
#include "dsp/core/half.h"
#include "dsp/core/illumination.h"
#include "dsp/core/q.h"
#include "dsp/scale/scale.h"
#include "libc/bits/xmmintrin.h"
#include "libc/calls/calls.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/struct/sigset.h"
#include "libc/intrin/pmulhrsw.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/math.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/gc.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/time.h"
#include "libc/x/x.h"
#include "third_party/avir/lanczos.h"
#include "tool/viz/lib/graphic.h"
#include "tool/viz/lib/knobs.h"
#include "tool/viz/lib/scale.h"
#include "tool/viz/lib/ycbcr.h"
#define M 15
#define CLAMP(X) MIN(255, MAX(0, X))
const double kBt601Primaries[] = {.299, .587, .114};
const double kBt709Primaries[] = {871024 / 4096299., 8788810 / 12288897.,
887015 / 12288897.};
const double kSrgbToXyz[3][3] = {
{506752 / 1228815., 87881 / 245763., 12673 / 70218.},
{87098 / 409605., 175762 / 245763., 12673 / 175545.},
{7918 / 409605., 87881 / 737289., 1001167 / 1053270.},
};
long magikarp_latency_;
long gyarados_latency_;
long ycbcr2rgb_latency_;
long double magikarp_start_;
struct YCbCr {
bool yonly;
int magnums[8][4];
int lighting[6][4];
unsigned char transfer[2][256];
struct YCbCrSamplingSolution {
long dyn, dxn;
long syn, sxn;
double ry, rx;
double oy, ox;
double py, px;
struct SamplingSolution *cy, *cx;
} luma, chroma;
};
/**
* Computes magnums for YCbCr decoding.
*
* @param swing should be 219 for TV, or 255 for JPEG
* @param M is integer coefficient bits
*/
void YCbCrComputeCoefficients(int swing, double gamma,
const double primaries[3],
const double illuminant[3], int out_magnums[8][4],
int out_lighting[6][4],
unsigned char out_transfer[256]) {
int i, j;
double x;
double f1[6][3];
long longs[6][6];
long bitlimit = roundup2pow(swing);
long wordoffset = rounddown2pow((bitlimit - swing) / 2);
long chromaswing = swing + 2 * (bitlimit / 2. - swing / 2. - wordoffset);
long lumamin = wordoffset;
long lumamax = wordoffset + swing;
long diffmax = wordoffset + chromaswing - bitlimit / 2;
long diffmin = -diffmax;
double rEb = 1 - primaries[2] + primaries[0] + primaries[1];
double rEgEb = 1 / primaries[1] * primaries[2] * rEb;
double rEr = 1 - primaries[0] + primaries[1] + primaries[2];
double rEgEr = 1 / primaries[1] * primaries[0] * rEr;
double unswing = 1. / swing * bitlimit;
double digital = 1. / swing * chromaswing;
double reals[6][6] = {
{rEr / digital},
{-rEgEb / digital, -rEgEr / digital},
{rEb / digital},
{0, 0, unswing},
};
for (i = 0; i < 4; ++i) {
GetIntegerCoefficients(longs[i], reals[i], M, diffmin, diffmax);
}
for (i = 0; i < 4; ++i) {
for (j = 0; j < 4; ++j) {
out_magnums[i][j] = longs[i][j];
}
}
out_magnums[3][0] = wordoffset;
out_magnums[3][1] = bitlimit / 2;
GetChromaticAdaptationMatrix(f1, kIlluminantD65, illuminant);
for (i = 0; i < 3; ++i) {
for (j = 0; j < 3; ++j) {
reals[i][j] = f1[i][j];
}
}
for (i = 0; i < 6; ++i) {
GetIntegerCoefficients(longs[i], reals[i], M, diffmin * 2, lumamax * 2);
}
for (i = 0; i < 6; ++i) {
for (j = 0; j < 3; ++j) {
out_lighting[i][j] = longs[i][j];
}
}
for (i = 0; i < 256; ++i) {
x = i;
x /= 255;
x = tv2pcgamma(x, gamma);
x *= 255;
out_transfer[i] = CLAMP(x);
}
memset(out_transfer, out_transfer[lumamin], lumamin);
memset(out_transfer + lumamax + 1, out_transfer[lumamax], bitlimit - lumamax);
}
void YCbCrInit(struct YCbCr **ycbcr, bool yonly, int swing, double gamma,
const double gamut[3], const double illuminant[3]) {
if (!*ycbcr) *ycbcr = xcalloc(1, sizeof(struct YCbCr));
(*ycbcr)->yonly = yonly;
memset((*ycbcr)->magnums, 0, sizeof((*ycbcr)->magnums));
memset((*ycbcr)->lighting, 0, sizeof((*ycbcr)->lighting));
YCbCrComputeCoefficients(swing, gamma, gamut, illuminant, (*ycbcr)->magnums,
(*ycbcr)->lighting, (*ycbcr)->transfer[0]);
imapxlatab((*ycbcr)->transfer[1]);
}
void YCbCrFree(struct YCbCr **ycbcr) {
if (*ycbcr) {
FreeSamplingSolution((*ycbcr)->luma.cy), (*ycbcr)->luma.cy = NULL;
FreeSamplingSolution((*ycbcr)->luma.cx), (*ycbcr)->luma.cx = NULL;
FreeSamplingSolution((*ycbcr)->chroma.cy), (*ycbcr)->chroma.cy = NULL;
FreeSamplingSolution((*ycbcr)->chroma.cx), (*ycbcr)->chroma.cx = NULL;
free(*ycbcr), *ycbcr = NULL;
}
}
void *YCbCrReallocPlane(long ys, long xs, const unsigned char p[ys][xs],
long yn, long xn) {
long y;
unsigned char(*res)[yn][xn];
res = xmemalign(32, yn * xn);
for (y = 0; y < yn; ++y) {
memcpy((*res)[y], p[y], xn);
}
return res;
}
void YCbCrComputeSamplingSolution(struct YCbCrSamplingSolution *scale, long dyn,
long dxn, long syn, long sxn, double ry,
double rx, double oy, double ox, double py,
double px) {
if (scale->dyn != dyn || scale->dxn != dxn || scale->syn != syn ||
scale->sxn != sxn || fabs(scale->ry - ry) > .001 ||
fabs(scale->rx - rx) > .001 || fabs(scale->oy - oy) > .001 ||
fabs(scale->ox - ox) > .001 || fabs(scale->py - py) > .001 ||
fabs(scale->px - px) > .001) {
LOGF("recomputing sampling solution");
FreeSamplingSolution(scale->cy), scale->cy = NULL;
FreeSamplingSolution(scale->cx), scale->cx = NULL;
scale->cy = ComputeSamplingSolution(dyn, syn, ry, oy, py);
scale->cx = ComputeSamplingSolution(dxn, sxn, rx, ox, px);
scale->dyn = dyn, scale->dxn = dxn;
scale->syn = syn, scale->sxn = sxn;
scale->ry = ry, scale->rx = rx;
scale->oy = oy, scale->ox = ox;
scale->py = py, scale->px = px;
}
}
void Y2Rgb(long yn, long xn, unsigned char RGB[restrict 3][yn][xn], long yys,
long yxs, const unsigned char Y[restrict yys][yxs],
const int K[8][4], const unsigned char T[256]) {
long i, j;
for (i = 0; i < yn; ++i) {
for (j = 0; j < xn; ++j) {
RGB[0][i][j] = T[Y[i][j]];
}
}
memcpy(RGB[1], RGB[0], yn * xn);
memcpy(RGB[2], RGB[0], yn * xn);
}
/**
* Converts YCbCr samples to RGB.
*/
void YCbCr2Rgb(long yn, long xn, unsigned char RGB[restrict 3][yn][xn],
long yys, long yxs, const unsigned char Y[restrict yys][yxs],
long cys, long cxs, const unsigned char Cb[restrict cys][cxs],
const unsigned char Cr[restrict cys][cxs], const int K[8][4],
const int L[6][4], const unsigned char T[256]) {
long i, j;
short y, u, v, r, g, b, A, B, C;
for (i = 0; i < yn; ++i) {
for (j = 0; j < xn; ++j) {
y = Y[i][j];
u = Cb[i][j] - K[3][1];
v = Cr[i][j] - K[3][1];
r = y + QRS(M, v * K[0][0]);
g = y + QRS(M, u * K[1][0] + v * K[1][1]);
b = y + QRS(M, u * K[2][0]);
r = QRS(M, (MIN(235, MAX(16, r)) - K[3][0]) * K[3][2]);
g = QRS(M, (MIN(235, MAX(16, g)) - K[3][0]) * K[3][2]);
b = QRS(M, (MIN(235, MAX(16, b)) - K[3][0]) * K[3][2]);
RGB[0][i][j] = CLAMP(QRS(M, r * L[0][0] + g * L[0][1] + b * L[0][2]));
RGB[1][i][j] = CLAMP(QRS(M, r * L[1][0] + g * L[1][1] + b * L[1][2]));
RGB[2][i][j] = CLAMP(QRS(M, r * L[2][0] + g * L[2][1] + b * L[2][2]));
}
}
}
void YCbCrConvert(struct YCbCr *me, long yn, long xn,
unsigned char RGB[restrict 3][yn][xn], long yys, long yxs,
const unsigned char Y[restrict yys][yxs], long cys, long cxs,
unsigned char Cb[restrict cys][cxs],
unsigned char Cr[restrict cys][cxs]) {
long double ts;
ts = nowl();
if (!me->yonly) {
YCbCr2Rgb(yn, xn, RGB, yys, yxs, Y, cys, cxs, Cb, Cr, me->magnums,
me->lighting, me->transfer[pf10_]);
} else {
Y2Rgb(yn, xn, RGB, yys, yxs, Y, me->magnums, me->transfer[pf10_]);
}
ycbcr2rgb_latency_ = lroundl((nowl() - ts) * 1e6l);
}
void YCbCr2RgbScaler(struct YCbCr *me, long dyn, long dxn,
unsigned char RGB[restrict 3][dyn][dxn], long yys,
long yxs, unsigned char Y[restrict yys][yxs], long cys,
long cxs, unsigned char Cb[restrict cys][cxs],
unsigned char Cr[restrict cys][cxs], long yyn, long yxn,
long cyn, long cxn, double syn, double sxn, double pry,
double prx) {
long double ts;
long y, x, scyn, scxn;
double yry, yrx, cry, crx, yoy, yox, coy, cox, err, oy;
scyn = syn * cyn / yyn;
scxn = sxn * cxn / yxn;
if (HALF(yxn) > dxn && HALF(scxn) > dxn) {
YCbCr2RgbScaler(me, dyn, dxn, RGB, yys, yxs,
Magikarp2xX(yys, yxs, Y, syn, sxn), cys, cxs,
Magkern2xX(cys, cxs, Cb, scyn, scxn),
Magkern2xX(cys, cxs, Cr, scyn, scxn), yyn, HALF(yxn), cyn,
HALF(cxn), syn, sxn / 2, pry, prx);
} else if (HALF(yyn) > dyn && HALF(scyn) > dyn) {
YCbCr2RgbScaler(me, dyn, dxn, RGB, yys, yxs,
Magikarp2xY(yys, yxs, Y, syn, sxn), cys, cxs,
Magkern2xY(cys, cxs, Cb, scyn, scxn),
Magkern2xY(cys, cxs, Cr, scyn, scxn), HALF(yyn), yxn,
HALF(cyn), scxn, syn / 2, sxn, pry, prx);
} else {
magikarp_latency_ = lroundl((nowl() - magikarp_start_) * 1e6l);
ts = nowl();
yry = syn / dyn;
yrx = sxn / dxn;
cry = syn * cyn / yyn / dyn;
crx = sxn * cxn / yxn / dxn;
yoy = syn / scyn / 2 - pry * .5;
yox = sxn / scxn / 2 - prx * .5;
coy = syn / scyn / 2 - pry * .5;
cox = sxn / scxn / 2 - prx * .5;
LOGF("gyarados pry=%.3f prx=%.3f syn=%.3f sxn=%.3f dyn=%ld dxn=%ld "
"yyn=%ld "
"yxn=%ld cyn=%ld cxn=%ld yry=%.3f yrx=%.3f cry=%.3f crx=%.3f "
"yoy=%.3f "
"yox=%.3f coy=%.3f cox=%.3f",
pry, prx, syn, sxn, dyn, dxn, yyn, yxn, cyn, cxn, yry, yrx, cry, crx,
yoy, yox, coy, cox);
YCbCrComputeSamplingSolution(&me->luma, dyn, dxn, syn, sxn, yry, yrx, yoy,
yox, pry, prx);
YCbCrComputeSamplingSolution(&me->chroma, dyn, dxn, scyn, scxn, cry, crx,
coy, cox, pry, prx);
if (pf8_) sharpen(1, yys, yxs, (void *)Y, yyn, yxn);
if (pf9_) unsharp(1, yys, yxs, (void *)Y, yyn, yxn);
GyaradosUint8(yys, yxs, Y, yys, yxs, Y, dyn, dxn, syn, sxn, 0, 255,
me->luma.cy, me->luma.cx, true);
GyaradosUint8(cys, cxs, Cb, cys, cxs, Cb, dyn, dxn, scyn, scxn, 0, 255,
me->chroma.cy, me->chroma.cx, false);
GyaradosUint8(cys, cxs, Cr, cys, cxs, Cr, dyn, dxn, scyn, scxn, 0, 255,
me->chroma.cy, me->chroma.cx, false);
gyarados_latency_ = lround((nowl() - ts) * 1e6l);
YCbCrConvert(me, dyn, dxn, RGB, yys, yxs, Y, cys, cxs, Cb, Cr);
LOGF("done");
}
}
/**
* Converts YCbCr frame for PC display.
*
* "[The] experiments of Professor J. D. Forbes, which I
* witnessed [established] that blue and yellow do not
* make green but a pinkish tint, when neither prevails
* in the combination [and the] result of mixing yellow
* and blue was, I believe, not previously known.
* James Clerk Maxwell
*
* This function converts TV to PC graphics. We do that by
*
* 1. decimating w/ facebook magikarp photoshop cubic sharpen
* 2. upsampling color difference planes, to be as big as luma plane
* 3. converting color format
* 4. expanding dynamic range
* 5. transferring gamma from TV to PC convention
* 6. resampling again to exact requested display / pixel geometry
*
* @param dyn/dxn is display height/width after scaling/conversion
* @param RGB points to memory for packed de-interlaced RGB output
* @param Y [16,235] is the luminance plane a gamma-corrected RGB
* weighted sum; a.k.a. black/white legacy component part of the
* TV signal; which may be used independently of the chrominance
* planes; and decodes to the range [0,1]
* @param Cb/Cr [16,240] is blue/red chrominance difference planes
* which (if sampled at a different rate) will get stretched out
* over the luma plane appropriately
* @param yys/yxs dimensions luma sample array
* @param cys/cxs dimensions chroma sample arrays
* @param yyn/yxn is number of samples in luma signal
* @param cyn/cxn is number of samples in each chroma signal
* @param syn/sxn is size of source signal
* @param pry/prx is pixel aspect ratio, e.g. 1,1
* @return RGB
*/
void *YCbCr2RgbScale(long dyn, long dxn,
unsigned char RGB[restrict 3][dyn][dxn], long yys,
long yxs, unsigned char Y[restrict yys][yxs], long cys,
long cxs, unsigned char Cb[restrict cys][cxs],
unsigned char Cr[restrict cys][cxs], long yyn, long yxn,
long cyn, long cxn, double syn, double sxn, double pry,
double prx, struct YCbCr **ycbcr) {
long minyys, minyxs, mincys, mincxs;
CHECK_LE(yyn, yys);
CHECK_LE(yxn, yxs);
CHECK_LE(cyn, cys);
CHECK_LE(cxn, cxs);
LOGF("magikarp2x");
magikarp_start_ = nowl();
minyys = MAX(ceil(syn), MAX(yyn, ceil(dyn * pry)));
minyxs = MAX(ceil(sxn), MAX(yxn, ceil(dxn * prx)));
mincys = MAX(cyn, ceil(dyn * pry));
mincxs = MAX(cxn, ceil(dxn * prx));
YCbCr2RgbScaler(*ycbcr, dyn, dxn, RGB, MAX(yys, minyys), MAX(yxs, minyxs),
(yys >= minyys && yxs >= minyxs
? Y
: gc(YCbCrReallocPlane(yys, yxs, Y, minyys, minyxs))),
MAX(cys, mincys), MAX(cxs, mincxs),
(cys >= mincys && cxs >= mincxs
? Cb
: gc(YCbCrReallocPlane(cys, cxs, Cb, mincys, mincxs))),
(cys >= mincys && cxs >= mincxs
? Cr
: gc(YCbCrReallocPlane(cys, cxs, Cr, mincys, mincxs))),
yyn, yxn, cyn, cxn, syn, sxn, pry, prx);
return RGB;
}

678
tool/viz/magikarp.c Normal file
View file

@ -0,0 +1,678 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "dsp/core/c1331.h"
#include "dsp/core/c161.h"
#include "dsp/core/core.h"
#include "dsp/scale/scale.h"
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/math.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/rand/rand.h"
#include "libc/runtime/gc.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"
#include "third_party/avir/lanczos1b.h"
#include "third_party/avir/lanczos1f.h"
#include "third_party/dtoa/dtoa.h"
#include "third_party/getopt/getopt.h"
#include "third_party/stb/stb_image.h"
#include "tool/viz/lib/bilinearscale.h"
#include "tool/viz/lib/graphic.h"
#include "tool/viz/lib/scale.h"
#define LONG long
#define CHAR char
#define CLAMP(X) MIN(255, MAX(0, X))
#define C13(A, B) (((A) + 3 * (B) + 2) >> 2)
#define LERP(X, Y, P) ((X) + (((P) * ((Y) - (X))) >> 8))
static double r_;
static unsigned char ChessBoard(unsigned y, unsigned x, unsigned char a,
unsigned char b) {
return !((y ^ x) & (1u << 2)) ? a : b;
}
static unsigned char AlphaBackground(unsigned y, unsigned x) {
return ChessBoard(y, x, 255, 200);
}
static unsigned char OutOfBoundsBackground(unsigned y, unsigned x) {
return ChessBoard(y, x, 40, 80);
}
static unsigned char Opacify(CHAR w, const unsigned char P[1u << w][1u << w],
const unsigned char A[1u << w][1u << w], LONG yn,
LONG xn, long y, long x) {
if ((0 <= y && y < yn) && (0 <= x && x < xn)) {
return LERP(AlphaBackground(y, x), P[y][x], A[y][x]);
} else {
return OutOfBoundsBackground(y, x);
}
}
static void PrintImage(CHAR w, unsigned char R[1u << w][1u << w],
unsigned char G[1u << w][1u << w],
unsigned char B[1u << w][1u << w],
unsigned char A[1u << w][1u << w], LONG yn, LONG xn) {
bool didhalfy;
long y, x;
didhalfy = false;
for (y = 0; y < yn; y += 2) {
if (y) printf("\e[0m\n");
for (x = 0; x < xn; ++x) {
printf("\e[48;2;%d;%d;%d;38;2;%d;%d;%dm▄",
Opacify(w, R, A, yn, xn, y + 0, x),
Opacify(w, G, A, yn, xn, y + 0, x),
Opacify(w, B, A, yn, xn, y + 0, x),
Opacify(w, R, A, yn, xn, y + 1, x),
Opacify(w, G, A, yn, xn, y + 1, x),
Opacify(w, B, A, yn, xn, y + 1, x));
}
if (y == 0) {
printf("\e[0m‾0");
} else if (yn / 2 <= y && y <= yn / 2 + 1 && !didhalfy) {
printf("\e[0m‾%s%s", "yn/2", y % 2 ? "+1" : "");
didhalfy = true;
} else if (y + 1 == yn / 2 && !didhalfy) {
printf("\e[0m⎯yn/2");
didhalfy = true;
} else if (y + 1 == yn) {
printf("\e[0m⎯yn");
} else if (y + 2 == yn) {
printf("\e[0m_yn");
} else if (!(y % 10)) {
printf("\e[0m‾%,u", y);
}
}
printf("\e[0m\n");
}
static void DeblinterlaceRgba(CHAR w, unsigned char R[1u << w][1u << w],
unsigned char G[1u << w][1u << w],
unsigned char B[1u << w][1u << w],
unsigned char A[1u << w][1u << w], LONG yn,
LONG xn, const unsigned char src[yn][xn][4]) {
long y, x;
for (y = 0; y < yn; ++y) {
for (x = 0; x < xn; ++x) {
R[y][x] = src[y][x][0];
G[y][x] = src[y][x][1];
B[y][x] = src[y][x][2];
A[y][x] = src[y][x][3];
}
}
}
static void SharpenX(CHAR w, unsigned char dst[1u << w][1u << w],
const unsigned char src[1u << w][1u << w], char yw,
char xw) {
int y, x;
for (y = 0; y < (1u << yw); ++y) {
for (x = 0; x < (1u << xw); ++x) {
dst[y][x] = C161(src[y][MAX(0, x - 1)], src[y][x],
src[y][MIN((1u << xw) - 1, x + 1)]);
}
}
}
static void SharpenY(CHAR w, unsigned char dst[1u << w][1u << w],
const unsigned char src[1u << w][1u << w], char yw,
char xw) {
int y, x;
for (y = 0; y < (1u << yw); ++y) {
for (x = 0; x < (1u << xw); ++x) {
dst[y][x] = C161(src[MAX(0, y - 1)][x], src[y][x],
src[MIN((1u << yw) - 1, y + 1)][x]);
}
}
}
static void UpscaleX(CHAR w, unsigned char img[1u << w][1u << w], char yw,
char xw) {
long y, x;
for (y = (1u << yw); y--;) {
for (x = (1u << xw); --x;) {
img[y][x] =
C13(img[y][MIN(((1u << xw) >> 1) - 1, (x >> 1) - 1 + (x & 1) * 2)],
img[y][x >> 1]);
}
}
}
static void UpscaleY(CHAR w, unsigned char img[1u << w][1u << w], char yw,
char xw) {
long y, x;
for (y = (1u << yw); --y;) {
for (x = (1u << xw); x--;) {
img[y][x] =
C13(img[MIN(((1u << yw) >> 1) - 1, (y >> 1) - 1 + (y & 1) * 2)][x],
img[y >> 1][x]);
}
}
}
static void Upscale(CHAR w, unsigned char img[1u << w][1u << w],
unsigned char tmp[1u << w][1u << w], char yw, char xw) {
UpscaleY(w, img, yw, xw - 1);
SharpenY(w, tmp, img, yw, xw - 1);
UpscaleX(w, tmp, yw, xw);
SharpenX(w, img, tmp, yw, xw);
}
#if 0
static void *MagikarpY(CHAR w, unsigned char p[1u << w][1u << w], char yw,
char xw) {
long y, x, yn, xn, ym;
unsigned char(*t)[(1u << w) + 2][1u << w];
t = memalign(64, ((1u << w) + 2) * (1u << w));
memset(t, 0, ((1u << w) + 2) * (1u << w));
yn = 1u << yw;
xn = 1u << xw;
ym = yn >> 1;
for (y = 0; y < ym; ++y) {
for (x = 0; x < xn; ++x) {
(*t)[y + 1][x] =
C1331(y ? p[(y << 1) - 1][x] : 0, p[y << 1][x], p[(y << 1) + 1][x],
p[MIN(yn - 1, (y << 1) + 2)][x]);
}
}
for (y = 0; y < ym; ++y) {
for (x = 0; x < xn; ++x) {
p[y][x] =
C161((*t)[y + 1 - 1][x], (*t)[y + 1 + 0][x], (*t)[y + 1 + 1][x]);
}
}
free(t);
return p;
}
static void *MagikarpX(CHAR w, unsigned char p[1u << w][1u << w], char yw,
char xw) {
int y, x;
LONG yn, xn, xm;
yn = 1u << yw;
xn = 1u << xw;
xm = xn >> 1;
for (x = 0; x < xm; ++x) {
for (y = 0; y < yn; ++y) {
p[y][(xn - xm - 1) + (xm - x - 1)] =
C1331(p[y][MAX(00 + 0, xn - (x << 1) - 1 + (xn & 1) - 1)],
p[y][MIN(xn - 1, xn - (x << 1) - 1 + (xn & 1) + 0)],
p[y][MIN(xn - 1, xn - (x << 1) - 1 + (xn & 1) + 1)],
p[y][MIN(xn - 1, xn - (x << 1) - 1 + (xn & 1) + 2)]);
}
}
for (x = 0; x < xm; ++x) {
for (y = 0; y < yn; ++y) {
p[y][x] = C161(p[y][MAX(xn - 1 - xm, xn - xm - 1 + x - 1)],
p[y][MIN(xn - 1 - 00, xn - xm - 1 + x + 0)],
p[y][MIN(xn - 1 - 00, xn - xm - 1 + x + 1)]);
}
}
return p;
}
static void ProcessImageVerbatim(LONG yn, LONG xn,
unsigned char img[yn][xn][4]) {
CHAR w;
void *R, *G, *B, *A;
w = roundup2log(MAX(yn, xn));
R = xvalloc((1u << w) * (1u << w));
G = xvalloc((1u << w) * (1u << w));
B = xvalloc((1u << w) * (1u << w));
A = xvalloc((1u << w) * (1u << w));
DeblinterlaceRgba(w, R, G, B, A, yn, xn, img);
PrintImage(w, R, G, B, A, yn, xn);
free(R);
free(G);
free(B);
free(A);
}
static void ProcessImageDouble(LONG yn, LONG xn, unsigned char img[yn][xn][4]) {
CHAR w;
void *t, *R, *G, *B, *A;
w = roundup2log(MAX(yn, xn)) + 1;
t = xvalloc((1u << w) * (1u << w));
R = xvalloc((1u << w) * (1u << w));
G = xvalloc((1u << w) * (1u << w));
B = xvalloc((1u << w) * (1u << w));
A = xvalloc((1u << w) * (1u << w));
DeblinterlaceRgba(w, R, G, B, A, yn, xn, img);
Upscale(w, R, t, w, w);
Upscale(w, G, t, w, w);
Upscale(w, B, t, w, w);
Upscale(w, A, t, w, w);
free(t);
PrintImage(w, R, G, B, A, yn * 2, xn * 2);
free(R);
free(G);
free(B);
free(A);
}
static void ProcessImageHalf(LONG yn, LONG xn, unsigned char img[yn][xn][4]) {
CHAR w;
void *R, *G, *B, *A;
w = roundup2log(MAX(yn, xn));
R = xvalloc((1u << w) * (1u << w));
G = xvalloc((1u << w) * (1u << w));
B = xvalloc((1u << w) * (1u << w));
A = xvalloc((1u << w) * (1u << w));
DeblinterlaceRgba(w, R, G, B, A, yn, xn, img);
MagikarpY(w, R, w, w);
MagikarpY(w, G, w, w);
MagikarpY(w, B, w, w);
MagikarpY(w, A, w, w);
MagikarpX(w, R, w - 1, w);
MagikarpX(w, G, w - 1, w);
MagikarpX(w, B, w - 1, w);
MagikarpX(w, A, w - 1, w);
PrintImage(w, R, G, B, A, yn >> 1, xn >> 1);
free(R);
free(G);
free(B);
free(A);
}
static void ProcessImageHalfY(LONG yn, LONG xn, unsigned char img[yn][xn][4]) {
CHAR w;
void *R, *G, *B, *A;
w = roundup2log(MAX(yn, xn));
R = xvalloc((1u << w) * (1u << w));
G = xvalloc((1u << w) * (1u << w));
B = xvalloc((1u << w) * (1u << w));
A = xvalloc((1u << w) * (1u << w));
DeblinterlaceRgba(w, R, G, B, A, yn, xn, img);
MagikarpY(w, R, w, w);
MagikarpY(w, G, w, w);
MagikarpY(w, B, w, w);
MagikarpY(w, A, w, w);
PrintImage(w, R, G, B, A, yn >> 1, xn);
free(R);
free(G);
free(B);
free(A);
}
static void ProcessImageHalfLanczos(LONG yn, LONG xn,
unsigned char img[yn][xn][4]) {
CHAR w;
void *t, *R, *G, *B, *A;
t = xvalloc((yn >> 1) * (xn >> 1) * 4);
lanczos1b(yn >> 1, xn >> 1, t, yn, xn, &img[0][0][0]);
w = roundup2log(MAX(yn >> 1, xn >> 1));
R = xvalloc((1u << w) * (1u << w));
G = xvalloc((1u << w) * (1u << w));
B = xvalloc((1u << w) * (1u << w));
A = xvalloc((1u << w) * (1u << w));
DeblinterlaceRgba(w, R, G, B, A, yn >> 1, xn >> 1, img);
free(t);
PrintImage(w, R, G, B, A, yn >> 1, xn >> 1);
free(R);
free(G);
free(B);
free(A);
}
static void ProcessImageWash(LONG yn, LONG xn, unsigned char img[yn][xn][4]) {
long w;
void *R, *G, *B, *A, *t;
w = roundup2log(MAX(yn, xn)) + 1;
t = xvalloc((1u << w) * (1u << w));
R = xvalloc((1u << w) * (1u << w));
G = xvalloc((1u << w) * (1u << w));
B = xvalloc((1u << w) * (1u << w));
A = xvalloc((1u << w) * (1u << w));
DeblinterlaceRgba(w, R, G, B, A, yn, xn, img);
Upscale(w, R, t, w, w);
Upscale(w, G, t, w, w);
Upscale(w, B, t, w, w);
Upscale(w, A, t, w, w);
MagikarpY(w, R, w, w);
MagikarpY(w, G, w, w);
MagikarpY(w, B, w, w);
MagikarpY(w, A, w, w);
MagikarpX(w, R, w - 1, w);
MagikarpX(w, G, w - 1, w);
MagikarpX(w, B, w - 1, w);
MagikarpX(w, A, w - 1, w);
free(t);
PrintImage(w, R, G, B, A, yn, xn);
free(R);
free(G);
free(B);
free(A);
}
#endif
#if 0
static void *MagikarpY(size_t ys, size_t xs, unsigned char p[ys][xs], size_t yn,
size_t xn) {
int y, x, h, b;
b = yn % 2;
h = yn / 2;
if (b && yn < ys) yn++;
for (y = b; y < h + b; ++y) {
for (x = 0; x < xn; ++x) {
p[(yn - h - 1) + (h - y - 1)][x] =
C1331(p[MAX(00 + 0, yn - y * 2 - 1 - 1)][x],
p[MIN(yn - 1, yn - y * 2 - 1 + 0)][x],
p[MIN(yn - 1, yn - y * 2 - 1 + 1)][x],
p[MIN(yn - 1, yn - y * 2 - 1 + 2)][x]);
}
}
for (y = b; y < h + b; ++y) {
for (x = 0; x < xn; ++x) {
p[y][x] = C161(p[MAX(yn - 1 - h, yn - h - 1 + y - 1)][x],
p[MIN(yn - 1 - 0, yn - h - 1 + y + 0)][x],
p[MIN(yn - 1 - 0, yn - h - 1 + y + 1)][x]);
}
}
return p;
}
#endif
#if 0
static void *MagikarpX(size_t ys, size_t xs, unsigned char p[ys][xs], size_t yn,
size_t xn) {
int y, x, w, b;
b = xn % 2;
w = xn / 2;
if (b && xn < xs) xn++;
for (x = 0; x < w; ++x) {
for (y = b; y < yn + b; ++y) {
p[y][(xn - w - 1) + (w - x - 1)] =
C1331(p[y][MAX(00 + 0, xn - x * 2 - 1 - 1)],
p[y][MIN(xn - 1, xn - x * 2 - 1 + 0)],
p[y][MIN(xn - 1, xn - x * 2 - 1 + 1)],
p[y][MIN(xn - 1, xn - x * 2 - 1 + 2)]);
}
}
for (x = 0; x < w; ++x) {
for (y = b; y < yn + b; ++y) {
p[y][x] = C161(p[y][MAX(xn - 1 - w, xn - w - 1 + x - 1)],
p[y][MIN(xn - 1 - 0, xn - w - 1 + x + 0)],
p[y][MIN(xn - 1 - 0, xn - w - 1 + x + 1)]);
}
}
return p;
}
#endif
#if 0
static void ProcessImageMagikarpImpl(CHAR sw,
unsigned char src[5][1u << sw][1u << sw],
LONG syn, LONG sxn,
const unsigned char img[syn][sxn][4],
LONG dyn, LONG dxn) {
DeblinterlaceRgba2(sw, src, syn, sxn, img);
MagikarpY(sw, src[0], sw, sw);
MagikarpX(sw, src[0], sw - 1, sw);
MagikarpY(sw, src[1], sw, sw);
MagikarpX(sw, src[1], sw - 1, sw);
MagikarpY(sw, src[2], sw, sw);
MagikarpX(sw, src[2], sw - 1, sw);
BilinearScale(sw, src[4], sw, src[3], dyn, dxn, syn, sxn);
memcpy(src[3], src[4], syn * sxn);
PrintImage2(sw, src, dyn, dxn);
}
static void ProcessImageMagikarp(LONG syn, LONG sxn,
unsigned char img[syn][sxn][4]) {
CHAR sw;
LONG dyn, dxn;
dyn = syn >> 1;
dxn = sxn >> 1;
sw = roundup2log(MAX(syn, sxn));
ProcessImageMagikarpImpl(sw, gc(xvalloc((1u << sw) * (1u << sw) * 5)), syn,
sxn, img, dyn, dxn);
}
#endif
/*
********************************************************************************
*/
static unsigned char Opacify2(unsigned yw, unsigned xw,
const unsigned char P[yw][xw],
const unsigned char A[yw][xw], unsigned yn,
unsigned xn, unsigned y, unsigned x) {
if ((0 <= y && y < yn) && (0 <= x && x < xn)) {
return LERP(AlphaBackground(y, x), P[y][x], A[y][x]);
} else {
return OutOfBoundsBackground(y, x);
}
}
static noinline void PrintImage2(unsigned yw, unsigned xw,
unsigned char img[4][yw][xw], unsigned yn,
unsigned xn) {
bool didhalfy;
unsigned y, x;
didhalfy = false;
for (y = 0; y < yn; y += 2) {
if (y) printf("\e[0m\n");
for (x = 0; x < xn; ++x) {
printf("\e[48;2;%d;%d;%d;38;2;%d;%d;%dm▄",
Opacify2(yw, xw, img[0], img[3], yn, xn, y + 0, x),
Opacify2(yw, xw, img[1], img[3], yn, xn, y + 0, x),
Opacify2(yw, xw, img[2], img[3], yn, xn, y + 0, x),
Opacify2(yw, xw, img[0], img[3], yn, xn, y + 1, x),
Opacify2(yw, xw, img[1], img[3], yn, xn, y + 1, x),
Opacify2(yw, xw, img[2], img[3], yn, xn, y + 1, x));
}
if (y == 0) {
printf("\e[0m‾0");
} else if (yn / 2 <= y && y <= yn / 2 + 1 && !didhalfy) {
printf("\e[0m‾%s%s", "yn/2", y % 2 ? "+1" : "");
didhalfy = true;
} else if (y + 1 == yn / 2 && !didhalfy) {
printf("\e[0m⎯yn/2");
didhalfy = true;
} else if (y + 1 == yn) {
printf("\e[0m⎯yn");
} else if (y + 2 == yn) {
printf("\e[0m_yn");
} else if (!(y % 10)) {
printf("\e[0m‾%,u", y);
}
}
printf("\e[0m\n");
}
static noinline void *DeblinterlaceRgba2(unsigned yn, unsigned xn,
unsigned char D[4][yn][xn],
const unsigned char S[yn][xn][4]) {
unsigned y, x;
for (y = 0; y < yn; ++y) {
for (x = 0; x < xn; ++x) {
D[0][y][x] = S[y][x][0];
D[1][y][x] = S[y][x][1];
D[2][y][x] = S[y][x][2];
D[3][y][x] = S[y][x][3];
}
}
return D;
}
void ProcessImageBilinearImpl(unsigned dyn, unsigned dxn,
unsigned char dst[4][dyn][dxn], unsigned syn,
unsigned sxn, unsigned char src[4][syn][sxn],
unsigned char img[syn][sxn][4]) {
DeblinterlaceRgba2(syn, sxn, src, img);
BilinearScale(4, dyn, dxn, dst, 4, syn, sxn, src, 0, 4, dyn, dxn, syn, sxn,
r_, r_, 0, 0);
PrintImage2(dyn, dxn, dst, dyn, dxn);
}
void ProcessImageBilinear(unsigned yn, unsigned xn,
unsigned char img[yn][xn][4]) {
unsigned dyn, dxn;
dyn = lround(yn / r_);
dxn = lround(xn / r_);
ProcessImageBilinearImpl(dyn, dxn, gc(xmalloc(dyn * dxn * 4)), yn, xn,
gc(xmalloc(yn * xn * 4)), img);
}
static void *b2f(long n, float dst[n], const unsigned char src[n]) {
long i;
float f;
for (i = 0; i < n; ++i) {
f = src[i];
f *= 1 / 255.;
dst[i] = f;
}
return dst;
}
static void *f2b(long n, unsigned char dst[n], const float src[n]) {
int x;
long i;
for (i = 0; i < n; ++i) {
x = lroundf(src[i] * 255);
dst[i] = MIN(255, MAX(0, x));
}
return dst;
}
void ProcessImageGyarados(unsigned yn, unsigned xn,
unsigned char img[yn][xn][4]) {
unsigned dyn, dxn;
dyn = lround(yn / r_);
dxn = lround(xn / r_);
PrintImage2(
dyn, dxn,
EzGyarados(4, dyn, dxn, gc(xmalloc(dyn * dxn * 4)), 4, yn, xn,
DeblinterlaceRgba2(yn, xn, gc(xmalloc(yn * xn * 4)), img), 0,
4, dyn, dxn, yn, xn, r_, r_, 0, 0),
dyn, dxn);
}
void MagikarpDecimate(int yw, int xw, unsigned char img[4][yw][xw], int yn,
int xn, int n) {
int c;
if (n <= 1) {
PrintImage2(yw, xw, img, yn, xn);
} else {
for (c = 0; c < 4; ++c) Magikarp2xY(yw, xw, img[c], yn, xn);
for (c = 0; c < 4; ++c) Magikarp2xX(yw, xw, img[c], (yn + 1) / 2, xn);
MagikarpDecimate(yw, xw, img, (yn + 1) / 2, (xn + 1) / 2, (n + 1) / 2);
}
}
void ProcessImageMagikarp(unsigned yn, unsigned xn,
unsigned char img[yn][xn][4]) {
MagikarpDecimate(yn, xn,
DeblinterlaceRgba2(yn, xn, gc(xmalloc(yn * xn * 4)), img),
yn, xn, lround(r_));
}
void *ProcessImageLanczosImpl(unsigned dyn, unsigned dxn,
float dst[4][dyn][dxn], unsigned syn,
unsigned sxn, float src[4][syn][sxn]) {
unsigned k;
struct lanczos1f scaler = {0};
lanczos1finit(&scaler);
for (k = 0; k < 4; ++k) {
lanczos1f(&scaler, dyn, dxn, dst[k], syn, sxn, sxn, src[k], r_, r_, 0, 0);
}
lanczos1ffree(&scaler);
return dst;
}
void ProcessImageLanczos(unsigned yn, unsigned xn,
unsigned char img[yn][xn][4]) {
unsigned dyn, dxn;
dyn = lround(yn / r_);
dxn = lround(xn / r_);
PrintImage2(
dyn, dxn,
f2b(dyn * dxn * 4, gc(xmalloc(dyn * dxn * 4)),
ProcessImageLanczosImpl(
dyn, dxn, gc(xmalloc(dyn * dxn * 4 * 4)), yn, xn,
b2f(yn * xn * 4, gc(xmalloc(yn * xn * 4 * 4)),
DeblinterlaceRgba2(yn, xn, gc(xmalloc(yn * xn * 4)), img)))),
dyn, dxn);
}
noinline void WithImageFile(const char *path,
void fn(unsigned yn, unsigned xn,
unsigned char img[yn][xn][4])) {
struct stat st;
int fd, yn, xn;
void *map, *data;
CHECK_NE(-1, (fd = open(path, O_RDONLY)), "%s", path);
CHECK_NE(-1, fstat(fd, &st));
CHECK_GT(st.st_size, 0);
CHECK_LE(st.st_size, INT_MAX);
fadvise(fd, 0, 0, MADV_WILLNEED | MADV_SEQUENTIAL);
CHECK_NE(MAP_FAILED,
(map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)));
CHECK_NOTNULL(
(data = stbi_load_from_memory(map, st.st_size, &xn, &yn, NULL, 4)), "%s",
path);
CHECK_NE(-1, munmap(map, st.st_size));
CHECK_NE(-1, close(fd));
fn(yn, xn, data);
free(data);
}
int main(int argc, char *argv[]) {
int i, opt;
bool bilinear;
void (*scaler)(unsigned yn, unsigned xn, unsigned char[yn][xn][4]) =
ProcessImageMagikarp;
r_ = 2;
while ((opt = getopt(argc, argv, "mlsSybr:")) != -1) {
switch (opt) {
case 'r':
r_ = strtod(optarg, NULL);
break;
case 'm':
scaler = ProcessImageMagikarp;
break;
case 's':
case 'S':
scaler = ProcessImageGyarados;
break;
case 'l':
scaler = ProcessImageLanczos;
break;
case 'b':
scaler = ProcessImageBilinear;
break;
default:
break;
}
}
cancolor();
showcrashreports();
for (i = optind; i < argc; ++i) {
WithImageFile(argv[i], scaler);
}
return 0;
}

110
tool/viz/od16.c Normal file
View file

@ -0,0 +1,110 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/conv/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/log/check.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "third_party/getopt/getopt.h"
#define USAGE \
" [FLAGS] [PATH...]\n\
this program prints binary as signed 16-bit decimal numbers\n\
\n\
Flags:\n\
-n INT\n\
-c INT\n\
-w INT width (aka cols) [default 8]\n\
-o PATH output path [default -]\n\
-h shows this information\n\
\n"
static long width_;
static FILE *in_, *out_;
static char *inpath_, *outpath_;
void PrintUsage(int rc, FILE *f) {
fputs("Usage: ", f);
fputs(program_invocation_name, f);
fputs(USAGE, f);
exit(rc);
}
void GetOpts(int *argc, char *argv[]) {
int opt;
outpath_ = "-";
while ((opt = getopt(*argc, argv, "?ho:w:c:n:")) != -1) {
switch (opt) {
case 'o':
outpath_ = optarg;
break;
case 'n':
case 'c':
case 'w':
width_ = strtol(optarg, NULL, 0);
break;
case '?':
case 'h':
PrintUsage(EXIT_SUCCESS, stdout);
default:
PrintUsage(EX_USAGE, stderr);
}
}
if (optind == *argc) {
argv[(*argc)++] = "-";
}
}
void ProcessFile(void) {
int a, b;
unsigned n;
n = 0;
while ((a = fgetc(in_)) != -1 && (b = fgetc(in_)) != -1) {
if (n) {
fputc(',', out_);
fputc(' ', out_);
}
fprintf(out_, "%7hd", b << 010 | a);
if (++n == width_) {
n = 0;
fputc('\n', out_);
}
}
if (n) {
fputc('\n', out_);
}
}
int main(int argc, char *argv[]) {
size_t i;
GetOpts(&argc, argv);
CHECK_NOTNULL((out_ = fopen(outpath_, "w")));
for (i = optind; i < argc; ++i) {
CHECK_NOTNULL((in_ = fopen((inpath_ = argv[i]), "r")));
ProcessFile();
CHECK_NE(-1, fclose_s(&in_));
}
CHECK_NE(-1, fclose_s(&out_));
return 0;
}

263
tool/viz/printimage.c Normal file
View file

@ -0,0 +1,263 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/math.h"
#include "libc/mem/mem.h"
#include "libc/rand/rand.h"
#include "libc/runtime/gc.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "libc/x/x.h"
#include "third_party/getopt/getopt.h"
#include "third_party/stb/stb_image.h"
#define LERP(X, Y, P) (((X) + (SAR((P) * ((Y) - (X)), 8))) & 0xff)
static struct Flags {
const char *out;
bool subpixel;
} g_flags;
static noreturn void PrintUsage(int rc, FILE *f) {
fprintf(f, "Usage: %s%s", program_invocation_name, "\
[FLAGS] [PATH]\n\
\n\
Flags:\n\
-o PATH output path\n\
-p convert to subpixel layout\n\
-v increases verbosity\n\
-? shows this information\n\
\n");
exit(rc);
}
static void GetOpts(int *argc, char *argv[]) {
int opt;
if (*argc == 2 &&
(strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-help") == 0)) {
PrintUsage(EXIT_SUCCESS, stdout);
}
while ((opt = getopt(*argc, argv, "?vpo:")) != -1) {
switch (opt) {
case 'o':
g_flags.out = optarg;
break;
case 'v':
++g_loglevel;
break;
case 'p':
g_flags.subpixel = true;
break;
case '?':
PrintUsage(EXIT_SUCCESS, stdout);
default:
PrintUsage(EX_USAGE, stderr);
}
}
if (optind == *argc) {
if (!g_flags.out) g_flags.out = "-";
argv[(*argc)++] = "-";
}
}
static unsigned char ChessBoard(unsigned y, unsigned x, unsigned char a,
unsigned char b) {
return !((y ^ x) & (1u << 2)) ? a : b;
}
static unsigned char AlphaBackground(unsigned y, unsigned x) {
return ChessBoard(y, x, 255, 200);
}
static unsigned char OutOfBoundsBackground(unsigned y, unsigned x) {
return ChessBoard(y, x, 40, 80);
}
static unsigned char Opacify(long yn, long xn, const unsigned char P[yn][xn],
const unsigned char A[yn][xn], long y, long x) {
if ((0 <= y && y < yn) && (0 <= x && x < xn)) {
return LERP(AlphaBackground(y, x), P[y][x], A[y][x]);
} else {
return OutOfBoundsBackground(y, x);
}
}
static void PrintRulerRight(long yn, long xn, long y, long x,
bool *inout_didhalfy) {
if (y == 0) {
printf("\e[0m‾0");
} else if (yn / 2 <= y && y <= yn / 2 + 1 && !*inout_didhalfy) {
printf("\e[0m‾%s%s", "yn/2", y % 2 ? "+1" : "");
*inout_didhalfy = true;
} else if (y + 1 == yn / 2 && !*inout_didhalfy) {
printf("\e[0m⎯yn/2");
*inout_didhalfy = true;
} else if (y + 1 == yn) {
printf("\e[0m⎯yn");
} else if (y + 2 == yn) {
printf("\e[0m_yn");
} else if (!(y % 10)) {
printf("\e[0m‾%,u", y);
}
}
static void PrintImageImpl(long syn, long sxn, unsigned char RGB[3][syn][sxn],
long y0, long yn, long x0, long xn, bool rule,
long dy, long dx) {
long y, x;
bool didhalfy, didfirstx;
unsigned char a[3], b[3];
didhalfy = false;
for (y = y0; y < yn; y += dy) {
didfirstx = false;
if (y) printf("\e[0m\n");
for (x = x0; x < xn; x += dx) {
a[0] = RGB[0][y][x];
a[1] = RGB[1][y][x];
a[2] = RGB[2][y][x];
if (y + dy < yn && x + dx < xn) {
b[0] = RGB[0][y + dy][x + dx];
b[1] = RGB[1][y + dy][x + dx];
b[2] = RGB[2][y + dy][x + dx];
} else {
b[2] = b[1] = b[0] = OutOfBoundsBackground(y + dy, x + dx);
}
printf("\e[48;2;%d;%d;%d;38;2;%d;%d;%dm%lc", a[0], a[1], a[2], b[0], b[1],
b[2], dy > 1 ? u'' : u'');
didfirstx = true;
}
if (rule) PrintRulerRight(yn, xn, y, x, &didhalfy);
}
printf("\e[0m\n");
}
static void PrintImage(long syn, long sxn, unsigned char RGB[3][syn][sxn],
long y0, long yn, long x0, long xn, bool rule) {
PrintImageImpl(syn, sxn, RGB, y0, yn, x0, xn, rule, 2, 1);
}
static void PrintImageLR(long syn, long sxn, unsigned char RGB[3][syn][sxn],
long y0, long yn, long x0, long xn, bool rule) {
PrintImageImpl(syn, sxn, RGB, y0, yn, x0, xn, rule, 1, 2);
}
static void *Deblinterlace(long dyn, long dxn, unsigned char dst[3][dyn][dxn],
long syn, long sxn,
const unsigned char src[syn][sxn][4], long y0,
long yn, long x0, long xn) {
long y, x;
for (y = y0; y < yn; ++y) {
for (x = x0; x < xn; ++x) {
dst[0][y][x] = src[y][x][0];
dst[1][y][x] = src[y][x][1];
dst[2][y][x] = src[y][x][2];
}
}
return dst;
}
static void *DeblinterlaceSubpixelBgr(long dyn, long dxn,
unsigned char dst[3][dyn][dxn][3],
long syn, long sxn,
const unsigned char src[syn][sxn][4],
long y0, long yn, long x0, long xn) {
long y, x;
for (y = y0; y < yn; ++y) {
for (x = x0; x < xn; ++x) {
dst[0][y][x][0] = 0;
dst[1][y][x][0] = 0;
dst[2][y][x][0] = src[y][x][2];
dst[0][y][x][1] = 0;
dst[1][y][x][1] = src[y][x][1];
dst[2][y][x][1] = 0;
dst[0][y][x][2] = src[y][x][0];
dst[1][y][x][2] = 0;
dst[2][y][x][2] = 0;
}
}
return dst;
}
static void ProcessImage(long syn, long sxn, unsigned char RGB[syn][sxn][4],
long cn) {
if (g_flags.subpixel) {
PrintImageLR(
syn, sxn * 3,
DeblinterlaceSubpixelBgr(
syn, sxn,
gc(memalign(32, sizeof(unsigned char) * syn * sxn * 3 * 3)), syn,
sxn, RGB, 0, syn, 0, sxn),
0, syn, 0, sxn * 3, true);
} else {
PrintImage(
syn, sxn,
Deblinterlace(syn, sxn,
gc(memalign(32, sizeof(unsigned char) * syn * sxn * 3)),
syn, sxn, RGB, 0, syn, 0, sxn),
0, syn, 0, sxn, true);
}
}
void WithImageFile(const char *path,
void fn(long syn, long sxn, unsigned char RGB[syn][sxn][4],
long cn)) {
struct stat st;
void *map, *data;
int fd, yn, xn, cn;
CHECK_NE(-1, (fd = open(path, O_RDONLY)), "%s", path);
CHECK_NE(-1, fstat(fd, &st));
CHECK_GT(st.st_size, 0);
CHECK_LE(st.st_size, INT_MAX);
fadvise(fd, 0, 0, MADV_WILLNEED | MADV_SEQUENTIAL);
CHECK_NE(MAP_FAILED,
(map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)));
CHECK_NOTNULL(
(data = stbi_load_from_memory(map, st.st_size, &xn, &yn, &cn, 4)), "%s",
path);
CHECK_NE(-1, munmap(map, st.st_size));
CHECK_NE(-1, close(fd));
fn(yn, xn, data, 4);
free(data);
}
int main(int argc, char *argv[]) {
int i;
showcrashreports();
GetOpts(&argc, argv);
stbi_set_unpremultiply_on_load(true);
for (i = optind; i < argc; ++i) {
WithImageFile(argv[i], ProcessImage);
}
return 0;
}

543
tool/viz/printpeb.c Normal file
View file

@ -0,0 +1,543 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/log/log.h"
#include "libc/nt/dll.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/enum/startf.h"
#include "libc/nt/files.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/ldr.h"
#include "libc/nt/struct/ldrdatatableentry.h"
#include "libc/nt/struct/linkedlist.h"
#include "libc/nt/struct/peb.h"
#include "libc/nt/struct/systeminfo.h"
#include "libc/nt/struct/teb.h"
#include "libc/nt/struct/unicodestring.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/o.h"
#include "tool/decode/lib/flagger.h"
#include "tool/decode/lib/idname.h"
char *GetString(struct NtUnicodeString *s) {
static char buf[1024];
unsigned len = min(sizeof(buf) - 1, s->Length);
for (unsigned i = 0; i < len; ++i) {
buf[i] = (unsigned char)s->Data[i];
}
buf[len] = '\0';
return &buf[0];
}
int NextBestThing(void) {
int64_t fd = open("/proc/self/maps", O_RDONLY);
posix_fadvise(fd, 0, 0, MADV_SEQUENTIAL);
ssize_t wrote;
while ((wrote = copyfd(fd, NULL, 1, NULL, 1024 * 64, 0)) != -1) {
if (wrote == 0) break;
}
close(fd);
return 0;
}
const struct IdName kNtStartfFlagNames[] = {
{kNtStartfUseshowwindow, "kNtStartfUseshowwindow"},
{kNtStartfUsesize, "kNtStartfUsesize"},
{kNtStartfUseposition, "kNtStartfUseposition"},
{kNtStartfUsecountchars, "kNtStartfUsecountchars"},
{kNtStartfUsefillattribute, "kNtStartfUsefillattribute"},
{kNtStartfRunfullscreen, "kNtStartfRunfullscreen"},
{kNtStartfForceonfeedback, "kNtStartfForceonfeedback"},
{kNtStartfForceofffeedback, "kNtStartfForceofffeedback"},
{kNtStartfUsestdhandles, "kNtStartfUsestdhandles"},
{kNtStartfUsehotkey, "kNtStartfUsehotkey"},
{kNtStartfTitleislinkname, "kNtStartfTitleislinkname"},
{kNtStartfTitleisappid, "kNtStartfTitleisappid"},
{kNtStartfPreventpinning, "kNtStartfPreventpinning"},
{kNtStartfUntrustedsource, "kNtStartfUntrustedsource"},
{0, 0},
};
void PrintStartupInfo(void) {
printf(
"\n\
\n\
new technology § startup info \n\
\n\
\n");
#define X(D, F) \
printf("%s.%-22s= " D "\n", "g_ntstartupinfo", #F, g_ntstartupinfo.F);
X("%u", cb);
X("%p", lpReserved);
X("%hs", lpDesktop);
X("%hs", lpTitle);
X("%u", dwX);
X("%u", dwY);
X("%u", dwXSize);
X("%u", dwYSize);
X("%u", dwXCountChars);
X("%u", dwYCountChars);
X("%u", dwFillAttribute);
printf("%s.%-22s: %s\n", "g_ntstartupinfo", "dwFlags",
recreateflags(kNtStartfFlagNames, g_ntstartupinfo.dwFlags));
X("%hu", wShowWindow);
X("%hu", cbReserved2);
X("%s", lpReserved2);
X("%ld", hStdInput);
X("%ld", hStdOutput);
X("%ld", hStdError);
#undef X
}
void PrintSystemInfo(void) {
printf(
"\n\
\n\
new technology § system info \n\
\n\
\n");
#define X(D, F) \
printf("%s.%-28s= " D "\n", "g_ntsysteminfo", #F, g_ntsysteminfo.F);
X("%08x", dwOemId);
X("%04hx", wProcessorArchitecture);
X("%d", dwPageSize);
X("%p", lpMinimumApplicationAddress);
X("%p", lpMaximumApplicationAddress);
X("%p", dwActiveProcessorMask);
X("%u", dwNumberOfProcessors);
X("%u", dwProcessorType);
X("%u", dwAllocationGranularity);
X("%hu", wProcessorLevel);
X("%hu", wProcessorRevision);
#undef X
}
const char *ft2str(enum NtFileType ft) {
if (ft == kNtFileTypeUnknown) return "kNtFileTypeUnknown";
if (ft == kNtFileTypeDisk) return "kNtFileTypeDisk";
if (ft == kNtFileTypeChar) return "kNtFileTypeChar";
if (ft == kNtFileTypePipe) return "kNtFileTypePipe";
if (ft == kNtFileTypeRemote) return "kNtFileTypeRemote";
return "wut?";
}
void PrintStdioInfo(void) {
printf(
"\n\
\n\
new technology § stdio info \n\
\n\
\n");
printf("%s: %ld (%s)\n", "g_fds.p[0].handle", g_fds.p[0].handle,
ft2str(GetFileType(g_fds.p[0].handle)));
printf("%s: %ld (%s)\n", "g_fds.p[1].handle", g_fds.p[1].handle,
ft2str(GetFileType(g_fds.p[1].handle)));
printf("%s: %ld (%s)\n", "g_fds.p[2].handle", g_fds.p[2].handle,
ft2str(GetFileType(g_fds.p[2].handle)));
}
void PrintTeb(void) {
GetCurrentProcessId();
SetLastError(0x1234);
printf(
"\n\
\n\
new technology § teb? \n\
\n\
\n");
printf("gs:0x%02x: %-39s = 0x%lx\n", 0x00, "NtGetSeh()", _NtGetSeh());
printf("gs:0x%02x: %-39s = 0x%lx\n", 0x08, "NtGetStackHigh()",
_NtGetStackHigh());
printf("gs:0x%02x: %-39s = 0x%lx\n", 0x10, "NtGetStackLow()",
_NtGetStackLow());
printf("gs:0x%02x: %-39s = 0x%lx\n", 0x18, "_NtGetSubsystemTib()",
_NtGetSubsystemTib());
printf("gs:0x%02x: %-39s = 0x%lx\n", 0x20, "NtGetFib()", _NtGetFib());
printf("gs:0x%02x: %-39s = 0x%lx\n", 0x30, "NtGetTeb()", NtGetTeb());
printf("gs:0x%02x: %-39s = 0x%lx\n", 0x38, "NtGetEnv()", _NtGetEnv());
printf("gs:0x%02x: %-39s = 0x%lx\n", 0x40, "NtGetPid()", NtGetPid());
printf("gs:0x%02x: %-39s = 0x%lx\n", 0x48, "NtGetTid()", NtGetTid());
printf("gs:0x%02x: %-39s = 0x%lx\n", 0x50, "NtGetRpc()", _NtGetRpc());
printf("gs:0x%02x: %-39s = 0x%lx\n", 0x58, "NtGetTls()", _NtGetTls());
printf("gs:0x%02x: %-39s = 0x%lx\n", 0x60, "NtGetPeb()", NtGetPeb());
printf("gs:0x%02x: %-39s = 0x%lx\n", 0x68, "NtGetErr()", NtGetErr());
}
void PrintPeb(void) {
struct NtPeb *peb = NtGetPeb();
printf(
"\n\
\n\
new technology § peb \n\
\n\
\n");
printf("0x%04x: %-40s = %u\n", offsetof(struct NtPeb, InheritedAddressSpace),
"InheritedAddressSpace", (unsigned)peb->InheritedAddressSpace);
printf("0x%04x: %-40s = %u\n",
offsetof(struct NtPeb, ReadImageFileExecOptions),
"ReadImageFileExecOptions", (unsigned)peb->ReadImageFileExecOptions);
printf("0x%04x: %-40s = %u\n", offsetof(struct NtPeb, BeingDebugged),
"BeingDebugged", (unsigned)peb->BeingDebugged);
printf("0x%04x: %-40s = %u\n", offsetof(struct NtPeb, __wut1), "__wut1",
(unsigned)peb->__wut1);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, Mutant), "Mutant",
peb->Mutant);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, ImageBaseAddress),
"ImageBaseAddress", peb->ImageBaseAddress);
/* struct NtLdr *Ldr; */
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, ProcessParameters),
"ProcessParameters", peb->ProcessParameters);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, SubSystemData),
"SubSystemData", peb->SubSystemData);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, ProcessHeap),
"ProcessHeap", peb->ProcessHeap);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, FastPebLock),
"FastPebLock", peb->FastPebLock);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, __wut3), "__wut3",
peb->__wut3);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, __wut4), "__wut4",
peb->__wut4);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, __wut5), "__wut5",
peb->__wut5);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, KernelCallbackTable),
"KernelCallbackTable", peb->KernelCallbackTable);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, UserSharedInfoPtr),
"UserSharedInfoPtr", peb->UserSharedInfoPtr);
printf("0x%04x: %-40s = 0x%x\n", offsetof(struct NtPeb, SystemReserved),
"SystemReserved", peb->SystemReserved);
printf("0x%04x: %-40s = 0x%x\n", offsetof(struct NtPeb, __wut6), "__wut6",
peb->__wut6);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, __wut7), "__wut7",
peb->__wut7);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, TlsExpansionCounter),
"TlsExpansionCounter", peb->TlsExpansionCounter);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, TlsBitmap),
"TlsBitmap", peb->TlsBitmap);
printf("0x%04x: %-40s = 0x%x 0x%x\n", offsetof(struct NtPeb, TlsBitmapBits),
"TlsBitmapBits", peb->TlsBitmapBits[0], peb->TlsBitmapBits[1]);
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtPeb, ReadOnlySharedMemoryBase),
"ReadOnlySharedMemoryBase", peb->ReadOnlySharedMemoryBase);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, __wut8), "__wut8",
peb->__wut8);
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtPeb, ReadOnlyStaticServerData),
"ReadOnlyStaticServerData", peb->ReadOnlyStaticServerData);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, AnsiCodePageData),
"AnsiCodePageData", peb->AnsiCodePageData);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, OemCodePageData),
"OemCodePageData", peb->OemCodePageData);
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtPeb, UnicodeCaseTableData), "UnicodeCaseTableData",
peb->UnicodeCaseTableData);
printf("0x%04x: %-40s = 0x%x\n", offsetof(struct NtPeb, NumberOfProcessors),
"NumberOfProcessors", peb->NumberOfProcessors);
printf("0x%04x: %-40s = 0x%x\n", offsetof(struct NtPeb, NtGlobalFlag),
"NtGlobalFlag", peb->NtGlobalFlag);
printf("0x%04x: %-40s = %ld\n",
offsetof(struct NtPeb, CriticalSectionTimeout),
"CriticalSectionTimeout", peb->CriticalSectionTimeout);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, HeapSegmentReserve),
"HeapSegmentReserve", peb->HeapSegmentReserve);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, HeapSegmentCommit),
"HeapSegmentCommit", peb->HeapSegmentCommit);
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtPeb, HeapDeCommitTotalFreeThreshold),
"HeapDeCommitTotalFreeThreshold", peb->HeapDeCommitTotalFreeThreshold);
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtPeb, HeapDeCommitFreeBlockThreshold),
"HeapDeCommitFreeBlockThreshold", peb->HeapDeCommitFreeBlockThreshold);
printf("0x%04x: %-40s = 0x%x\n", offsetof(struct NtPeb, NumberOfHeaps),
"NumberOfHeaps", peb->NumberOfHeaps);
printf("0x%04x: %-40s = 0x%x\n", offsetof(struct NtPeb, MaximumNumberOfHeaps),
"MaximumNumberOfHeaps", peb->MaximumNumberOfHeaps);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, ProcessHeaps),
"ProcessHeaps", peb->ProcessHeaps);
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtPeb, GdiSharedHandleTable), "GdiSharedHandleTable",
peb->GdiSharedHandleTable);
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtPeb, ProcessStarterHelper), "ProcessStarterHelper",
peb->ProcessStarterHelper);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, GdiDCAttributeList),
"GdiDCAttributeList", peb->GdiDCAttributeList);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, LoaderLock),
"LoaderLock", peb->LoaderLock);
printf("0x%04x: %-40s = 0x%x\n", offsetof(struct NtPeb, OSMajorVersion),
"OSMajorVersion", peb->OSMajorVersion);
printf("0x%04x: %-40s = 0x%x\n", offsetof(struct NtPeb, OSMinorVersion),
"OSMinorVersion", peb->OSMinorVersion);
printf("0x%04x: %-40s = %hu\n", offsetof(struct NtPeb, OSBuildNumber),
"OSBuildNumber", peb->OSBuildNumber);
printf("0x%04x: %-40s = %hu\n", offsetof(struct NtPeb, OSCSDVersion),
"OSCSDVersion", peb->OSCSDVersion);
printf("0x%04x: %-40s = 0x%x\n", offsetof(struct NtPeb, OSPlatformId),
"OSPlatformId", peb->OSPlatformId);
printf("0x%04x: %-40s = 0x%x\n", offsetof(struct NtPeb, ImageSubsystem),
"ImageSubsystem", peb->ImageSubsystem);
printf("0x%04x: %-40s = 0x%x\n",
offsetof(struct NtPeb, ImageSubsystemMajorVersion),
"ImageSubsystemMajorVersion", peb->ImageSubsystemMajorVersion);
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtPeb, ImageSubsystemMinorVersion),
"ImageSubsystemMinorVersion", peb->ImageSubsystemMinorVersion);
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtPeb, ImageProcessAffinityMask),
"ImageProcessAffinityMask", peb->ImageProcessAffinityMask);
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtPeb, ActiveProcessAffinityMask),
"ActiveProcessAffinityMask", peb->ActiveProcessAffinityMask);
/* "0x%lx", GdiHandleBuffer[38 - __SIZEOF_POINTER__]; */
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtPeb, PostProcessInitRoutine),
"PostProcessInitRoutine", peb->PostProcessInitRoutine);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, TlsExpansionBitmap),
"TlsExpansionBitmap", peb->TlsExpansionBitmap);
/* "0x%x", TlsExpansionBitmapBits[32]; */
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, SessionId),
"SessionId", peb->SessionId);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, AppCompatFlags),
"AppCompatFlags", peb->AppCompatFlags);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, AppCompatFlagsUser),
"AppCompatFlagsUser", peb->AppCompatFlagsUser);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, pShimData),
"pShimData", peb->pShimData);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, AppCompatInfo),
"AppCompatInfo", peb->AppCompatInfo);
printf("0x%04x: %-40s = \"%s\"\n", offsetof(struct NtPeb, CSDVersion),
"CSDVersion", GetString(&peb->CSDVersion));
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtPeb, ActivationContextData), "ActivationContextData",
peb->ActivationContextData);
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtPeb, ProcessAssemblyStorageMap),
"ProcessAssemblyStorageMap", peb->ProcessAssemblyStorageMap);
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtPeb, SystemDefaultActivationContextData),
"SystemDefaultActivationContextData",
peb->SystemDefaultActivationContextData);
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtPeb, SystemAssemblyStorageMap),
"SystemAssemblyStorageMap", peb->SystemAssemblyStorageMap);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, MinimumStackCommit),
"MinimumStackCommit", peb->MinimumStackCommit);
}
void PrintPebLdr(void) {
printf(
"\n\
\n\
new technology § peb » ldr \n\
\n\
\n");
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtLdr, SizeOfThis),
"SizeOfThis", NtGetPeb()->Ldr->SizeOfThis);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtLdr, IsInitialized),
"IsInitialized", NtGetPeb()->Ldr->IsInitialized);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtLdr, SsHandle),
"SsHandle", NtGetPeb()->Ldr->SsHandle);
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtLdr, InLoadOrderModuleList), "InLoadOrderModuleList",
NtGetPeb()->Ldr->InLoadOrderModuleList);
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtLdr, InMemoryOrderModuleList),
"InMemoryOrderModuleList", NtGetPeb()->Ldr->InMemoryOrderModuleList);
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtLdr, InInitOrderModuleList), "InInitOrderModuleList",
NtGetPeb()->Ldr->InInitOrderModuleList);
}
void PrintModulesLoadOrder(void) {
{
printf(
"\n\
\n\
new technology § modules » load order \n\
\n\
\n");
struct NtLinkedList *head = &NtGetPeb()->Ldr->InLoadOrderModuleList;
struct NtLinkedList *ldr = head->Next;
do {
const struct NtLdrDataTableEntry *dll =
(const struct NtLdrDataTableEntry *)ldr;
/* struct NtLinkedList InLoadOrderLinks; /\* msdn:reserved *\/ */
/* struct NtLinkedList InMemoryOrderLinks; */
/* struct NtLinkedList InInitOrderLinks; /\* msdn:reserved *\/ */
printf("0x%p\n", ldr);
printf("0x%p vs. 0x%p\n", dll, GetModuleHandleW(dll->FullDllName.Data));
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtLdrDataTableEntry, DllBase), "DllBase",
dll->DllBase);
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtLdrDataTableEntry, EntryPoint), "EntryPoint",
dll->EntryPoint);
printf("0x%04x: %-40s = 0x%x\n",
offsetof(struct NtLdrDataTableEntry, SizeOfImage), "SizeOfImage",
dll->SizeOfImage);
printf("0x%04x: %-40s = \"%s\"\n",
offsetof(struct NtLdrDataTableEntry, FullDllName), "FullDllName",
GetString(&dll->FullDllName));
printf("0x%04x: %-40s = \"%s\"\n",
offsetof(struct NtLdrDataTableEntry, BaseDllName), "BaseDllName",
GetString(&dll->BaseDllName));
printf("0x%04x: %-40s = 0x%x\n",
offsetof(struct NtLdrDataTableEntry, Flags), "Flags", dll->Flags);
printf("0x%04x: %-40s = %hu\n",
offsetof(struct NtLdrDataTableEntry, Load_Count), "Load_Count",
dll->Load_Count);
printf("0x%04x: %-40s = %hu\n",
offsetof(struct NtLdrDataTableEntry, TlsIndex), "TlsIndex",
dll->TlsIndex);
/* union { */
/* struct NtLinkedList HashLinks; */
/* struct { */
/* void *SectionPointer; */
/* uint32_t CheckSum; */
/* }; */
/* }; */
/* union { */
/* void *LoadedImports; */
/* uint32_t TimeDateStamp; */
/* }; */
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtLdrDataTableEntry, EntryPointActivationContext),
"EntryPointActivationContext", dll->EntryPointActivationContext);
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtLdrDataTableEntry, PatchInformation),
"PatchInformation", dll->PatchInformation);
/* struct NtLinkedList ForwarderLinks; */
/* struct NtLinkedList ServiceTagLinks; */
/* struct NtLinkedList StaticLinks; */
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtLdrDataTableEntry, ContextInformation),
"ContextInformation", dll->ContextInformation);
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtLdrDataTableEntry, OriginalBase), "OriginalBase",
dll->OriginalBase);
printf("0x%04x: %-40s = %ld\n",
offsetof(struct NtLdrDataTableEntry, LoadTime), "LoadTime",
dll->LoadTime);
printf("\n");
} while ((ldr = ldr->Next) && ldr != head);
}
}
void PrintModulesMemoryOrder(void) {
{
printf(
"\n\
\n\
new technology § modules » memory order \n\
\n\
\n");
struct NtLinkedList *head = &NtGetPeb()->Ldr->InMemoryOrderModuleList;
struct NtLinkedList *ldr = head->Next;
do {
const struct NtLdrDataTableEntry *dll =
(const struct NtLdrDataTableEntry *)ldr;
/* struct NtLinkedList InLoadOrderLinks; /\* msdn:reserved *\/ */
/* struct NtLinkedList InMemoryOrderLinks; */
/* struct NtLinkedList InInitOrderLinks; /\* msdn:reserved *\/ */
printf("0x%p\n", dll);
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtLdrDataTableEntry, DllBase), "DllBase",
dll->DllBase);
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtLdrDataTableEntry, EntryPoint), "EntryPoint",
dll->EntryPoint);
printf("0x%04x: %-40s = 0x%x\n",
offsetof(struct NtLdrDataTableEntry, SizeOfImage), "SizeOfImage",
dll->SizeOfImage);
printf("0x%04x: %-40s = \"%s\"\n",
offsetof(struct NtLdrDataTableEntry, FullDllName), "FullDllName",
GetString(&dll->FullDllName));
printf("0x%04x: %-40s = \"%s\"\n",
offsetof(struct NtLdrDataTableEntry, BaseDllName), "BaseDllName",
GetString(&dll->BaseDllName));
printf("0x%04x: %-40s = 0x%x\n",
offsetof(struct NtLdrDataTableEntry, Flags), "Flags", dll->Flags);
printf("0x%04x: %-40s = %hu\n",
offsetof(struct NtLdrDataTableEntry, Load_Count), "Load_Count",
dll->Load_Count);
printf("0x%04x: %-40s = %hu\n",
offsetof(struct NtLdrDataTableEntry, TlsIndex), "TlsIndex",
dll->TlsIndex);
/* /\* union { *\/ */
/* /\* struct NtLinkedList HashLinks; *\/ */
/* /\* struct { *\/ */
/* /\* void *SectionPointer; *\/ */
/* /\* uint32_t CheckSum; *\/ */
/* /\* }; *\/ */
/* /\* }; *\/ */
/* /\* union { *\/ */
/* /\* void *LoadedImports; *\/ */
/* /\* uint32_t TimeDateStamp; *\/ */
/* /\* }; *\/ */
/* printf("0x%04x: %-40s = 0x%lx\n", */
/* offsetof(struct NtLdrDataTableEntry,
* EntryPointActivationContext), */
/* "EntryPointActivationContext",
* dll->EntryPointActivationContext); */
/* printf("0x%04x: %-40s = 0x%lx\n", */
/* offsetof(struct NtLdrDataTableEntry, PatchInformation), */
/* "PatchInformation", dll->PatchInformation); */
/* /\* struct NtLinkedList ForwarderLinks; *\/ */
/* /\* struct NtLinkedList ServiceTagLinks; *\/ */
/* /\* struct NtLinkedList StaticLinks; *\/ */
/* printf("0x%04x: %-40s = 0x%lx\n", */
/* offsetof(struct NtLdrDataTableEntry, ContextInformation), */
/* "ContextInformation", dll->ContextInformation); */
/* printf("0x%04x: %-40s = 0x%lx\n", */
/* offsetof(struct NtLdrDataTableEntry, OriginalBase),
* "OriginalBase", */
/* dll->OriginalBase); */
/* printf("0x%04x: %-40s = %ld\n", */
/* offsetof(struct NtLdrDataTableEntry, LoadTime), "LoadTime", */
/* dll->LoadTime); */
printf("\n");
} while ((ldr = ldr->Next) && ldr != head);
}
}
int main(int argc, char *argv[]) {
showcrashreports();
if (IsLinux()) {
return NextBestThing();
}
if (!IsWindows()) {
fprintf(stderr, "error: this tool is intended for windows\n");
return 1;
}
PrintStartupInfo();
PrintSystemInfo();
PrintStdioInfo();
PrintTeb();
PrintPeb();
PrintPebLdr();
PrintModulesLoadOrder();
PrintModulesMemoryOrder();
return 0;
}

1666
tool/viz/printvideo.c Normal file

File diff suppressed because it is too large Load diff

163
tool/viz/resize.c Normal file
View file

@ -0,0 +1,163 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/calls/ioctl.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/termios.h"
#include "libc/fmt/fmt.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "libc/runtime/gc.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "third_party/avir/resize.h"
#include "third_party/zlib/zlib.h"
void ProcessFile(const char *path) {
/* int fd; */
/* void *map; */
/* z_stream zs; */
/* uint8_t *rgb; */
/* struct stat st; */
/* const char *ext; */
/* int width, height; */
/* size_t pathlen, rgbbytes; */
/* CHECK_NOTNULL((ext = memrchr(path, '-', (pathlen = strlen(path))))); */
/* CHECK_EQ(2, sscanf(ext, "-%dx%d.rgb.gz", &width, &height)); */
/* CHECK_NE(-1, (fd = open(path, O_RDONLY))); */
/* CHECK_NE(-1, fstat(fd, &st)); */
/* CHECK_NOTNULL((rgb = malloc((rgbbytes = width * height * 3)))); */
/* CHECK_NE(MAP_FAILED, */
/* (map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0))); */
/* zs.next_in = map; */
/* zs.zalloc = Z_NULL; */
/* zs.zfree = Z_NULL; */
/* zs.avail_in = st.st_size; */
/* zs.total_in = st.st_size; */
/* zs.next_out = rgb; */
/* zs.avail_out = rgbbytes; */
/* zs.total_out = rgbbytes; */
/* CHECK_EQ(Z_OK, inflateInit2(&zs, 16 + MAX_WBITS)); */
/* CHECK_NE(Z_BUF_ERROR, inflate(&zs, Z_NO_FLUSH)); */
/* CHECK_EQ(Z_OK, inflateEnd(&zs)); */
/* struct winsize ws; */
/* struct Resizer *rz; */
/* ws.ws_row = 25; */
/* ws.ws_col = 80; */
/* LOGIFNEG1(ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws)); */
/* ws.ws_row *= 2; */
/* ws.ws_col /= 2; */
/* ws.ws_row /= 2; */
/* int y, x, i; */
/* uint8_t *rgb2, *u8p; */
/* float *frgba, *frgba2, *f32p; */
/* CHECK_NOTNULL((rz = NewResizer())); */
/* CHECK_NOTNULL((frgba = malloc(width * height * 4 * sizeof(float)))); */
/* CHECK_NOTNULL((frgba2 = malloc(ws.ws_row * ws.ws_col * 4 *
* sizeof(float)))); */
/* CHECK_NOTNULL((rgb2 = (uint8_t *)malloc(ws.ws_row * ws.ws_col * 3))); */
/* for (u8p = rgb, f32p = frgba, y = 0; y < height; ++y) { */
/* for (x = 0; x < width; ++x, u8p += 3, f32p += 4) { */
/* f32p[0] = (int)u8p[0], f32p[1] = (int)u8p[1]; */
/* f32p[2] = (int)u8p[2], f32p[3] = 1; */
/* for (i = 0; i < 4; ++i) f32p[i] /= 256; */
/* } */
/* } */
/* ResizeImage(rz, frgba, ws.ws_row, ws.ws_col, frgba, height, width); */
/* for (u8p = rgb2, f32p = frgba2, y = 0; y < ws.ws_row; ++y) { */
/* for (x = 0; x < ws.ws_col; ++x, u8p += 3, f32p += 4) { */
/* for (i = 0; i < 4; ++i) f32p[i] *= 256; */
/* u8p[0] = (int)f32p[0]; */
/* u8p[1] = (int)f32p[1]; */
/* u8p[2] = (int)f32p[2]; */
/* } */
/* } */
/* free(frgba2); */
/* free(frgba); */
/* int y, x; */
/* uint8_t *rgb2; */
/* CHECK_NOTNULL((rz = NewResizer())); */
/* CHECK_NOTNULL((rgb2 = (uint8_t *)malloc(ws.ws_row * ws.ws_col * 3))); */
/* printf("%d %d %d %d %d %d\n", rgb2, ws.ws_row, ws.ws_col, rgb, height,
* width); */
/* ResizeImage8(rz, rgb2, ws.ws_row, ws.ws_col, rgb, height, width); */
/* uint8_t *p; */
/* /\* printf("\e[H"); *\/ */
/* for (p = rgb2, y = 0; y < ws.ws_row / 2; ++y) { */
/* for (x = 0; x < ws.ws_col; ++x, p += 3) { */
/* printf("\e[48;2;%hhu;%hhu;%hhu;38;2;%hhu;%hhu;%hhum▄", p[0], p[1],
* p[2], */
/* p[ws.ws_col * 3 + 0], p[ws.ws_col * 3 + 1], p[ws.ws_col * 3 +
* 2]); */
/* } */
/* for (x = 0; x < ws.ws_col; ++x, p += 3) { */
/* } */
/* printf("\n"); */
/* } */
/* printf("\e[0m"); */
/* uint8_t *rgb2; */
/* struct winsize ws; */
/* struct Resizer *rz; */
/* ws.ws_row = 25; */
/* ws.ws_col = 80; */
/* LOGIFNEG1(ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws)); */
/* CHECK_NOTNULL((rz = NewResizer())); */
/* CHECK_NOTNULL((rgb2 = malloc(ws.ws_row * ws.ws_col * 3))); */
/* printf("%d %d %d %d %d %d\n", rgb2, ws.ws_row, ws.ws_col, rgb, height,
* width); */
/* ResizeImage8(rz, rgb2, ws.ws_row, ws.ws_col, rgb, height, width); */
/* int y, x; */
/* uint8_t *p; */
/* printf("\e[H"); */
/* for (p = rgb2, y = 0; y < ws.ws_row; ++y) { */
/* for (x = 0; x < ws.ws_col; ++x, p += 3) { */
/* if (p[0] || p[1] || p[2]) { */
/* printf("\e[48;2;%hhu;%hhu;%hhum ", p[0], p[1], p[2]); */
/* } */
/* } */
/* printf("\n"); */
/* } */
/* printf("\e[0m"); */
/* CHECK_NE(-1, munmap(map, st.st_size)); */
/* CHECK_NE(-1, close(fd)); */
/* FreeResizer(rz); */
/* free(rgb2); */
/* free(rgb); */
}
int main(int argc, char *argv[]) {
int i;
for (i = 1; i < argc; ++i) {
ProcessFile(argv[i]);
}
return 0;
}

133
tool/viz/rgbtoxterm.c Normal file
View file

@ -0,0 +1,133 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "dsp/tty/quant.h"
#include "libc/calls/calls.h"
#include "libc/log/check.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "libc/sysv/consts/fileno.h"
#include "third_party/getopt/getopt.h"
#define kUsage \
"Usage:\n\
\n\
%s [-cber] [-o FILE] [ARGS...]\n\
\n\
Flags:\n\
\n\
-e enable emphasis\n\
-b emit as background color\n\
-r print raw codes\n\
-c emit cleanup (reset) codes when done\n\
-o FILE redirects output [default: /dev/stdout]\n\
\n\
Arguments:\n\
\n\
- may be passed via ARGS or STDIN (one per line)\n\
- may be #RRGGBB or RRGGBB\n\
- may be #RGB or RGB (#123 #112233)\n\
- anything else is printed verbatim\n\
\n"
static FILE *fout_;
static size_t linecap_;
static char *outpath_, *line_;
static bool rawmode_, background_, emphasis_, cleanup_;
noreturn void usage(int rc, FILE *f) {
fprintf(f, kUsage, program_invocation_name);
exit(rc);
}
void getopts(int *argc, char *argv[]) {
int opt;
outpath_ = "-";
while ((opt = getopt(*argc, argv, "?hrecbo:")) != -1) {
switch (opt) {
case 'r':
rawmode_ = true;
break;
case 'b':
background_ = true;
break;
case 'c':
cleanup_ = true;
break;
case 'e':
emphasis_ = true;
break;
case 'o':
outpath_ = optarg;
break;
case '?':
case 'h':
usage(EXIT_SUCCESS, stdout);
default:
usage(EX_USAGE, stderr);
}
}
}
void processarg(const char *arg) {
const char *p;
size_t r, g, b;
if (*(p = arg) == '#') p++;
if (strlen(p) == 3 && (isxdigit(p[0]) && isxdigit(p[1]) && isxdigit(p[2]))) {
r = hextoint(p[0]) << 4 | hextoint(p[0]);
g = hextoint(p[1]) << 4 | hextoint(p[1]);
b = hextoint(p[2]) << 4 | hextoint(p[2]);
} else if (strlen(p) == 6 &&
(isxdigit(p[0]) && isxdigit(p[1]) && isxdigit(p[2]) &&
isxdigit(p[3]) && isxdigit(p[4]) && isxdigit(p[5]))) {
r = hextoint(p[0]) << 4 | hextoint(p[1]);
g = hextoint(p[2]) << 4 | hextoint(p[3]);
b = hextoint(p[4]) << 4 | hextoint(p[5]);
} else {
fputs(arg, fout_);
return;
}
fprintf(fout_, "%s[%s%d;5;%hhum%s", rawmode_ ? "\e" : "\\e",
emphasis_ ? "1;" : "", background_ ? 48 : 38, rgb2tty(r, g, b),
&"\n"[rawmode_]);
}
int main(int argc, char *argv[]) {
size_t i;
getopts(&argc, argv);
CHECK_NOTNULL((fout_ = fopen(outpath_, "w")));
if (optind < argc) {
for (i = optind; i < argc; ++i) {
processarg(argv[i]);
}
} else {
while ((getline(&line_, &linecap_, stdin)) != -1) {
processarg(chomp(line_));
}
free_s(&line_);
}
if (cleanup_) {
fprintf(fout_, "%s[0m\n", rawmode_ ? "\e" : "\\e");
}
CHECK_NE(-1, fclose_s(&fout_));
return 0;
}

175
tool/viz/tabalign.c Normal file
View file

@ -0,0 +1,175 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/arraylist.h"
#include "libc/bits/safemacros.h"
#include "libc/conv/conv.h"
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "libc/unicode/unicode.h"
#include "third_party/getopt/getopt.h"
#define kOneTrueTabWidth 8
struct Pool {
size_t i, n;
char *p;
};
struct Lines {
size_t i, n;
struct Line {
uint16_t off;
uint16_t col;
int32_t line;
} * p;
};
static bool chunk_;
static FILE *fi_, *fo_;
static struct Pool pool_;
static struct Lines lines_;
static size_t mincol_, col_, maxcol_, linecap_;
static char *inpath_, *outpath_, *delim_, *line_;
noreturn void usage(int rc, FILE *f) {
fprintf(f, "%s%s%s\n", "Usage: ", program_invocation_name,
" [-c] [-m MINCOL] [-M MAXCOL] [-F DELIM] [-o FILE] [FILE...]\n"
"\n"
" This program aligns monospace text. It's aware of tabs,\n"
" color codes, wide characters, combining characters etc.\n");
exit(rc);
}
void getopts(int *argc, char *argv[]) {
int opt;
delim_ = "#";
outpath_ = "-";
while ((opt = getopt(*argc, argv, "?hco:m:M:F:")) != -1) {
switch (opt) {
case 'm':
mincol_ = strtol(optarg, NULL, 0);
break;
case 'M':
maxcol_ = strtol(optarg, NULL, 0);
break;
case 'c':
chunk_ = true;
break;
case 'o':
outpath_ = optarg;
break;
case 'F':
delim_ = optarg;
break;
case '?':
case 'h':
usage(EXIT_SUCCESS, stdout);
default:
usage(EX_USAGE, stderr);
}
}
if (optind == *argc) {
argv[(*argc)++] = "-";
}
}
void flush(void) {
size_t i, j;
const char *s;
struct Line l;
col_ = roundup(col_ + 1, kOneTrueTabWidth);
if (maxcol_) col_ = min(col_, maxcol_);
for (i = 0; i < lines_.i; ++i) {
l = lines_.p[i];
s = &pool_.p[l.line];
if (l.off < USHRT_MAX) {
fwrite(s, l.off, 1, fo_);
for (j = l.col; j < col_;) {
fputc('\t', fo_);
if (j % kOneTrueTabWidth == 0) {
j += 8;
} else {
j += kOneTrueTabWidth - (j & (kOneTrueTabWidth - 1));
}
}
fwrite(s + l.off, strlen(s) - l.off, 1, fo_);
} else {
fwrite(s, strlen(s), 1, fo_);
}
fputc('\n', fo_);
}
col_ = mincol_;
pool_.i = 0;
lines_.i = 0;
}
void processfile(void) {
char *p;
int col, s;
size_t off, len;
while ((getline(&line_, &linecap_, fi_)) != -1) {
chomp(line_);
len = strlen(line_);
s = concat(&pool_, line_, len + 1);
if (len < USHRT_MAX) {
if ((p = strstr(line_, delim_))) {
off = p - line_;
col = strnwidth(line_, off);
if (col < USHRT_MAX) {
col_ = max(col_, col);
append(&lines_, &((struct Line){.line = s, .off = off, .col = col}));
continue;
}
} else {
if (chunk_) {
flush();
fputs(line_, fo_);
fputc('\n', fo_);
continue;
}
}
}
append(&lines_, &((struct Line){.line = s, .off = 0xffff, .col = 0xffff}));
}
}
int main(int argc, char *argv[]) {
size_t i;
getopts(&argc, argv);
CHECK_NOTNULL((fo_ = fopen(outpath_, "w")));
for (i = optind; i < argc; ++i) {
CHECK_NOTNULL((fi_ = fopen((inpath_ = argv[i]), "r")));
processfile();
CHECK_NE(-1, fclose_s(&fi_));
}
flush();
CHECK_NE(-1, fclose_s(&fo_));
free(lines_.p);
free(pool_.p);
free(line_);
return 0;
}

56
tool/viz/unbing.c Normal file
View file

@ -0,0 +1,56 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
/**
* @fileoverview UnBing: Glyphs Binary.
*
* Intended for reassembling modified binaries. Characters that aren't
* IBM CodePage 437 glyphs are ignored. That includes line feeds, so
* it's safe to use the fold command on the bing program output, to have
* something almost representing a source code file. A hack also exists
* for comments in such files: 𝘶𝘴𝘦 𝑛𝑜𝑛-𝑎𝑠𝑐𝑖𝑖 𝗹𝗲𝘁𝘁𝗲𝗿𝗶𝗻𝗴 𝔞𝔩𝔱𝔢𝔯𝔫𝔞𝔱𝔦𝔳𝔢𝔰.
*
* bash$ o/tool/viz/bing.com </bin/sh | o/tool/viz/fold.com >sh.txt
* bash$ emacs sh.txt
* bash$ o/tool/viz/unbing.com <sh.txt >sh
* bash$ chmod +x sh
* bash$ ./sh
*
* That's how it works.
*/
uint16_t g_map[0x10000];
int main(int argc, char *argv[argc]) {
size_t i;
wint_t c;
for (i = 0; i < 256; ++i) {
g_map[kCp437[i]] = i + 1;
}
while ((c = fgetwc(stdin)) != WEOF) {
if (c == (c & 0xffff) && g_map[c]) {
fputc(g_map[c] - 1, stdout);
}
}
return 0;
}

212
tool/viz/upscalefloat.c Normal file
View file

@ -0,0 +1,212 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/macros.h"
#include "libc/math.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "libc/x/x.h"
#include "third_party/stb/stb_image.h"
#define C13(A, B) (((A) + 3 * (B)) / 4)
#define S3T(A, B, C) MAX(0, ((24 * (B)) - (4 * ((A) + (C)))) / 16)
#define LERP(A, B, P) ((A) * (1 - (P)) + (B) * (P))
float ByteToFloat(int b) {
return 1 / 255.f * b;
}
int FloatToByte(float f) {
return MAX(0, MIN(255, roundf(255 * f)));
}
float ChessBoard(unsigned y, unsigned x, float a, float b) {
return !((y ^ x) & (1u << 2)) ? a : b;
}
float AlphaBackground(unsigned y, unsigned x) {
return ChessBoard(y, x, 1.f, .7f);
}
float OutOfBoundsBackground(unsigned y, unsigned x) {
return ChessBoard(y, x, .01f, .02f);
}
float Opacify(size_t yn, size_t xn, const float P[yn][xn],
const float A[yn][xn], long y, long x) {
if ((0 <= y && y < yn) && (0 <= x && x < xn)) {
return LERP(AlphaBackground(y, x), P[y][x], A[y][x]);
} else {
return OutOfBoundsBackground(y, x);
}
}
void PrintImage(size_t yn, size_t xn, float R[yn][xn], float G[yn][xn],
float B[yn][xn], float A[yn][xn]) {
unsigned y, x;
for (y = 0; y < yn; y += 2) {
if (y) printf("\e[0m\n");
for (x = 0; x < xn; ++x) {
printf("\e[48;2;%d;%d;%d;38;2;%d;%d;%dm▄",
FloatToByte(Opacify(yn, xn, R, A, y + 0, x)),
FloatToByte(Opacify(yn, xn, G, A, y + 0, x)),
FloatToByte(Opacify(yn, xn, B, A, y + 0, x)),
FloatToByte(Opacify(yn, xn, R, A, y + 1, x)),
FloatToByte(Opacify(yn, xn, G, A, y + 1, x)),
FloatToByte(Opacify(yn, xn, B, A, y + 1, x)));
}
}
printf("\e[0m\n");
}
void DeblinterlaceRgba(size_t dyn, size_t dxn, float R[dyn][dxn],
float G[dyn][dxn], float B[dyn][dxn], float A[dyn][dxn],
size_t syn, size_t sxn,
const unsigned char src[syn][sxn][4]) {
unsigned y, x;
for (y = 0; y < syn; ++y) {
for (x = 0; x < sxn; ++x) {
R[y][x] = ByteToFloat(src[y][x][0]);
G[y][x] = ByteToFloat(src[y][x][1]);
B[y][x] = ByteToFloat(src[y][x][2]);
A[y][x] = ByteToFloat(src[y][x][3]);
}
}
}
void SharpenX(size_t yw, size_t xw, float dst[yw][xw], const float src[yw][xw],
size_t yn, size_t xn) {
int y, x;
for (y = 0; y < yn; ++y) {
for (x = 0; x < xn; ++x) {
dst[y][x] =
S3T(src[y][MAX(0, x - 1)], src[y][x], src[y][MIN(xn - 1, x + 1)]);
}
}
}
void SharpenY(size_t yw, size_t xw, float dst[yw][xw], const float src[yw][xw],
size_t yn, size_t xn) {
int y, x;
for (y = 0; y < yn; ++y) {
for (x = 0; x < xn; ++x) {
dst[y][x] =
S3T(src[MAX(0, y - 1)][x], src[y][x], src[MIN(yn - 1, y + 1)][x]);
}
}
}
void UpscaleX(size_t yw, size_t xw, float img[yw][xw], size_t yn, size_t xn) {
unsigned y, x;
for (y = yn; y--;) {
for (x = xn; --x;) {
img[y][x] =
C13(img[y][MIN(xn / 2 - 1, x / 2 - 1 + x % 2 * 2)], img[y][x / 2]);
}
}
}
void UpscaleY(size_t yw, size_t xw, float img[yw][xw], size_t yn, size_t xn) {
unsigned y, x;
for (y = yn; --y;) {
for (x = xn; x--;) {
img[y][x] =
C13(img[MIN(yn / 2 - 1, y / 2 - 1 + y % 2 * 2)][x], img[y / 2][x]);
}
}
}
void Upscale(size_t yw, size_t xw, float img[yw][xw], float tmp[yw][xw],
size_t yn, size_t xn) {
UpscaleY(yw, xw, img, yn, xn / 2);
SharpenY(yw, xw, tmp, img, yn, xn / 2);
UpscaleX(yw, xw, tmp, yn, xn);
SharpenX(yw, xw, img, tmp, yn, xn);
}
void ProcessImageDouble(size_t yn, size_t xn, unsigned char img[yn][xn][4]) {
void *t = xmemalign(32, sizeof(float) * yn * 2 * xn * 2);
void *R = xmemalign(32, sizeof(float) * yn * 2 * xn * 2);
void *G = xmemalign(32, sizeof(float) * yn * 2 * xn * 2);
void *B = xmemalign(32, sizeof(float) * yn * 2 * xn * 2);
void *A = xmemalign(32, sizeof(float) * yn * 2 * xn * 2);
DeblinterlaceRgba(yn * 2, xn * 2, R, G, B, A, yn, xn, img);
Upscale(yn * 2, xn * 2, R, t, yn * 2, xn * 2);
Upscale(yn * 2, xn * 2, G, t, yn * 2, xn * 2);
Upscale(yn * 2, xn * 2, B, t, yn * 2, xn * 2);
Upscale(yn * 2, xn * 2, A, t, yn * 2, xn * 2);
free(t);
PrintImage(yn * 2, xn * 2, R, G, B, A);
free(R);
free(G);
free(B);
free(A);
}
void ProcessImage(size_t yn, size_t xn, unsigned char img[yn][xn][4]) {
void *R = xmemalign(32, sizeof(float) * yn * xn);
void *G = xmemalign(32, sizeof(float) * yn * xn);
void *B = xmemalign(32, sizeof(float) * yn * xn);
void *A = xmemalign(32, sizeof(float) * yn * xn);
DeblinterlaceRgba(yn, xn, R, G, B, A, yn, xn, img);
PrintImage(yn, xn, R, G, B, A);
free(R);
free(G);
free(B);
free(A);
}
void WithImageFile(const char *path, void fn(size_t yn, size_t xn,
unsigned char img[yn][xn][4])) {
struct stat st;
int fd, yn, xn;
void *map, *data;
CHECK_NE(-1, (fd = open(path, O_RDONLY)), "%s", path);
CHECK_NE(-1, fstat(fd, &st));
CHECK_GT(st.st_size, 0);
CHECK_LE(st.st_size, INT_MAX);
fadvise(fd, 0, 0, MADV_WILLNEED | MADV_SEQUENTIAL);
CHECK_NE(MAP_FAILED,
(map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)));
CHECK_NOTNULL(
(data = stbi_load_from_memory(map, st.st_size, &xn, &yn, NULL, 4)), "%s",
path);
CHECK_NE(-1, munmap(map, st.st_size));
CHECK_NE(-1, close(fd));
fn(yn, xn, data);
free(data);
}
int main(int argc, char *argv[]) {
int i;
for (i = 1; i < argc; ++i) {
WithImageFile(argv[i], ProcessImageDouble);
}
return 0;
}

209
tool/viz/upscaleint.c Normal file
View file

@ -0,0 +1,209 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/macros.h"
#include "libc/math.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "libc/x/x.h"
#include "third_party/stb/stb_image.h"
#define CLAMP(X) MAX(0, MIN(255, X))
#define C13(A, B) (((A) + 3 * (B) + 2) >> 2)
#define S3T(A, B, C) CLAMP(-((A) >> 2) + ((B) + ((B) >> 1)) + -((C) >> 2))
#define LERP(X, Y, P) ((X) + (((P) * ((Y) - (X))) >> 8))
static unsigned char ChessBoard(unsigned y, unsigned x, unsigned char a,
unsigned char b) {
return !((y ^ x) & (1u << 2)) ? a : b;
}
static unsigned char AlphaBackground(unsigned y, unsigned x) {
return ChessBoard(y, x, 255, 200);
}
static unsigned char OutOfBoundsBackground(unsigned y, unsigned x) {
return ChessBoard(y, x, 40, 80);
}
static unsigned char Opacify(size_t yn, size_t xn,
const unsigned char P[yn][xn],
const unsigned char A[yn][xn], long y, long x) {
if ((0 <= y && y < yn) && (0 <= x && x < xn)) {
return LERP(AlphaBackground(y, x), P[y][x], A[y][x]);
} else {
return OutOfBoundsBackground(y, x);
}
}
static void PrintImage(size_t yn, size_t xn, unsigned char R[yn][xn],
unsigned char G[yn][xn], unsigned char B[yn][xn],
unsigned char A[yn][xn]) {
unsigned y, x;
for (y = 0; y < yn; y += 2) {
if (y) printf("\e[0m\n");
for (x = 0; x < xn; ++x) {
printf("\e[48;2;%d;%d;%d;38;2;%d;%d;%dm▄",
Opacify(yn, xn, R, A, y + 0, x), Opacify(yn, xn, G, A, y + 0, x),
Opacify(yn, xn, B, A, y + 0, x), Opacify(yn, xn, R, A, y + 1, x),
Opacify(yn, xn, G, A, y + 1, x), Opacify(yn, xn, B, A, y + 1, x));
}
}
printf("\e[0m\n");
}
static void DeblinterlaceRgba(size_t dyn, size_t dxn, unsigned char R[dyn][dxn],
unsigned char G[dyn][dxn],
unsigned char B[dyn][dxn],
unsigned char A[dyn][dxn], size_t syn, size_t sxn,
const unsigned char src[syn][sxn][4]) {
unsigned y, x;
for (y = 0; y < syn; ++y) {
for (x = 0; x < sxn; ++x) {
R[y][x] = src[y][x][0];
G[y][x] = src[y][x][1];
B[y][x] = src[y][x][2];
A[y][x] = src[y][x][3];
}
}
}
static void SharpenX(size_t yw, size_t xw, unsigned char dst[yw][xw],
const unsigned char src[yw][xw], size_t yn, size_t xn) {
int y, x;
for (y = 0; y < yn; ++y) {
for (x = 0; x < xn; ++x) {
dst[y][x] =
S3T(src[y][MAX(0, x - 1)], src[y][x], src[y][MIN(xn - 1, x + 1)]);
}
}
}
static void SharpenY(size_t yw, size_t xw, unsigned char dst[yw][xw],
const unsigned char src[yw][xw], size_t yn, size_t xn) {
int y, x;
for (y = 0; y < yn; ++y) {
for (x = 0; x < xn; ++x) {
dst[y][x] =
S3T(src[MAX(0, y - 1)][x], src[y][x], src[MIN(yn - 1, y + 1)][x]);
}
}
}
static void UpscaleX(size_t yw, size_t xw, unsigned char img[yw][xw], size_t yn,
size_t xn) {
unsigned y, x;
for (y = yn; y--;) {
for (x = xn; --x;) {
img[y][x] =
C13(img[y][MIN(xn / 2 - 1, x / 2 - 1 + x % 2 * 2)], img[y][x / 2]);
}
}
}
static void UpscaleY(size_t yw, size_t xw, unsigned char img[yw][xw], size_t yn,
size_t xn) {
unsigned y, x;
for (y = yn; --y;) {
for (x = xn; x--;) {
img[y][x] =
C13(img[MIN(yn / 2 - 1, y / 2 - 1 + y % 2 * 2)][x], img[y / 2][x]);
}
}
}
static void Upscale(size_t yw, size_t xw, unsigned char img[yw][xw],
unsigned char tmp[yw][xw], size_t yn, size_t xn) {
UpscaleY(yw, xw, img, yn, xn / 2);
SharpenY(yw, xw, tmp, img, yn, xn / 2);
UpscaleX(yw, xw, tmp, yn, xn);
SharpenX(yw, xw, img, tmp, yn, xn);
}
static void ProcessImageDouble(size_t yn, size_t xn,
unsigned char img[yn][xn][4]) {
void *t = xmemalign(32, sizeof(unsigned char) * yn * 2 * xn * 2);
void *R = xmemalign(32, sizeof(unsigned char) * yn * 2 * xn * 2);
void *G = xmemalign(32, sizeof(unsigned char) * yn * 2 * xn * 2);
void *B = xmemalign(32, sizeof(unsigned char) * yn * 2 * xn * 2);
void *A = xmemalign(32, sizeof(unsigned char) * yn * 2 * xn * 2);
DeblinterlaceRgba(yn * 2, xn * 2, R, G, B, A, yn, xn, img);
Upscale(yn * 2, xn * 2, R, t, yn * 2, xn * 2);
Upscale(yn * 2, xn * 2, G, t, yn * 2, xn * 2);
Upscale(yn * 2, xn * 2, B, t, yn * 2, xn * 2);
Upscale(yn * 2, xn * 2, A, t, yn * 2, xn * 2);
free(t);
PrintImage(yn * 2, xn * 2, R, G, B, A);
free(R);
free(G);
free(B);
free(A);
}
static void ProcessImage(size_t yn, size_t xn, unsigned char img[yn][xn][4]) {
void *R = xmemalign(32, sizeof(unsigned char) * yn * xn);
void *G = xmemalign(32, sizeof(unsigned char) * yn * xn);
void *B = xmemalign(32, sizeof(unsigned char) * yn * xn);
void *A = xmemalign(32, sizeof(unsigned char) * yn * xn);
DeblinterlaceRgba(yn, xn, R, G, B, A, yn, xn, img);
PrintImage(yn, xn, R, G, B, A);
free(R);
free(G);
free(B);
free(A);
}
void WithImageFile(const char *path, void fn(size_t yn, size_t xn,
unsigned char img[yn][xn][4])) {
struct stat st;
int fd, yn, xn;
void *map, *data;
CHECK_NE(-1, (fd = open(path, O_RDONLY)), "%s", path);
CHECK_NE(-1, fstat(fd, &st));
CHECK_GT(st.st_size, 0);
CHECK_LE(st.st_size, INT_MAX);
fadvise(fd, 0, 0, MADV_WILLNEED | MADV_SEQUENTIAL);
CHECK_NE(MAP_FAILED,
(map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)));
CHECK_NOTNULL(
(data = stbi_load_from_memory(map, st.st_size, &xn, &yn, NULL, 4)), "%s",
path);
CHECK_NE(-1, munmap(map, st.st_size));
CHECK_NE(-1, close(fd));
fn(yn, xn, data);
free(data);
}
int main(int argc, char *argv[]) {
int i;
for (i = 1; i < argc; ++i) {
WithImageFile(argv[i], ProcessImageDouble);
}
return 0;
}

89
tool/viz/viz.mk Normal file
View file

@ -0,0 +1,89 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += TOOL_VIZ
TOOL_VIZ_SRCS := $(wildcard tool/viz/*.c)
TOOL_VIZ_COMS = $(TOOL_VIZ_OBJS:%.o=%.com)
TOOL_VIZ_OBJS = \
$(TOOL_VIZ_SRCS:%=o/$(MODE)/%.zip.o) \
$(TOOL_VIZ_SRCS:%.c=o/$(MODE)/%.o)
TOOL_VIZ_BINS = \
$(TOOL_VIZ_COMS) \
$(TOOL_VIZ_COMS:%=%.dbg)
TOOL_VIZ_DIRECTDEPS = \
DSP_CORE \
DSP_MPEG \
DSP_TTY \
DSP_SCALE \
LIBC_BITS \
LIBC_CALLS \
LIBC_CALLS_HEFTY \
LIBC_CONV \
LIBC_DNS \
LIBC_FMT \
LIBC_LOG \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_NT_KERNEL32 \
LIBC_NT_KERNELBASE \
LIBC_RUNTIME \
LIBC_TESTLIB \
LIBC_STDIO \
LIBC_STR \
LIBC_STUBS \
LIBC_SOCK \
LIBC_SYSV \
LIBC_TIME \
LIBC_TINYMATH \
LIBC_UNICODE \
LIBC_RAND \
LIBC_X \
LIBC_SYSV_CALLS \
NET_HTTP \
TOOL_DECODE_LIB \
TOOL_VIZ_LIB \
THIRD_PARTY_GETOPT \
THIRD_PARTY_AVIR \
THIRD_PARTY_DLMALLOC \
THIRD_PARTY_DTOA \
THIRD_PARTY_STB \
THIRD_PARTY_XED \
THIRD_PARTY_ZLIB
TOOL_VIZ_DEPS := \
$(call uniq,$(foreach x,$(TOOL_VIZ_DIRECTDEPS),$($(x))))
o/$(MODE)/tool/viz/viz.pkg: \
$(TOOL_VIZ_OBJS) \
$(foreach x,$(TOOL_VIZ_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/tool/viz/%.com.dbg: \
$(TOOL_VIZ_DEPS) \
o/$(MODE)/tool/viz/%.o \
o/$(MODE)/tool/viz/viz.pkg \
$(CRT) \
$(APE)
@$(APELINK)
o/$(MODE)/tool/viz/derasterize.o: \
OVERRIDE_CFLAGS += \
-DSTACK_FRAME_UNLIMITED \
$(MATHEMATICAL)
o/$(MODE)/tool/viz/magikarp.o: \
OVERRIDE_CFLAGS += \
$(MATHEMATICAL)
$(TOOL_VIZ_OBJS): \
$(BUILD_FILES) \
tool/viz/viz.mk
.PHONY: o/$(MODE)/tool/viz
o/$(MODE)/tool/viz: \
o/$(MODE)/tool/viz/lib \
$(TOOL_VIZ_BINS) \
$(TOOL_VIZ_CHECKS)

186
tool/viz/xterm256cubes.c Normal file
View file

@ -0,0 +1,186 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/stdio/stdio.h"
#define DueToGnomeTerminal 1
#define DueToLiteralXterm 1
#define DueToKittyWithPragmataPro 1
#if 0
static void rgb2hsv(T r, T g, T b, T *out_h, T *out_s, T *out_v) {
T c, h, s, v, min, max;
h = NAN;
s = 0;
v = 0;
min = MIN(MIN(r, g), b);
max = MAX(MAX(r, g), b);
if (max > C(0.0)) {
v = max;
c = max - min;
s = c / v;
if (c > C(0.00001)) {
if (r >= max) {
h = (g - b) / c;
} else if (g >= max) {
h = C(2.0) + (b - r) / c;
} else {
h = C(4.0) + (r - g) / c;
}
h *= C(60.0);
if (h < C(0.0)) {
h += C(360.0);
}
}
}
*out_h = h;
*out_s = s;
*out_v = v;
}
static void hsv2rgb(T h, T s, T v, T *out_r, T *out_g, T *out_b) {
long i;
T r, g, b, hh, p, q, t, ff;
if (s <= C(0.0)) {
r = v;
g = v;
b = v;
} else {
hh = h;
if (h >= C(360.0)) hh = 0;
hh /= C(60.0);
i = (long)hh;
ff = hh - i;
p = v * (C(1.0) - s);
q = v * (C(1.0) - (s * ff));
t = v * (C(1.0) - (s * (C(1.0) - ff)));
switch (i) {
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
case 5:
default:
r = v;
g = p;
b = q;
break;
}
}
*out_r = r;
*out_g = g;
*out_b = b;
}
#endif
#define DIST(X, Y) ((X) - (Y))
#define SQR(X) ((X) * (X))
#define SUM(X, Y, Z) ((X) + (Y) + (Z))
static const uint8_t kXtermCube[] = {0, 0137, 0207, 0257, 0327, 0377};
static int uncube(int x) {
return x < 48 ? 0 : x < 115 ? 1 : (x - 35) / 40;
}
static int rgb2xterm256(int r, int g, int b) {
unsigned av, ir, ig, ib, il, qr, qg, qb, ql;
av = (r + g + b) / 3;
ql = (il = av > 238 ? 23 : (av - 3) / 10) * 10 + 8;
qr = kXtermCube[(ir = uncube(r))];
qg = kXtermCube[(ig = uncube(g))];
qb = kXtermCube[(ib = uncube(b))];
if (SUM(SQR(DIST(qr, r)), SQR(DIST(qg, g)), SQR(DIST(qb, b))) <=
SUM(SQR(DIST(ql, r)), SQR(DIST(ql, g)), SQR(DIST(ql, b)))) {
return ir * 36 + ig * 6 + ib + 020;
} else {
return il + 0350;
}
}
bool IsUglyColorMixture(int rune, int y, int tone, bool toneisfg) {
assert(tone == 16 || (231 <= tone && tone <= 255));
return false;
}
int main(int argc, char *argv[]) {
unsigned y, z, x, k, w;
static const char16_t s[2][3] = {{u'', u'', u''}, {u'', u'', u''}};
printf("\npure\n");
for (y = 0; y < 6; ++y) {
for (z = 0; z < 6; ++z) {
for (x = 0; x < 6; ++x) {
printf("\033[48;5;%hhum ", 16 + x + y * 6 + z * 6 * 6);
}
printf("\033[0m ");
}
printf("\n");
}
#define MIX(NAME, COLOR) \
do { \
printf("\n%s %d ▓░/▒▒/░▓\n", NAME, COLOR); \
for (k = 0; k < 3; ++k) { \
for (y = 0; y < 6; ++y) { \
for (z = 0; z < 6; ++z) { \
for (x = 0; x < 6; ++x) { \
printf("\033[48;5;%hhu;38;5;%hhum%lc", COLOR, \
16 + x + y * 6 + z * 6 * 6, s[0][k]); \
printf("\033[48;5;%hhu;38;5;%hhum%lc", 16 + x + y * 6 + z * 6 * 6, \
COLOR, s[1][k]); \
} \
printf("\033[0m "); \
} \
printf("\n"); \
} \
} \
} while (0)
MIX("tint", 231);
MIX("tint", 255);
MIX("tint", 254);
MIX("tone", 240);
MIX("shade", 232);
for (w = 233; w < 254; ++w) {
MIX("gray", w);
}
return 0;
}

View file

@ -0,0 +1,184 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "dsp/tty/quant.h"
#include "libc/bits/bits.h"
#include "libc/bits/xchg.h"
#include "libc/fmt/fmt.h"
#include "libc/math.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
/* #define ROUND(x) x */
/* #define RT int */
/* #define R1 1 */
/* #define R2 2 */
/* #define R3 3 */
#define RT float
#define MUL(x, y) ((x) * (y))
#define RND(x) roundf(x)
#define R1 0.25f
#define R2 0.50f
#define R3 0.75f
#define rgb_t struct TtyRgb
forceinline RT lerp(RT x, RT y, RT d) {
return x * (1.0 - d) + y * d;
}
forceinline int lerp255(RT x, RT y, RT d) {
return lerp(x / 255.0, y / 255.0, d) * 255.0;
}
forceinline rgb_t rgblerp(rgb_t x, rgb_t y, RT d) {
return (rgb_t){lerp255(x.r, y.r, d), lerp255(x.g, y.g, d),
lerp255(x.b, y.b, d)};
}
forceinline rgb_t getquant(unsigned xt) {
return g_ansi2rgb_[xt];
}
forceinline unsigned dist(int x, int y) {
return x - y;
}
forceinline unsigned sqr(int x) {
return x * x;
}
forceinline unsigned rgbdist(rgb_t x, rgb_t y) {
return sqrt(sqr(dist(x.r, y.r)) + sqr(dist(x.g, y.g)) + sqr(dist(x.b, y.b)));
}
bool b;
rgb_t rgb, cc, c1, c2;
unsigned i, j, k, m, n, x, y;
char buf[128];
/* 0125 025 067-29 # '░' bg=0352 fg=0306 → ░░░ */
/* 0125 025 067-29 # '▓' bg=0306 fg=0352 → ▓▓▓ */
/* 0125 055 067-29 # '░' bg=0352 fg=0314 → ░░░ */
int main(int argc, char *argv[]) {
/* memcpy(g_ansi2rgb_, &kTangoPalette, sizeof(kTangoPalette)); */
/* i = 21; */
/* j = 22; */
/* c1 = getquant(i); */
/* c2 = getquant(j); */
/* cc = rgblerp(c1, c2, R1); */
/* printf("rgblerp((%3d,%3d,%3d), (%3d,%3d,%3d),4) → (%3d,%3d,%3d)\n", c1.r,
*/
/* c1.g, c1.b, c2.r, c2.g, c2.b, cc.r, cc.g, cc.b); */
/* exit(0); */
for (m = 16; m < 256; m += 6) {
for (n = 16; n < 256; n += 6) {
printf("------------------------------------------------------------\n");
i = m;
j = n;
b = false;
while (i < m + 6) {
printf("\n");
cc = getquant(i);
sprintf(buf, "\e[48;5;%dm ", i);
printf("0x%02x%02x%02x, %d,%d,0\t/* 0x%02x%02x%02x "
" + ' ' bg=%3d → %s \e[0m */\n",
cc.b, cc.g, cc.r, i, 0, getquant(i).r, getquant(i).g,
getquant(i).b, i, buf);
#if 0
sprintf(buf, "\e[38;5;%dm███", i);
printf("0x%08x 0x%02x%02x%02x\t"
" '█' fg=%3d → %s\e[0m\n",
cc.b, cc.g, cc.r, strlen(buf), i, buf);
#endif
for (x = i; x < i + 1; ++x) {
for (y = j; y < j + 1; ++y) {
for (k = 0; k < 2; ++k) {
if (x > y /* && */
/* rgbdist(getquant(x), getquant(y)) < 49744125 / 16 */ /* &&
((32
<= x && x <= 232) && (32 <= y && y <= 232))
&& */
/* (cc.r > 0137 && cc.g > 0137 && cc.b > 0137) */) {
sprintf(buf, "\e[48;5;%d;38;5;%dm░░░", x, y);
cc = rgblerp(getquant(x), getquant(y), R1);
printf("0x%02x%02x%02x, %d,%d,1\t/* 0x%02x%02x%02x + "
"0x%02x%02x%02x"
" + '░' bg=%3d fg=%3d → "
"\e[48;5;%dm \e[48;5;%dm "
"%s\e[48;2;%d;%d;%dm \e[0m */\n",
cc.b, cc.g, cc.r, x, y, getquant(x).r, getquant(x).g,
getquant(x).b, getquant(y).r, getquant(y).g,
getquant(y).b, x, y, x, y, buf, cc.r, cc.g, cc.b);
sprintf(buf, "\e[48;5;%d;38;5;%dm▒▒▒", x, y);
cc = rgblerp(getquant(x), getquant(y), R2);
printf("0x%02x%02x%02x, %d,%d,2\t/* 0x%02x%02x%02x + "
"0x%02x%02x%02x"
" + '▒' bg=%3d fg=%3d → "
"\e[48;5;%dm \e[48;5;%dm "
"%s\e[48;2;%d;%d;%dm \e[0m */\n",
cc.b, cc.g, cc.r, x, y, getquant(x).r, getquant(x).g,
getquant(x).b, getquant(y).r, getquant(y).g,
getquant(y).b, x, y, x, y, buf, cc.r, cc.g, cc.b);
sprintf(buf, "\e[48;5;%d;38;5;%dm▓▓▓", x, y);
cc = rgblerp(getquant(x), getquant(y), R3);
printf("0x%02x%02x%02x, %d,%d,3\t/* 0x%02x%02x%02x + "
"0x%02x%02x%02x"
" + '▓' bg=%3d fg=%3d → "
"\e[48;5;%dm \e[48;5;%dm "
"%s\e[48;2;%d;%d;%dm \e[0m */\n",
cc.b, cc.g, cc.r, x, y, getquant(x).r, getquant(x).g,
getquant(x).b, getquant(y).r, getquant(y).g,
getquant(y).b, x, y, x, y, buf, cc.r, cc.g, cc.b);
}
#if 0
sprintf(buf, "\e[48;5;%d;38;5;%dm▓▓▓", x, y);
cc = rgblerp((c1 = getquant(x)), (c2 = getquant(y)), R3);
printf("0%03o%03o%03o\t# '▓' bg=%3d fg=%3d → "
"%s\e[48;2;%d;%d;%dm \e[0m\n",
cc.b, cc.g, cc.r, strlen(buf), x, y, buf,
lerp255(c1.r, c2.r, R3), lerp255(c1.g, c2.g, R3),
lerp255(c1.b, c2.b, R3));
#endif
xchg(&x, &y);
}
}
}
++i;
++j;
}
}
}
/* for (i = 0; i < 255; ++i) { */
/* for (j = 0; j < 255; ++j) { */
/* for (k = 0; k < 255; ++k) { */
/* printf("0%03o%03o%03o\n", i, j, k); */
/* } */
/* } */
/* } */
return 0;
}

View file

@ -0,0 +1,177 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "dsp/tty/quant.h"
#include "libc/fmt/fmt.h"
#include "libc/log/check.h"
#include "libc/macros.h"
#include "libc/math.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "third_party/getopt/getopt.h"
#define USAGE \
" [FLAGS] [PATH...]\n\
\n\
Flags:\n\
-o PATH output path\n\
-h shows this information\n\
\n"
static size_t linecap_;
static FILE *in_, *out_;
static char *inpath_, *outpath_, *line_;
void PrintUsage(int rc, FILE *f) {
fputs("Usage: ", f);
fputs(program_invocation_name, f);
fputs(USAGE, f);
exit(rc);
}
void GetOpts(int *argc, char *argv[]) {
int opt;
outpath_ = "-";
while ((opt = getopt(*argc, argv, "?ho:")) != -1) {
switch (opt) {
case 'o':
outpath_ = optarg;
break;
case '?':
case 'h':
PrintUsage(EXIT_SUCCESS, stdout);
default:
PrintUsage(EX_USAGE, stderr);
}
}
if (optind == *argc) {
argv[(*argc)++] = "-";
}
}
#define U256F1(X) ((float)((X)&0xffu) * 256.0f)
#define F1U256(X) MAX(MIN(lrintl(roundl(256.0f * (X))), 255), 0)
forceinline struct TtyRgb getquant(unsigned xt) { return g_ansi2rgb_[xt]; }
forceinline unsigned dist(int x, int y) { return x - y; }
forceinline unsigned sqr(int x) { return x * x; }
static unsigned rgb2hsl(unsigned rgba) {
/* this is broken */
unsigned h8, s8, l8;
float r, g, b, h, s, d, l, cmax, cmin;
r = U256F1(rgba);
g = U256F1(rgba >> 010);
b = U256F1(rgba >> 020);
cmax = MAX(MAX(r, g), b);
cmin = MIN(MIN(r, g), b);
h = 0.0f;
s = 0.0f;
d = cmax - cmin;
l = (cmax + cmin) / 2.0f;
if (cmax != cmin) {
s = l > 0.5L ? d / (2.0f - cmax - cmin) : d / (cmax + cmin);
if (cmax == r) {
h = (g - b) / d + (g < b ? 6.0f : 0.0f);
} else if (cmax == g) {
h = (b - r) / d + 2.0f;
} else if (cmax == b) {
h = (r - g) / d + 4.0f;
}
h /= 6.0f;
}
h8 = F1U256(h);
s8 = F1U256(s);
l8 = F1U256(l);
return ((rgba >> 030) & 255) << 030 | l8 << 020 | s8 << 010 | h8;
}
static struct TtyRgb rgb2hsl2(struct TtyRgb rgb) {
unsigned x =
(unsigned)rgb.b << 020 | (unsigned)rgb.g << 010 | (unsigned)rgb.r;
unsigned y = rgb2hsl(x);
return (struct TtyRgb){
.r = y & 0xff, .g = (y >> 010) & 0xff, .b = (y >> 020) & 0xff};
}
static unsigned rgbdist(struct TtyRgb x, struct TtyRgb y) {
x = rgb2hsl2(x);
y = rgb2hsl2(y);
return sqrt(sqr(dist(x.r, y.r)) + sqr(dist(x.g, y.g)) + sqr(dist(x.b, y.b)));
}
static unsigned xtdist(unsigned x, unsigned y) {
return rgbdist(getquant(x), getquant(y));
}
void Show(unsigned color, unsigned bg, unsigned fg, unsigned glyph) {
uint8_t r, g, b;
b = (color >> 020) & 0xff;
g = (color >> 010) & 0xff;
r = color & 0xff;
printf("\tmix\t0x%04x,%3d,%3d,%3d,%3d,%3d,%3d\t# \e[48;2;%d;%d;%dm \e[0m\n",
rgbdist((struct TtyRgb){r, g, b, 0}, (struct TtyRgb){0, 0, 0, 0}), r,
g, b, bg, fg, glyph, r, g, b);
}
void ProcessFile(void) {
char *p;
unsigned color1, bg1, fg1, glyph1;
unsigned color, bg, fg, glyph;
color1 = -1u;
bg1 = -1u;
fg1 = -1u;
glyph1 = -1u;
while ((getline(&line_, &linecap_, in_)) != -1) {
p = chomp(line_);
sscanf(p, "%x, %u,%u,%u", &color, &bg, &fg, &glyph);
if (color != color1) {
if (color1 != -1u) {
Show(color1, bg1, fg1, glyph1);
}
color1 = color;
bg1 = bg;
fg1 = fg;
glyph1 = glyph;
}
if ((fg1 && !fg) || (fg && fg1 && xtdist(fg, bg) < xtdist(fg1, bg1))) {
color1 = color;
bg1 = bg;
fg1 = fg;
glyph1 = glyph;
}
}
Show(color1, bg1, fg1, glyph1);
}
int main(int argc, char *argv[]) {
size_t i;
GetOpts(&argc, argv);
CHECK_NOTNULL((out_ = fopen(outpath_, "w")));
for (i = optind; i < argc; ++i) {
CHECK_NOTNULL((in_ = fopen((inpath_ = argv[i]), "r")));
ProcessFile();
CHECK_NE(-1, fclose_s(&in_));
}
CHECK_NE(-1, fclose_s(&out_));
free(line_);
return 0;
}

1219
tool/viz/xterm256info.c Normal file

File diff suppressed because it is too large Load diff

75
tool/viz/ycbcrio.c Normal file
View file

@ -0,0 +1,75 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "dsp/mpeg/ycbcrio.h"
#include "libc/fmt/fmt.h"
#include "libc/log/check.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "third_party/getopt/getopt.h"
#define USAGE \
" [FLAGS] [PATH...]\n\
\n\
Flags:\n\
-h shows this information\n\
\n"
static char *inpath_;
static void PrintUsage(int rc, FILE *f) {
fputs("Usage: ", f);
fputs(program_invocation_name, f);
fputs(USAGE, f);
exit(rc);
}
static void GetOpts(int *argc, char *argv[]) {
int opt;
while ((opt = getopt(*argc, argv, "?h")) != -1) {
switch (opt) {
case '?':
case 'h':
PrintUsage(EXIT_SUCCESS, stdout);
default:
PrintUsage(EX_USAGE, stderr);
}
}
}
static void ProcessFile(struct Ycbcrio *m) {
/* m->frame-> */
}
int main(int argc, char *argv[]) {
size_t i;
struct Ycbcrio *m;
GetOpts(&argc, argv);
for (i = optind; i < argc; ++i) {
inpath_ = argv[i];
m = YcbcrioOpen(inpath_, NULL);
ProcessFile(m);
YcbcrioClose(&m);
}
return 0;
}