add farbfeld output

This commit is contained in:
Kiëd Llaentenn 2020-09-19 12:59:55 +00:00
parent fc0d0207aa
commit 6765bb8fc7
11 changed files with 334 additions and 90 deletions

8
args.h
View File

@ -26,11 +26,17 @@ extern char *argv0;
typedef struct Options {
size_t refresh_rate;
size_t animation_speed;
size_t max_heat_loss;
size_t heat_loss;
size_t wind;
size_t random_factor;
bool random_wind;
bool truecolor;
uint32_t width;
uint32_t height;
bool farbfeld_mode;
size_t ff_frame;
} Options;
/* use main(int argc, char *argv[]) */

70
colors.c Normal file
View File

@ -0,0 +1,70 @@
#ifndef COLORS_INCLUDED
#define COLORS_INCLUDED
#include "colors.h"
#include "termbox.h"
#define BLACK 0x000000
const struct tb_cell normcolors[13] = {
// default
{ ' ', 9, 0 },
// red/black
{ 0x2591, 2, 0 },
{ 0x2592, 2, 0 },
{ 0x2593, 2, 0 },
{ 0x2588, 2, 0 },
// yellow/red
{ 0x2591, 4, 2 },
{ 0x2592, 4, 2 },
{ 0x2593, 4, 2 },
{ 0x2588, 4, 2 },
// white/red
{ 0x2591, 8, 2 },
{ 0x2592, 8, 2 },
{ 0x2593, 8, 2 },
{ 0x2588, 8, 2 },
};
const struct tb_cell truecolors[36] = {
{ ' ', BLACK, 0x070707 },
{ ' ', BLACK, 0x1F0707 },
{ ' ', BLACK, 0x2F0F07 },
{ ' ', BLACK, 0x470F07 },
{ ' ', BLACK, 0x571707 },
{ ' ', BLACK, 0x671F07 },
{ ' ', BLACK, 0x771F07 },
{ ' ', BLACK, 0x8F2707 },
{ ' ', BLACK, 0x9F2F07 },
{ ' ', BLACK, 0xAF3F07 },
{ ' ', BLACK, 0xBF4707 },
{ ' ', BLACK, 0xC74707 },
{ ' ', BLACK, 0xDF4F07 },
{ ' ', BLACK, 0xDF5707 },
{ ' ', BLACK, 0xDF5707 },
{ ' ', BLACK, 0xD75F07 },
{ ' ', BLACK, 0xD7670F },
{ ' ', BLACK, 0xCF6F0F },
{ ' ', BLACK, 0xCF770F },
{ ' ', BLACK, 0xCF7F0F },
{ ' ', BLACK, 0xCF8717 },
{ ' ', BLACK, 0xC78717 },
{ ' ', BLACK, 0xC78F17 },
{ ' ', BLACK, 0xC7971F },
{ ' ', BLACK, 0xBF9F1F },
{ ' ', BLACK, 0xBF9F1F },
{ ' ', BLACK, 0xBFA727 },
{ ' ', BLACK, 0xBFA727 },
{ ' ', BLACK, 0xBFAF2F },
{ ' ', BLACK, 0xB7AF2F },
{ ' ', BLACK, 0xB7B737 },
{ ' ', BLACK, 0xCFCF6F },
{ ' ', BLACK, 0xDFDF9F },
{ ' ', BLACK, 0xEFEFC7 },
{ ' ', BLACK, 0xFFFFFF }
};
#endif

View File

