41
41
#ifdef OS_WINDOWS
42
42
#define CLK 0
43
43
44
- #define WINDOWS_CALL (cond , format ) \
45
- do { \
46
- if (UNLIKELY(cond)) \
47
- winError(format); \
44
+ #define WINDOWS_CALL (cond , format ) \
45
+ do { \
46
+ if (UNLIKELY(cond)) \
47
+ winError(format); \
48
48
} while (0)
49
49
50
50
static void winError (char * const format )
51
51
{
52
52
LPVOID lpMsgBuf ;
53
53
const DWORD dw = GetLastError ();
54
54
errno = dw ;
55
- FormatMessage (
56
- FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS ,
57
- NULL ,
58
- dw ,
59
- MAKELANGID (LANG_NEUTRAL , SUBLANG_DEFAULT ),
60
- (LPTSTR )& lpMsgBuf ,
61
- 0 , NULL );
55
+ FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
56
+ | FORMAT_MESSAGE_IGNORE_INSERTS ,
57
+ NULL , dw , MAKELANGID (LANG_NEUTRAL , SUBLANG_DEFAULT ), (LPTSTR )& lpMsgBuf , 0 , NULL );
62
58
I_Error (format , lpMsgBuf );
63
59
}
64
60
@@ -89,37 +85,36 @@ static int clock_gettime(const int p, struct timespec *const spec)
89
85
#define UNLIKELY (x ) (x)
90
86
#endif
91
87
92
- #define CALL (stmt , format ) \
93
- do { \
94
- if (UNLIKELY(stmt)) \
95
- I_Error(format, errno); \
88
+ #define CALL (stmt , format ) \
89
+ do { \
90
+ if (UNLIKELY(stmt)) \
91
+ I_Error(format, errno); \
96
92
} while (0)
97
93
#define CALL_STDOUT (stmt , format ) CALL((stmt) == EOF, format)
98
94
99
- #define BUF_ITOA (buf , byte ) \
100
- do { \
101
- *(buf)++ = '0' + (byte) / 100u; \
102
- *(buf)++ = '0' + (byte) / 10u % 10u; \
103
- *(buf)++ = '0' + (byte) % 10u; \
95
+ #define BUF_ITOA (buf , byte ) \
96
+ do { \
97
+ *(buf)++ = '0' + (byte) / 100u; \
98
+ *(buf)++ = '0' + (byte) / 10u % 10u; \
99
+ *(buf)++ = '0' + (byte) % 10u; \
104
100
} while (0)
105
-
106
- #define BUF_MEMCPY (buf , s , len ) \
107
- do { \
108
- memcpy(buf, s, len); \
109
- (buf) += (len); \
101
+ #define BUF_MEMCPY (buf , s , len ) \
102
+ do { \
103
+ memcpy(buf, s, len); \
104
+ (buf) += (len); \
110
105
} while (0)
111
-
112
- #define BUF_PUTS (buf , s ) \
113
- do { \
114
- BUF_MEMCPY(buf, s, sizeof(s) - 1); \
106
+ #define BUF_PUTS (buf , s ) \
107
+ do { \
108
+ BUF_MEMCPY(buf, s, static_strlen(s)); \
115
109
} while (0)
116
-
117
- #define BUF_PUTCHAR (buf , c ) \
118
- do { \
119
- *(buf)++ = c; \
110
+ #define BUF_PUTCHAR (buf , c ) \
111
+ do { \
112
+ *(buf)++ = c; \
120
113
} while (0)
121
114
122
- #define GRAD_LEN (sizeof(grad) - 1)
115
+ #define static_strlen (s ) (sizeof(s) - 1)
116
+
117
+ #define GRAD_LEN static_strlen(grad)
123
118
#define EVENT_BUFFER_LEN (INPUT_BUFFER_LEN * 2u - 1u)
124
119
125
120
enum {
@@ -128,8 +123,38 @@ enum {
128
123
RGB_SUM_MAX = 776U ,
129
124
};
130
125
131
- static const char grad [] = " .'`^\",:;Il!i><~+_-?][}{1)(|\\/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$" ;
126
+ static const char grad [] =
127
+ " .'`^\",:;Il!i><~+_-?][}{1)(|\\/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$" ;
132
128
static const char unicode_grad [] = "\u2591\u2592\u2593\u2588" ;
129
+ const char * braille_grads [] = { "\u2801\u2802\u2804\u2808\u2810\u2820\u2840\u2880" ,
130
+ "\u2803\u2805\u2806\u2809\u280a\u280c\u2811\u2812\u2814\u2818\u2821\u2822\u2824\u2828\u2830\u2841\u2842\u2844\u2848\u2850\u2860\u2881\u2882\u2884\u2888\u2890\u28a0\u28c0" ,
131
+ "\u2807\u280b\u280d\u280e\u2813\u2815\u2816\u2819\u281a\u281c\u2823\u2825\u2826\u2829\u282a\u282c\u2831\u2832\u2834\u2838\u2843\u2845\u2846\u2849\u284a\u284c\u2851\u2852\u2854\u2858\u2861\u2862\u2864\u2868\u2870\u2883\u2885\u2886\u2889\u288a\u288c\u2891\u2892\u2894\u2898\u28a1\u28a2\u28a4\u28a8\u28b0\u28c1\u28c2\u28c4\u28c8\u28d0\u28e0" ,
132
+ "\u280f\u2817\u281b\u281d\u281e\u2827\u282b\u282d\u282e\u2833\u2835\u2836\u2839\u283a\u283c\u2847\u284b\u284d\u284e\u2853\u2855\u2856\u2859\u285a\u285c\u2863\u2865\u2866\u2869\u286a\u286c\u2871\u2872\u2874\u2878\u2887\u288b\u288d\u288e\u2893\u2895\u2896\u2899\u289a\u289c\u28a3\u28a5\u28a6\u28a9\u28aa\u28ac\u28b1\u28b2\u28b4\u28b8\u28c3\u28c5\u28c6\u28c9\u28ca\u28cc\u28d1\u28d2\u28d4\u28d8\u28e1\u28e2\u28e4\u28e8\u28f0" ,
133
+ "\u281f\u282f\u2837\u283b\u283d\u283e\u284f\u2857\u285b\u285d\u285e\u2867\u286b\u286d\u286e\u2873\u2875\u2876\u2879\u287a\u287c\u288f\u2897\u289b\u289d\u289e\u28a7\u28ab\u28ad\u28ae\u28b3\u28b5\u28b6\u28b9\u28ba\u28bc\u28c7\u28cb\u28cd\u28ce\u28d3\u28d5\u28d6\u28d9\u28da\u28dc\u28e3\u28e5\u28e6\u28e9\u28ea\u28ec\u28f1\u28f2\u28f4\u28f8" ,
134
+ "\u283f\u285f\u286f\u2877\u287b\u287d\u287e\u289f\u28af\u28b7\u28bb\u28bd\u28be\u28cf\u28d7\u28db\u28dd\u28de\u28e7\u28eb\u28ed\u28ee\u28f3\u28f5\u28f6\u28f9\u28fa\u28fc" ,
135
+ "\u287f\u28bf\u28df\u28ef\u28f7\u28fb\u28fd\u28fe" , "\u28ff" };
136
+ const size_t braille_grad_lengths [] = { static_strlen (braille_grads [0 ]),
137
+ static_strlen (braille_grads [1 ]), static_strlen (braille_grads [2 ]),
138
+ static_strlen (braille_grads [3 ]), static_strlen (braille_grads [4 ]),
139
+ static_strlen (braille_grads [5 ]), static_strlen (braille_grads [6 ]),
140
+ static_strlen (braille_grads [7 ]) };
141
+
142
+ /* print(','.join(str(int(((i / 255)**0.5) * 255)) for i in range(256))) */
143
+ static const uint8_t byte_sqrt [] = { 0 , 15 , 22 , 27 , 31 , 35 , 39 , 42 , 45 , 47 , 50 , 52 , 55 , 57 , 59 , 61 ,
144
+ 63 , 65 , 67 , 69 , 71 , 73 , 74 , 76 , 78 , 79 , 81 , 82 , 84 , 85 , 87 , 88 , 90 , 91 , 93 , 94 , 95 , 97 , 98 ,
145
+ 99 , 100 , 102 , 103 , 104 , 105 , 107 , 108 , 109 , 110 , 111 , 112 , 114 , 115 , 116 , 117 , 118 , 119 ,
146
+ 120 , 121 , 122 , 123 , 124 , 125 , 126 , 127 , 128 , 129 , 130 , 131 , 132 , 133 , 134 , 135 , 136 , 137 ,
147
+ 138 , 139 , 140 , 141 , 141 , 142 , 143 , 144 , 145 , 146 , 147 , 148 , 148 , 149 , 150 , 151 , 152 , 153 ,
148
+ 153 , 154 , 155 , 156 , 157 , 158 , 158 , 159 , 160 , 161 , 162 , 162 , 163 , 164 , 165 , 165 , 166 , 167 ,
149
+ 168 , 168 , 169 , 170 , 171 , 171 , 172 , 173 , 174 , 174 , 175 , 176 , 177 , 177 , 178 , 179 , 179 , 180 ,
150
+ 181 , 182 , 182 , 183 , 184 , 184 , 185 , 186 , 186 , 187 , 188 , 188 , 189 , 190 , 190 , 191 , 192 , 192 ,
151
+ 193 , 194 , 194 , 195 , 196 , 196 , 197 , 198 , 198 , 199 , 200 , 200 , 201 , 201 , 202 , 203 , 203 , 204 ,
152
+ 205 , 205 , 206 , 206 , 207 , 208 , 208 , 209 , 210 , 210 , 211 , 211 , 212 , 213 , 213 , 214 , 214 , 215 ,
153
+ 216 , 216 , 217 , 217 , 218 , 218 , 219 , 220 , 220 , 221 , 221 , 222 , 222 , 223 , 224 , 224 , 225 , 225 ,
154
+ 226 , 226 , 227 , 228 , 228 , 229 , 229 , 230 , 230 , 231 , 231 , 232 , 233 , 233 , 234 , 234 , 235 , 235 ,
155
+ 236 , 236 , 237 , 237 , 238 , 238 , 239 , 240 , 240 , 241 , 241 , 242 , 242 , 243 , 243 , 244 , 244 , 245 ,
156
+ 245 , 246 , 246 , 247 , 247 , 248 , 248 , 249 , 249 , 250 , 250 , 251 , 251 , 252 , 252 , 253 , 253 , 254 ,
157
+ 255 };
133
158
134
159
struct color_t {
135
160
uint32_t b : 8 ;
@@ -138,6 +163,8 @@ struct color_t {
138
163
uint32_t a : 8 ;
139
164
};
140
165
166
+ enum character_set_t { ASCII , BLOCK , BRAILLE };
167
+
141
168
static char * output_buffer ;
142
169
static size_t output_buffer_size ;
143
170
static struct timespec ts_init ;
@@ -147,10 +174,11 @@ static uint16_t event_buffer[EVENT_BUFFER_LEN];
147
174
static uint16_t * event_buf_loc ;
148
175
149
176
static bool color_enabled ;
150
- static bool unicode_enabled ;
177
+ static enum character_set_t character_set = ASCII ;
151
178
static bool gradient_enabled ;
152
179
static bool bold_enabled ;
153
180
static bool erase_enabled ;
181
+ static bool gamma_correct_enabled ;
154
182
155
183
void DG_AtExit (void )
156
184
{
@@ -188,7 +216,8 @@ void DG_Init(void)
188
216
const HANDLE hInputHandle = GetStdHandle (STD_INPUT_HANDLE );
189
217
WINDOWS_CALL (hInputHandle == INVALID_HANDLE_VALUE , "DG_Init: %s" );
190
218
WINDOWS_CALL (!GetConsoleMode (hInputHandle , & mode ), "DG_Init: %s" );
191
- mode &= ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT | ENABLE_QUICK_EDIT_MODE | ENABLE_ECHO_INPUT );
219
+ mode &= ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT | ENABLE_QUICK_EDIT_MODE
220
+ | ENABLE_ECHO_INPUT );
192
221
WINDOWS_CALL (!SetConsoleMode (hInputHandle , mode ), "DG_Init: %s" );
193
222
#else
194
223
struct termios t ;
@@ -202,21 +231,37 @@ void DG_Init(void)
202
231
gradient_enabled = M_CheckParm ("-nograd" ) == 0 ;
203
232
bold_enabled = M_CheckParm ("-nobold" ) == 0 ;
204
233
erase_enabled = M_CheckParm ("-erase" ) > 0 ;
205
- unicode_enabled = M_CheckParm ("-unicode" ) > 0 ;
234
+ gamma_correct_enabled = M_CheckParm ("-fixgamma" ) > 0 ;
235
+
236
+ int i = M_CheckParmWithArgs ("-chars" , 1 );
237
+ if (i > 0 ) {
238
+ if (!strcmp ("ascii" , myargv [i + 1 ])) {
239
+ character_set = ASCII ;
240
+ } else if (!strcmp ("block" , myargv [i + 1 ])) {
241
+ character_set = BLOCK ;
242
+ } else if (!strcmp ("braille" , myargv [i + 1 ])) {
243
+ character_set = BRAILLE ;
244
+ } else {
245
+ I_Error ("Unrecognized argument for -chars: '%s'" , myargv [i + 1 ]);
246
+ }
247
+ }
206
248
207
- if (unicode_enabled && !setlocale (LC_ALL , "en_US.UTF-8" ))
249
+ if (character_set != ASCII && !setlocale (LC_ALL , "en_US.UTF-8" ))
208
250
I_Error ("DG_Init: setlocale error" );
209
251
210
252
/* Longest per-pixel SGR code: \033[38;2;RRR;GGG;BBBm (length 19)
211
- * 3 Chars per pixel (unicode)
253
+ * 2 Chars per pixel
212
254
* 1 Newline character per line
213
255
* 1 NUL terminator
214
256
* SGR move cursor code: \033[;H (length 4)
215
257
* SGR clear code: \033[0m (length 4)
216
258
* SGR bold code: \033[1m (length 4)
217
259
* SGR erase code: \033[2J (length 4)
218
260
*/
219
- output_buffer_size = ((color_enabled ? 19U : 0U ) + (unicode_enabled ? 6U : 2U )) * DOOMGENERIC_RESX * DOOMGENERIC_RESY + DOOMGENERIC_RESY + 1U + 4U + (bold_enabled ? 4U : 0U ) + (erase_enabled ? 4U : 0U ) + ((color_enabled || bold_enabled ) ? 4U : 0U );
261
+ output_buffer_size = ((color_enabled ? 19U : 0U ) + (character_set == ASCII ? 2U : 6U ))
262
+ * DOOMGENERIC_RESX * DOOMGENERIC_RESY
263
+ + DOOMGENERIC_RESY + 1U + 4U + (bold_enabled ? 4U : 0U ) + (erase_enabled ? 4U : 0U )
264
+ + ((color_enabled || bold_enabled ) ? 4U : 0U );
220
265
output_buffer = malloc (output_buffer_size );
221
266
222
267
CALL (clock_gettime (CLK , & ts_init ), "DG_Init: clock_gettime error %d" );
@@ -246,6 +291,12 @@ void DG_DrawFrame(void)
246
291
BUF_PUTS (buf , "\033[1m" );
247
292
for (row = 0 ; row < DOOMGENERIC_RESY ; row ++ ) {
248
293
for (col = 0 ; col < DOOMGENERIC_RESX ; col ++ ) {
294
+ if (gamma_correct_enabled ) {
295
+ pixel -> r = byte_sqrt [pixel -> r ];
296
+ pixel -> g = byte_sqrt [pixel -> g ];
297
+ pixel -> b = byte_sqrt [pixel -> b ];
298
+ }
299
+
249
300
if (color_enabled && (color ^ * (uint32_t * )pixel ) & 0x00FFFFFF ) {
250
301
BUF_PUTS (buf , "\033[38;2;" );
251
302
BUF_ITOA (buf , pixel -> r );
@@ -257,11 +308,24 @@ void DG_DrawFrame(void)
257
308
color = * (uint32_t * )pixel ;
258
309
}
259
310
260
- if (unicode_enabled ) {
311
+ switch (character_set ) {
312
+ case ASCII :
313
+ if (gradient_enabled ) {
314
+ const char v_char = grad [(pixel -> r + pixel -> g + pixel -> b )
315
+ * GRAD_LEN / RGB_SUM_MAX ];
316
+ BUF_PUTCHAR (buf , v_char );
317
+ BUF_PUTCHAR (buf , v_char );
318
+ } else {
319
+ BUF_PUTS (buf , "##" );
320
+ }
321
+ break ;
322
+ case BLOCK :
261
323
if (gradient_enabled ) {
262
- const size_t idx = (pixel -> r + pixel -> g + pixel -> b ) * (UNICODE_GRAD_LEN + 1U ) / RGB_SUM_MAX ;
324
+ const size_t idx = (pixel -> r + pixel -> g + pixel -> b )
325
+ * (UNICODE_GRAD_LEN + 1U ) / RGB_SUM_MAX ;
263
326
if (idx ) {
264
- const void * const v_char = & unicode_grad [(idx - 1 ) * 3 ];
327
+ const void * const v_char =
328
+ & unicode_grad [(idx - 1 ) * 3 ];
265
329
BUF_MEMCPY (buf , v_char , 3 );
266
330
BUF_MEMCPY (buf , v_char , 3 );
267
331
} else {
@@ -270,14 +334,24 @@ void DG_DrawFrame(void)
270
334
} else {
271
335
BUF_PUTS (buf , "\u2588\u2588" );
272
336
}
273
- } else {
337
+ break ;
338
+ case BRAILLE :
274
339
if (gradient_enabled ) {
275
- const char v_char = grad [(pixel -> r + pixel -> g + pixel -> b ) * GRAD_LEN / RGB_SUM_MAX ];
276
- BUF_PUTCHAR (buf , v_char );
277
- BUF_PUTCHAR (buf , v_char );
340
+ const size_t idx =
341
+ (pixel -> r + pixel -> g + pixel -> b ) * 8 / RGB_SUM_MAX ;
342
+ if (idx ) {
343
+ const char * const gradient = braille_grads [idx - 1 ];
344
+ const size_t len =
345
+ braille_grad_lengths [idx - 1 ] / 3 ;
346
+ BUF_MEMCPY (buf , & gradient [(random () % len ) * 3 ], 3 );
347
+ BUF_MEMCPY (buf , & gradient [(random () % len ) * 3 ], 3 );
348
+ } else {
349
+ BUF_PUTS (buf , " " );
350
+ }
278
351
} else {
279
- BUF_PUTS (buf , "## " );
352
+ BUF_PUTS (buf , "\u28ff\u28ff " );
280
353
}
354
+ break ;
281
355
}
282
356
283
357
pixel ++ ;
@@ -540,12 +614,16 @@ void DG_ReadInput(void)
540
614
unsigned input_count = 0 ;
541
615
if (event_cnt ) {
542
616
INPUT_RECORD input_records [32 ];
543
- WINDOWS_CALL (!ReadConsoleInput (hInputHandle , input_records , 32 , & event_cnt ), "DG_ReadInput: %s" );
617
+ WINDOWS_CALL (!ReadConsoleInput (hInputHandle , input_records , 32 , & event_cnt ),
618
+ "DG_ReadInput: %s" );
544
619
545
620
DWORD i ;
546
621
for (i = 0 ; i < event_cnt ; i ++ ) {
547
- if (input_records [i ].Event .KeyEvent .bKeyDown && input_records [i ].EventType == KEY_EVENT ) {
548
- unsigned char inp = convertToDoomKey (input_records [i ].Event .KeyEvent .wVirtualKeyCode , input_records [i ].Event .KeyEvent .uChar .AsciiChar );
622
+ if (input_records [i ].Event .KeyEvent .bKeyDown
623
+ && input_records [i ].EventType == KEY_EVENT ) {
624
+ unsigned char inp = convertToDoomKey (
625
+ input_records [i ].Event .KeyEvent .wVirtualKeyCode ,
626
+ input_records [i ].Event .KeyEvent .uChar .AsciiChar );
549
627
if (inp ) {
550
628
input_buffer [input_count ++ ] = inp ;
551
629
if (input_count == INPUT_BUFFER_LEN - 1u )
0 commit comments