Files
learnFPGA/FIRMWARE/tty_graphics.h
2025-08-02 06:09:31 +03:00

174 lines
5.1 KiB
C

#ifndef TTY_GRAPHICS_H
#define TTY_GRAPHICS_H
#include <stdio.h>
#include <stdint.h>
/**
* \brief Resets default tty colors (white foreground, black background)
* \details It is useful to call this function once all graphics are finished,
* else text output might be invisible or difficult to see depending on
* current foreground and background colors.
*/
static inline void tty_graphics_reset_colors() {
printf("\033[48;5;16m" // set background color black
"\033[38;5;15m" // set foreground color white
);
}
/**
* \brief Moves the cursor position to the origin (top left).
*/
static inline void tty_graphics_home() {
printf("\033[H");
}
/**
* \brief Clears the terminal.
*/
static inline void tty_graphics_clear() {
printf("\033[2J");
}
/**
* \brief Initializes "graphics mode".
* \details resets default colors, clears the terminal and moves the
* cursor to the top-left position.
*/
static inline void tty_graphics_init() {
tty_graphics_reset_colors();
tty_graphics_home();
tty_graphics_clear();
}
/**
* \brief Terminates "graphics mode".
* \details Restores default foreground and background colors.
*/
static inline void tty_graphics_terminate() {
tty_graphics_reset_colors();
}
/**
* \brief Moves the cursor to a specific location.
*/
static inline void tty_graphics_gotoXY(int x, int y) {
printf("\033[%d;%dH",y,x);
}
/**
* \brief Draws a "pixel" (a block) at the current
* cursor position and advances the current cursor
* position.
*/
static inline void tty_graphics_draw_one_pixel(
uint8_t r, uint8_t g, uint8_t b
) {
printf("\033[48;2;%d;%d;%dm ",(int)r,(int)g,(int)b);
}
/**
* \brief Draws two "pixels" at the current
* cursor position and advances the current cursor
* position.
* \details Characters are roughly twice as high as wide.
* To generate square pixels, this function draws two pixels in
* the same character, using the special lower-half white / upper-half
* black character, and setting the background and foreground colors.
*/
static inline void tty_graphics_draw_two_pixels(
uint8_t r1, uint8_t g1, uint8_t b1,
uint8_t r2, uint8_t g2, uint8_t b2
) {
if((r2 == r1) && (g2 == g1) && (b2 == b1)) {
tty_graphics_draw_one_pixel(r1,g1,b1);
} else {
printf("\033[48;2;%d;%d;%dm",(int)r1,(int)g1,(int)b1);
printf("\033[38;2;%d;%d;%dm",(int)r2,(int)g2,(int)b2);
// https://www.w3.org/TR/xml-entity-names/025.html
// https://onlineunicodetools.com/convert-unicode-to-utf8
// https://copypastecharacter.com/
printf("\xE2\x96\x83");
}
}
/**
* \brief Moves the cursor position to the next line.
* \details Background and foreground colors are set to black.
*/
static inline void tty_graphics_newline() {
printf("\033[38;2;0;0;0m");
printf("\033[48;2;0;0;0m\n");
}
typedef void (*tty_graphics_pixelfunc)(int x, int y, uint8_t* r, uint8_t* g, uint8_t* b);
typedef void (*tty_graphics_fpixelfunc)(int x, int y, float* r, float* g, float* b);
/**
* \brief Draws an image by calling a user-specified function for each pixel.
* \param[in] width , height dimension of the image in square pixels
* \param[in] do_pixel the user function to be called for each pixel (a "shader"), that
* determines the (integer) components r,g,b of the pixel's color.
* \details Uses half-charater pixels.
*/
static inline void tty_graphics_scan(int width, int height, tty_graphics_pixelfunc do_pixel) {
uint8_t r1, g1, b1;
uint8_t r2, g2, b2;
tty_graphics_home();
for (int j = 0; j<height; j+=2) {
for (int i = 0; i<width; i++) {
do_pixel(i,j , &r1, &g1, &b1);
do_pixel(i,j+1, &r2, &g2, &b2);
tty_graphics_draw_two_pixels(r1,g1,b1,r2,g2,b2);
if(i == width-1) {
tty_graphics_newline();
}
}
}
}
/**
* brief Converts a floating point value to a byte.
* \param[in] the floating point value in [0,1]
* \return the byte, in [0,255]
* \details the input value is clamped to [0,1]
*/
static inline uint8_t tty_graphics_ftoi(float f) {
f = (f < 0.0f) ? 0.0f : f;
f = (f > 1.0f) ? 1.0f : f;
return (uint8_t)(255.0f * f);
}
/**
* \brief Draws an image by calling a user-specified function for each pixel.
* \param[in] width , height dimension of the image in square pixels
* \param[in] do_pixel the user function to be called for each pixel (a "shader"), that
* determines the (floating-point) components fr,fg,fb of the pixel's color.
* \details Uses half-charater pixels.
*/
static inline void tty_graphics_fscan(int width, int height, tty_graphics_fpixelfunc do_pixel) {
float fr1, fg1, fb1;
float fr2, fg2, fb2;
uint8_t r1, g1, b1;
uint8_t r2, g2, b2;
tty_graphics_home();
for (int j = 0; j<height; j+=2) {
for (int i = 0; i<width; i++) {
do_pixel(i,j , &fr1, &fg1, &fb1);
r1 = tty_graphics_ftoi(fr1);
g1 = tty_graphics_ftoi(fg1);
b1 = tty_graphics_ftoi(fb1);
do_pixel(i,j+1, &fr2, &fg2, &fb2);
r2 = tty_graphics_ftoi(fr2);
g2 = tty_graphics_ftoi(fg2);
b2 = tty_graphics_ftoi(fb2);
tty_graphics_draw_two_pixels(r1,g1,b1,r2,g2,b2);
if(i == width-1) {
tty_graphics_newline();
}
}
}
}
#endif