@ -3,74 +3,7 @@
#include "termbox.h"
#ifdef __OpenBSD__
#include "sys/types.h"
#else
#include "stdint.h"
#endif
#define BLACK 0x000000
struct tb_cell normcolors[13] =
{
// default
{ ' ', 9, 0 },
// red/black
{ 0x2591, 2, 0 },
{ 0x2592, 2, 0 },
{ 0x2593, 2, 0 },
{ 0x2588, 2, 0 },
// yellow/red
{ 0x2591, 4, 2 },
{ 0x2592, 4, 2 },
{ 0x2593, 4, 2 },
{ 0x2588, 4, 2 },
// white/red
{ 0x2591, 8, 2 },
{ 0x2592, 8, 2 },
{ 0x2593, 8, 2 },
{ 0x2588, 8, 2 },
};
struct tb_cell truecolors[36] = {
{ ' ', BLACK, 0x070707 },
{ ' ', BLACK, 0x1F0707 },
{ ' ', BLACK, 0x2F0F07 },
{ ' ', BLACK, 0x470F07 },
{ ' ', BLACK, 0x571707 },
{ ' ', BLACK, 0x671F07 },
{ ' ', BLACK, 0x771F07 },
{ ' ', BLACK, 0x8F2707 },
{ ' ', BLACK, 0x9F2F07 },
{ ' ', BLACK, 0xAF3F07 },
{ ' ', BLACK, 0xBF4707 },
{ ' ', BLACK, 0xC74707 },
{ ' ', BLACK, 0xDF4F07 },
{ ' ', BLACK, 0xDF5707 },
{ ' ', BLACK, 0xDF5707 },
{ ' ', BLACK, 0xD75F07 },
{ ' ', BLACK, 0xD7670F },
{ ' ', BLACK, 0xCF6F0F },
{ ' ', BLACK, 0xCF770F },
{ ' ', BLACK, 0xCF7F0F },
{ ' ', BLACK, 0xCF8717 },
{ ' ', BLACK, 0xC78717 },
{ ' ', BLACK, 0xC78F17 },
{ ' ', BLACK, 0xC7971F },
{ ' ', BLACK, 0xBF9F1F },
{ ' ', BLACK, 0xBF9F1F },
{ ' ', BLACK, 0xBFA727 },
{ ' ', BLACK, 0xBFA727 },
{ ' ', BLACK, 0xBFAF2F },
{ ' ', BLACK, 0xB7AF2F },
{ ' ', BLACK, 0xB7B737 },
{ ' ', BLACK, 0xCFCF6F },
{ ' ', BLACK, 0xDFDF9F },
{ ' ', BLACK, 0xEFEFC7 },
{ ' ', BLACK, 0xFFFFFF }
};
extern struct tb_cell normcolors[13];
extern struct tb_cell truecolors[36];
#endif

32
draw.c
View File

