mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-02 09:18:31 +00:00
Initial import
This commit is contained in:
commit
c91b3c5006
14915 changed files with 590219 additions and 0 deletions
121
tool/viz/ascii2utf8.c
Normal file
121
tool/viz/ascii2utf8.c
Normal 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
265
tool/viz/basicidea.c
Normal 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
44
tool/viz/bin2asm.c
Normal 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
93
tool/viz/bing.c
Normal 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
104
tool/viz/comma.c
Normal 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
322
tool/viz/cpuid.c
Normal 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
149
tool/viz/deathstar.c
Normal 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
619
tool/viz/derasterize.c
Normal 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
43
tool/viz/double2int.c
Normal 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
85
tool/viz/fold.c
Normal 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
314
tool/viz/generatematrix.c
Normal 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);
|
||||
}
|
63
tool/viz/generatetortureimage.c
Normal file
63
tool/viz/generatetortureimage.c
Normal 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
82
tool/viz/int2float.c
Normal 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
115
tool/viz/invertblocks.c
Normal 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;
|
||||
}
|
41
tool/viz/lib/ansitrinsics.h
Normal file
41
tool/viz/lib/ansitrinsics.h
Normal 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_ */
|
101
tool/viz/lib/bilinearscale.c
Normal file
101
tool/viz/lib/bilinearscale.c
Normal 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;
|
||||
}
|
14
tool/viz/lib/bilinearscale.h
Normal file
14
tool/viz/lib/bilinearscale.h
Normal 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
30
tool/viz/lib/boxblur.c
Normal 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
40
tool/viz/lib/convoindex.c
Normal 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;
|
||||
}
|
67
tool/viz/lib/convolution.h
Normal file
67
tool/viz/lib/convolution.h
Normal 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
42
tool/viz/lib/convolve.h
Normal 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
124
tool/viz/lib/dither.c
Normal 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);
|
||||
}
|
54
tool/viz/lib/doublechrominance.S
Normal file
54
tool/viz/lib/doublechrominance.S
Normal 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
31
tool/viz/lib/emboss.c
Normal 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);
|
||||
}
|
59
tool/viz/lib/formatmatrix-byte.c
Normal file
59
tool/viz/lib/formatmatrix-byte.c
Normal 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);
|
||||
}
|
65
tool/viz/lib/formatmatrix-double.c
Normal file
65
tool/viz/lib/formatmatrix-double.c
Normal 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);
|
||||
}
|
57
tool/viz/lib/formatmatrix-float.c
Normal file
57
tool/viz/lib/formatmatrix-float.c
Normal 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);
|
||||
}
|
59
tool/viz/lib/formatmatrix-short.c
Normal file
59
tool/viz/lib/formatmatrix-short.c
Normal 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);
|
||||
}
|
126
tool/viz/lib/formatstringtable-assembly.c
Normal file
126
tool/viz/lib/formatstringtable-assembly.c
Normal 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;
|
||||
}
|
28
tool/viz/lib/formatstringtable-assertion.c
Normal file
28
tool/viz/lib/formatstringtable-assertion.c
Normal 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", " ", "");
|
||||
}
|
26
tool/viz/lib/formatstringtable-basic.c
Normal file
26
tool/viz/lib/formatstringtable-basic.c
Normal 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");
|
||||
}
|
41
tool/viz/lib/formatstringtable-code.c
Normal file
41
tool/viz/lib/formatstringtable-code.c
Normal 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;
|
||||
}
|
66
tool/viz/lib/formatstringtable-testlib.h
Normal file
66
tool/viz/lib/formatstringtable-testlib.h
Normal 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_ */
|
60
tool/viz/lib/formatstringtable.c
Normal file
60
tool/viz/lib/formatstringtable.c
Normal 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;
|
||||
}
|
49
tool/viz/lib/formatstringtable.h
Normal file
49
tool/viz/lib/formatstringtable.h
Normal 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
71
tool/viz/lib/gaussian.c
Normal 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;
|
||||
}
|
33
tool/viz/lib/getxtermcodes.c
Normal file
33
tool/viz/lib/getxtermcodes.c
Normal 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
545
tool/viz/lib/glyphs.c
Normal 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),
|
||||
/* ▁ *\
|
||||
2501▕━▎box 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),
|
||||
/* ▁ *\
|
||||
25019▕┉▎box 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),
|
||||
/* ▁ *\
|
||||
2503▕┃▎box 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),
|
||||
/* ▁ *\
|
||||
254b▕╋▎box 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),
|
||||
/* ▁ *\
|
||||
2579▕╹▎box 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),
|
||||
/* ▁ *\
|
||||
257a▕╺▎box 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),
|
||||
/* ▁ *\
|
||||
257b▕╻▎box 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),
|
||||
/* ▁ *\
|
||||
2578▕╸▎box 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),
|
||||
/* ▁ *\
|
||||
250f▕┏▎box 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),
|
||||
/* ▁ *\
|
||||
251b▕┛▎box 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),
|
||||
/* ▁ *\
|
||||
2513▕┓▎box 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),
|
||||
/* ▁ *\
|
||||
2517▕┗▎box 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),
|
||||
/* ▁ *\
|
||||
25E2▕◢▎black 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),
|
||||
/* ▁ *\
|
||||
25E3▕◣▎black 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),
|
||||
/* ▁ *\
|
||||
25E4▕◥▎black 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),
|
||||
/* ▁ *\
|
||||
25E5▕◤▎black 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),
|
||||
/* ▁ *\
|
||||
2500▕═▎box 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),
|
||||
/* ▁ *\
|
||||
23BB▕⎻▎horizontal 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),
|
||||
/* ▁ *\
|
||||
23BD▕⎼▎horizontal 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
58
tool/viz/lib/graphic.h
Normal 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
35
tool/viz/lib/halfblit.c
Normal 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
10
tool/viz/lib/halfblit.h
Normal 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
21
tool/viz/lib/knobs.h
Normal 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
106
tool/viz/lib/perlin3.c
Normal 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());
|
38
tool/viz/lib/resizegraphic.c
Normal file
38
tool/viz/lib/resizegraphic.c
Normal 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
12
tool/viz/lib/scale.h
Normal 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
71
tool/viz/lib/sharpen.c
Normal 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
76
tool/viz/lib/sobel.c
Normal 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);
|
||||
}
|
||||
}
|
56
tool/viz/lib/stringbuilder.c
Normal file
56
tool/viz/lib/stringbuilder.c
Normal 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;
|
||||
}
|
21
tool/viz/lib/stringbuilder.h
Normal file
21
tool/viz/lib/stringbuilder.h
Normal 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_ */
|
29
tool/viz/lib/thunks/expect_matrixeq.S
Normal file
29
tool/viz/lib/thunks/expect_matrixeq.S
Normal 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
73
tool/viz/lib/unsharp.c
Normal 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
120
tool/viz/lib/vizlib.mk
Normal 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)
|
42
tool/viz/lib/writetoframebuffer.c
Normal file
42
tool/viz/lib/writetoframebuffer.c
Normal 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
34
tool/viz/lib/ycbcr.h
Normal 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
395
tool/viz/lib/ycbcr2rgb3.c
Normal 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 Y′CbCr 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 Y′CbCr 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 Y′CbCr 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
678
tool/viz/magikarp.c
Normal 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
110
tool/viz/od16.c
Normal 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
263
tool/viz/printimage.c
Normal 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
543
tool/viz/printpeb.c
Normal 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
1666
tool/viz/printvideo.c
Normal file
File diff suppressed because it is too large
Load diff
163
tool/viz/resize.c
Normal file
163
tool/viz/resize.c
Normal 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
133
tool/viz/rgbtoxterm.c
Normal 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
175
tool/viz/tabalign.c
Normal 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
56
tool/viz/unbing.c
Normal 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
212
tool/viz/upscalefloat.c
Normal 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
209
tool/viz/upscaleint.c
Normal 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
89
tool/viz/viz.mk
Normal 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
186
tool/viz/xterm256cubes.c
Normal 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;
|
||||
}
|
184
tool/viz/xterm256effective.c
Normal file
184
tool/viz/xterm256effective.c
Normal 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;
|
||||
}
|
177
tool/viz/xterm256effective2.c
Normal file
177
tool/viz/xterm256effective2.c
Normal 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
1219
tool/viz/xterm256info.c
Normal file
File diff suppressed because it is too large
Load diff
75
tool/viz/ycbcrio.c
Normal file
75
tool/viz/ycbcrio.c
Normal 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;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue