174 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			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
 |