@ -22,11 +22,11 @@ extern struct Options *opts;
// initialize the framebuffer
void
init(struct buffer *buf)
init(struct buffer *buf, uint16_t width, uint16_t height)
{
// initialize width/height of terminal
buf->width = tb_width();
buf->height = tb_height();
buf->width = width;
buf->height = height;
size_t len = buf->width * buf->height;
buf->buf = (uint8_t*) calloc(len, sizeof(uint8_t));
@ -49,21 +49,26 @@ void
dofire(struct buffer *buf)
{
size_t src;
size_t random = (rand() % 7) & 3;
size_t rnd_wind = (lrand48() % 7) & 3;
size_t rnd_lose = lrand48() % 100;
size_t rnd_loss = (lrand48() % 7) & 3;
size_t dest;
struct tb_cell *realbuf = tb_cell_buffer();
for (size_t x = 0; x < buf->width; ++x) {
for (size_t y = 1; y < buf->height; ++y) {
if ((rand() % opts->random_factor) == 0) {
random = (rand() % 7) & 3;
// TODO; test rngs
if ((lrand48() % opts->random_factor) == 0) {
rnd_wind = (lrand48() % 7) & 3;
rnd_lose = lrand48() % 100;
rnd_loss = (lrand48() % 7) & 3;
}
src = y * buf->width + x;
if (opts->random_wind) {
dest = src - random + opts->wind;
dest = src - rnd_wind + opts->wind;
} else {
dest = src + opts->wind;
}
@ -84,13 +89,21 @@ dofire(struct buffer *buf)
dest -= buf->width;
}
size_t loss = MIN(opts->max_heat_loss, 3);
buf->buf[dest] = MAX(buf->buf[src] - (random & loss), 0);
size_t loss = rnd_lose < opts->heat_loss ? 2 : 0;
buf->buf[dest] = MAX(buf->buf[src] - (rnd_loss & loss), 0);
if (buf->buf[dest] > max_value) {
buf->buf[dest] = 0;
}
// TODO: comment everything
// copy from our buffer to termbox's buffer
// unless, of course, our buffer is bigger
if (src >= tb_width() * tb_height()) {
continue;
}
realbuf[dest] = colors[buf->buf[dest]];
realbuf[src] = colors[buf->buf[src]];
}
@ -103,5 +116,4 @@ void
cleanup(struct buffer *buf)
{
free(buf->buf);
tb_shutdown();
}

2
draw.h
View File

@ -14,7 +14,7 @@ struct buffer {
uint8_t* buf;
};
void init(struct buffer *buf);
void init(struct buffer *buf, uint16_t width, uint16_t height);
void dofire(struct buffer *buf);
void cleanup(struct buffer *buf);

54
ff.c Normal file
View File

@ -0,0 +1,54 @@
/*
* winsock.h on windows,
* arpa/inet.h on unix
* for htons()
*/
#if defined(_WIN32) || defined(__WIN32__)
#include <winsock.h>
#else
#include <arpa/inet.h>
#endif
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "termbox.h"
#include "bool.h"
#include "ff.h"
static uint16_t
clr(uint32_t clr)
{
uint16_t nclr = (((uint16_t) clr) & 0xff) & 0xffff;
return nclr | (nclr << 8);
}
void
ff_from_tbscr(uint32_t width, uint32_t height, uint8_t *img, struct tb_cell *colors, FILE *fp)
{
/* write farbfeld headers */
fputs("farbfeld", fp);
uint32_t tmp;
tmp = htonl(width);
fwrite(&tmp, sizeof(tmp), 1, fp);
tmp = htonl(height);
fwrite(&tmp, sizeof(tmp), 1, fp);
/* write image row by row */
uint16_t *rowbuf = malloc(width * (4 * sizeof(uint16_t)));
for (size_t y = 0; y < height; ++y) {
for (size_t x = 0; x < width; ++x) {
uint32_t color = colors[img[y * width + x]].bg;
rowbuf[4 * x + 0] = htons(clr(color >> 16));
rowbuf[4 * x + 1] = htons(clr(color >> 8));
rowbuf[4 * x + 2] = htons(clr(color));
rowbuf[4 * x + 3] = htons((uint16_t) 0xffff);
}
fwrite(rowbuf, sizeof(uint16_t), width * 4, fp);
memset(rowbuf, 0, width * (4 * sizeof(uint16_t)));
}
}

15
ff.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef FF_H
#define FF_H
#include <stdio.h>
#include <stdint.h>
#include "termbox.h"
#include "bool.h"
void ff_from_tbscr(
uint32_t width, uint32_t height,
uint8_t *img, struct tb_cell *colors,
FILE *fp
);
#endif

53
main.c
View File

@ -1,10 +1,16 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "bool.h"
#include "output.h"
#include "draw.h"
#include "colors.h"
#include "terminfo.h"
#include "termbox.h"
#include "args.h"
#include "ff.h"
#ifdef __OpenBSD__
#include "sys/types.h"
@ -31,15 +37,29 @@ main(int argc, char *argv[])
opts->refresh_rate = 1;
size_t output_mode = TB_OUTPUT_NORMAL;
opts->truecolor = FALSE;
opts->max_heat_loss = 1;
opts->heat_loss = 45;
opts->wind = 1;
opts->random_wind = TRUE;
opts->random_factor = 4;
opts->width = ttywidth();
opts->height = ttyheight();
// argument parsing
argv0 = argv[0];
ARGBEGIN {
case 'F':
opts->farbfeld_mode = TRUE;
opts->ff_frame = atoi(ARGF());
output_mode = TB_OUTPUT_TRUECOLOR;
opts->truecolor = TRUE;
break;
case 'H':
opts->height = atoi(ARGF());
break;
case 'W':
opts->width = atoi(ARGF());
break;
case 't':
output_mode = TB_OUTPUT_TRUECOLOR;
opts->truecolor = TRUE;
@ -51,7 +71,7 @@ main(int argc, char *argv[])
opts->refresh_rate = atoi(ARGF());
break;
case 'l':
opts->max_heat_loss = atoi(ARGF());
opts->heat_loss = atoi(ARGF());
break;
case 'w':
opts->wind = atoi(ARGF());
@ -62,6 +82,7 @@ main(int argc, char *argv[])
case 'f':
opts->random_factor = atoi(ARGF());
break;
case 'v':
case 'V':
printf("%s %s\n", argv0, VERSION);
return 0;
@ -74,7 +95,7 @@ main(int argc, char *argv[])
printf(" Higher values == slower refresh rate.\n");
printf(" -s [speed] Change animation speed. (default: 5)\n");
printf(" Higher values == slower animation.\n");
printf(" -l [loss] Maximum heat loss for each row upward. (default: 1)\n");
printf(" -l [loss] Heat loss for each row upward. (default: 45)\n");
printf(" Higher values will lead to a smaller fire.\n");
printf(" -w [wind] Wind. Negative values, or values less than one will\n");
printf(" cause the fire to be blown west. (default: 1)\n");
@ -99,14 +120,15 @@ main(int argc, char *argv[])
} ARGEND
// initialize termbox
tb_init();
tb_init(); /* check return value */
tb_select_output_mode(output_mode);
tb_clear();
struct buffer buf;
struct tb_event e;
// initialize drawing
init(&buf);
init(&buf, opts->width, opts->height);
uint64_t ctr = 0;
@ -117,7 +139,24 @@ main(int argc, char *argv[])
// update framebuffer
dofire(&buf);
if ((ctr % opts->refresh_rate) != 0) {
/* check if we should print the image now */
if (opts->farbfeld_mode && ctr >= opts->ff_frame) {
tb_shutdown(); /* shutdown so we can output the image to stdout */
if (isatty(STDOUT_FILENO)) {
EPRINT("fire: cowardly refusing to write farbfeld image to the terminal.\n");
return 1;
}
ff_from_tbscr(opts->width, opts->height, buf.buf,
(struct tb_cell*) &truecolors, stdout);
cleanup(&buf);
return 0;
}
/* don't display or check for events if not on refresh frame */
if ((ctr % opts->refresh_rate) != 0 || opts->farbfeld_mode) {
continue;
}
@ -133,6 +172,7 @@ main(int argc, char *argv[])
// handle keypresses
// q, ctrl+c, ctrl+d => quit
/* TODO: handle resizes */
if (e.type == TB_EVENT_KEY) {
switch (e.ch) {
case 'q':
@ -153,5 +193,6 @@ main(int argc, char *argv[])
cleanup:
cleanup(&buf);
tb_shutdown();
return 0;
}

View File

@ -11,11 +11,11 @@ WARNING = -Wall -Wextra -pedantic -Wmissing-prototypes \
INC = -Isub/termbox_next/src
CC = gcc
CFLAGS = -std=c99 $(WARNING) $(INC) -fsanitize=address -Og -ggdb
LDFLAGS =
CFLAGS = -std=c99 -O0 -ggdb $(WARNING) $(INC) #-fsanitize=address
LDFLAGS = -static
TRMBOX = sub/termbox_next/bin/termbox.a
SRC = main.c draw.c
SRC = main.c draw.c ff.c colors.c terminfo.c
OBJ = $(SRC:.c=.o)
DESTDIR = /

95
terminfo.c Normal file
View File

@ -0,0 +1,95 @@
/*
* terminfo.c: get TTY/console's buffer
* height and width.
*
* TODO: test this on Windows 10.
*
* why is all Windows programming so
* damn complicated.
*
* Thanks to this SO question for Windows stuff:
* stackoverflow.com/questions/6812224/getting-terminal-size-in-c-for-windows
*
* (c) Kiëd Llaentenn and contributors
* See the LICENSE.md file for copyright
* information.
*/
#include <stdio.h>
#include <stdint.h>
#include "terminfo.h"
#if defined(_WIN32) || defined(__WIN32__)
#define WOE_IS_ME
#endif
#ifdef WOE_IS_ME
#include <windows.h>
#else
#include <sys/ioctl.h>
#include <unistd.h>
#endif
/*
* sizes to fall back to if:
* 1) stdout isn't a tty
* 2) if on Windows (temporary, only until win32
* support it added
*/
const uint16_t fallback_width = 80;
const uint16_t fallback_height = 24;
/* file descriptor to get dimensions of */
#ifdef WOE_IS_ME
CONST DWORD fd = STD_OUTPUT_HANDLE;
#else
const size_t fd = STDOUT_FILENO;
#endif
uint16_t
ttywidth(void)
{
#ifdef WOE_IS_ME
/* why on earth does _isatty return NONZERO
* if FD is a tty?! */
if (_isatty(fd))
return fallback_width;
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(
GetStdHandle(fd), &csbi
);
return csbi.srWindow.Right - csbi.srWindow.Left + 1;
#else
if (!isatty(fd))
return fallback_width;
struct winsize w;
ioctl(fd, TIOCGWINSZ, &w);
return w.ws_col;
#endif
}
uint16_t
ttyheight(void)
{
#ifdef WOE_IS_ME
if (_isatty(fd))
return fallback_height;
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(
GetStdHandle(fd), &csbi
);
return csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
#else
if (!isatty(fd))
return fallback_height;
struct winsize w;
ioctl(fd, TIOCGWINSZ, &w);
return w.ws_row;
#endif
}

18
terminfo.h Normal file
View File

@ -0,0 +1,18 @@
/*
* terminfo.h: get TTY/console's buffer
* height and width.
*
* (c) Kiëd Llaentenn and contributors
* See the LICENSE.md file for copyright
* information.
*/
#ifndef TERMINFO_H
#define TERMINFO_H
#include <stdint.h>
uint16_t ttywidth(void);
uint16_t ttyheight(void);
#endif