-
Notifications
You must be signed in to change notification settings - Fork 2
/
grapher.c
160 lines (126 loc) · 3.05 KB
/
grapher.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// grapher.c
//
// by Abraham Stolk.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <inttypes.h>
#include <signal.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>
#include "grapher.h"
#define HALFBLOCK "▀" // Uses Unicode char U+2580
static int termw = 0, termh = 0;
int imw = 0;
int imh = 0;
uint32_t* im = 0;
char* overlay = 0;
char postscript[256];
int grapher_resized = 1;
static void get_terminal_size(void)
{
struct winsize tmp;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &tmp);
termw = tmp.ws_col;
termh = tmp.ws_row;
}
static void setup_image(void)
{
if (im) free(im);
if (overlay) free(overlay);
imw = termw;
imh = 2 * (termh-1);
const size_t sz = imw * imh * 4;
im = (uint32_t*) malloc(sz);
memset( im, 0x00, sz );
overlay = (char*) malloc( imw * (imh/2) );
memset( overlay, 0x00, imw * (imh/2) );
}
static void sigwinchHandler(int sig)
{
(void)sig; // unused
grapher_resized = 1;
}
static void print_image_double_res( int w, int h, unsigned char* data, char* overlay )
{
if ( h & 1 )
h--;
const int linesz = 32768;
char line[ linesz ];
for ( int y = 0; y<h; y += 2 )
{
const unsigned char* row0 = data + (y + 0) * w * 4;
const unsigned char* row1 = data + (y + 1) * w * 4;
line[0] = 0;
for ( int x = 0; x<w; ++x )
{
char overlaychar = overlay ? *overlay++ : 0;
// foreground colour.
strncat( line, "\x1b[38;2;", sizeof(line) - strlen(line) - 1 );
char tripl[80];
unsigned char r = *row0++;
unsigned char g = *row0++;
unsigned char b = *row0++;
unsigned char a = *row0++;
if ( overlaychar ) r = g = b = a = 0xff;
snprintf( tripl, sizeof(tripl), "%d;%d;%dm", r,g,b );
strncat( line, tripl, sizeof(line) - strlen(line) - 1 );
// background colour.
strncat( line, "\x1b[48;2;", sizeof(line) - strlen(line) - 1 );
r = *row1++;
g = *row1++;
b = *row1++;
a = *row1++;
if ( overlaychar ) r = g = b = a = 0x00;
if ( overlaychar )
snprintf( tripl, sizeof(tripl), "%d;%d;%dm%c", r,g,b,overlaychar );
else
snprintf( tripl, sizeof(tripl), "%d;%d;%dm" HALFBLOCK, r,g,b );
strncat( line, tripl, sizeof(line) - strlen(line) - 1 );
}
strncat( line, RESETALL, sizeof(line) - strlen(line) - 1 );
if ( y == h - 1 )
printf( "%s", line );
else
puts( line );
}
}
int grapher_init( void )
{
if ( system("tty -s 1> /dev/null 2> /dev/null") )
return -1;
// Listen to changes in terminal size
struct sigaction sa;
sigemptyset( &sa.sa_mask );
sa.sa_flags = 0;
sa.sa_handler = sigwinchHandler;
if ( sigaction( SIGWINCH, &sa, 0 ) == -1 )
perror( "sigaction" );
return 0;
}
void grapher_adapt_to_new_size(void)
{
printf(CLEARSCREEN);
get_terminal_size();
setup_image();
grapher_resized = 0;
}
void grapher_update( void )
{
printf( CURSORHOME );
print_image_double_res( imw, imh, (unsigned char*) im, overlay );
printf(SETBG "0;0;0m");
printf( "%s", postscript );
fflush( stdout );
}
void grapher_exit(void)
{
free(im);
printf( RESETALL );
printf( CLEARSCREEN );
}