Add SIGINT handling to gracefully exit
This commit is contained in:
91
donut.c
91
donut.c
@@ -1,4 +1,5 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -20,6 +21,10 @@
|
|||||||
#define STEP_ALPHA 0.016028534
|
#define STEP_ALPHA 0.016028534
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
volatile sig_atomic_t keep_running = 1;
|
||||||
|
|
||||||
|
void sigint_handler(int sig) { keep_running = 0; }
|
||||||
|
|
||||||
// Clears the terminal
|
// Clears the terminal
|
||||||
void clear_terminal() {
|
void clear_terminal() {
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
@@ -34,43 +39,54 @@ void clear_terminal() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Frees up the heap
|
||||||
|
void cleanup(char **buffer, size_t term_size) {
|
||||||
|
if (buffer) {
|
||||||
|
for (size_t i = 0; i < term_size; ++i) {
|
||||||
|
free(buffer[i]);
|
||||||
|
}
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
clear_terminal();
|
||||||
|
}
|
||||||
|
|
||||||
// Function allocates memory for the frame buffer
|
// Function allocates memory for the frame buffer
|
||||||
char **allocate_memory(int term_size) {
|
char **allocate_memory(size_t term_size) {
|
||||||
char **array = malloc(term_size * sizeof(char *));
|
char **array = malloc(term_size * sizeof(char *));
|
||||||
for (int i = 0; i < term_size; ++i)
|
for (size_t i = 0; i < term_size; ++i)
|
||||||
array[i] = malloc(term_size * sizeof(char));
|
array[i] = malloc(term_size * sizeof(char));
|
||||||
|
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function gets the size of the terminal
|
// Function gets the size of the terminal
|
||||||
int terminal_size() {
|
size_t terminal_size() {
|
||||||
int term_size;
|
size_t term_size;
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
CONSOLE_SCREEN_BUFFER_INFO c;
|
CONSOLE_SCREEN_BUFFER_INFO c;
|
||||||
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &c);
|
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &c);
|
||||||
int row = (int)(c.srWindow.Bottom - c.srWindow.Top + 1);
|
size_t row = (size_t)(c.srWindow.Bottom - c.srWindow.Top + 1);
|
||||||
int col = (int)(c.srWindow.Right - c.srWindow.Left + 1);
|
size_t col = (size_t)(c.srWindow.Right - c.srWindow.Left + 1);
|
||||||
term_size = row < col ? row : col;
|
term_size = row < col ? row : col;
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
struct winsize w;
|
struct winsize w;
|
||||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
||||||
term_size = w.ws_row < w.ws_col ? (int)w.ws_row : (int)w.ws_col;
|
term_size = w.ws_row < w.ws_col ? (size_t)w.ws_row : (size_t)w.ws_col;
|
||||||
#endif
|
#endif
|
||||||
return term_size;
|
return term_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function dumps the frame into the terminal
|
// Function dumps the frame into the terminal
|
||||||
void dump_frame(char **buffer, int term_size) {
|
void dump_frame(char **buffer, size_t term_size) {
|
||||||
for (int i = 0; i < term_size; ++i) {
|
for (size_t i = 0; i < term_size; ++i) {
|
||||||
for (int j = 0; j < term_size; ++j)
|
for (size_t j = 0; j < term_size; ++j)
|
||||||
putchar(buffer[i][j]);
|
putchar(buffer[i][j]);
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function builds the frame and returns the frame buffer
|
// Function builds the frame and returns the frame buffer
|
||||||
char **build_frame(char **buffer, int term_size, int i, int scrn_dist) {
|
char **build_frame(char **buffer, size_t term_size, size_t i, size_t scrn_dist) {
|
||||||
float x = i * STEP_ROT_X; // Rotational speed around the x axis
|
float x = i * STEP_ROT_X; // Rotational speed around the x axis
|
||||||
float y = i * STEP_ROT_Y; // Rotational speed around the y axis
|
float y = i * STEP_ROT_Y; // Rotational speed around the y axis
|
||||||
|
|
||||||
@@ -80,13 +96,13 @@ char **build_frame(char **buffer, int term_size, int i, int scrn_dist) {
|
|||||||
float z_buffer[term_size][term_size]; // Declaring buffer for storing z coordinates
|
float z_buffer[term_size][term_size]; // Declaring buffer for storing z coordinates
|
||||||
|
|
||||||
// Initializing frame buffer and z buffer
|
// Initializing frame buffer and z buffer
|
||||||
for (int i = 0; i < term_size; ++i)
|
for (size_t i = 0; i < term_size; ++i)
|
||||||
for (int j = 0; j < term_size; ++j) {
|
for (size_t j = 0; j < term_size; ++j) {
|
||||||
buffer[i][j] = ' ';
|
buffer[i][j] = ' ';
|
||||||
z_buffer[i][j] = 0;
|
z_buffer[i][j] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop uses theta to revolve a point around the center of the circle
|
// Loop uses theta to revolve a posize_t around the center of the circle
|
||||||
// 6.283186 = 2 * Pi = 360°
|
// 6.283186 = 2 * Pi = 360°
|
||||||
for (float theta = 0; theta < 6.283186; theta += STEP_THETA) {
|
for (float theta = 0; theta < 6.283186; theta += STEP_THETA) {
|
||||||
// Precomputing sines and cosines of theta
|
// Precomputing sines and cosines of theta
|
||||||
@@ -112,21 +128,22 @@ char **build_frame(char **buffer, int term_size, int i, int scrn_dist) {
|
|||||||
float z_inv = 1 / z;
|
float z_inv = 1 / z;
|
||||||
|
|
||||||
// Calculating x and y coordinates of the 2D projection
|
// Calculating x and y coordinates of the 2D projection
|
||||||
int x_proj = (float)term_size / 2 + scrn_dist * z_inv * x;
|
size_t x_proj = (float)term_size / 2 + scrn_dist * z_inv * x;
|
||||||
int y_proj = (float)term_size / 2 - scrn_dist * z_inv * y;
|
size_t y_proj = (float)term_size / 2 - scrn_dist * z_inv * y;
|
||||||
|
|
||||||
// Calculating luminous intensity
|
// Calculating luminous intensity
|
||||||
float lumi_int = cos_alpha * cos_theta * sin_y - cos_x * cos_theta * sin_alpha - sin_x * sin_theta + cos_y * (cos_x * sin_theta - cos_theta * sin_x * sin_alpha);
|
float lumi_size_t = cos_alpha * cos_theta * sin_y - cos_x * cos_theta * sin_alpha - sin_x * sin_theta +
|
||||||
|
cos_y * (cos_x * sin_theta - cos_theta * sin_x * sin_alpha);
|
||||||
|
|
||||||
/* Checking if surface is pointing away from the point of view
|
/* Checking if surface is pointing away from the posize_t of view
|
||||||
* Also checking if the point is closer than any other point
|
* Also checking if the posize_t is closer than any other point
|
||||||
* previously plotted
|
* previously plotted
|
||||||
*/
|
*/
|
||||||
if (lumi_int > 0 && z_inv > z_buffer[x_proj][y_proj]) {
|
if (lumi_size_t > 0 && z_inv > z_buffer[x_proj][y_proj]) {
|
||||||
z_buffer[x_proj][y_proj] = z_inv;
|
z_buffer[x_proj][y_proj] = z_inv;
|
||||||
|
|
||||||
// Bringing the value of luminance between 0 to 11
|
// Bringing the value of luminance between 0 to 11
|
||||||
int lumi_idx = lumi_int * 8;
|
size_t lumi_idx = lumi_size_t * 8;
|
||||||
|
|
||||||
/* Storing an appropriate character that represents the correct
|
/* Storing an appropriate character that represents the correct
|
||||||
* amount of luminance
|
* amount of luminance
|
||||||
@@ -155,46 +172,48 @@ Examples:\n\
|
|||||||
prog_name, prog_name, prog_name);
|
prog_name, prog_name, prog_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void runner(bool dynamic, bool limit, int frames) {
|
void runner(bool dynamic, bool limit, size_t frames) {
|
||||||
|
// Set up the signal handler
|
||||||
|
struct sigaction sa;
|
||||||
|
sa.sa_handler = sigint_handler;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = 0;
|
||||||
|
sigaction(SIGINT, &sa, NULL);
|
||||||
|
|
||||||
// Allocating memory to the frame buffer according to terminal size
|
// Allocating memory to the frame buffer according to terminal size
|
||||||
int term_size = terminal_size();
|
size_t term_size = terminal_size();
|
||||||
int scrn_dist = term_size * 5 * 3 / (8 * (1 + 2));
|
size_t scrn_dist = term_size * 5 * 3 / (8 * (1 + 2));
|
||||||
char **buffer = allocate_memory(term_size);
|
char **buffer = allocate_memory(term_size);
|
||||||
|
|
||||||
// Loop rotates the donut around both the axes
|
// Loop rotates the donut around both the axes
|
||||||
for (int i = 0; !limit || i < frames; ++i) {
|
for (size_t i = 0; (keep_running) && (!limit || i < frames); ++i) {
|
||||||
if (dynamic && i % 32 == 0 && term_size - terminal_size() != 0) {
|
if (dynamic && i % 32 == 0 && term_size - terminal_size() != 0) {
|
||||||
// Frees the old frame buffer
|
// Frees the old frame buffer
|
||||||
for (int i = 0; i < term_size; ++i) {
|
cleanup(buffer, term_size);
|
||||||
free(buffer[i]);
|
|
||||||
}
|
|
||||||
free(buffer);
|
|
||||||
|
|
||||||
// Reallocates the frame buffer as per new terminal size
|
// Reallocates the frame buffer as per new terminal size
|
||||||
term_size = terminal_size();
|
term_size = terminal_size();
|
||||||
buffer = allocate_memory(term_size);
|
buffer = allocate_memory(term_size);
|
||||||
|
|
||||||
// Calculates screen distance based on terminal size
|
// Calculates screen distance based on terminal size
|
||||||
scrn_dist = term_size * 5 * 3 / (8 * (1 + 2));
|
scrn_dist = term_size * 5 * 3 / (8 * (1 + 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Building the frame
|
// Building the frame
|
||||||
buffer = build_frame(buffer, term_size, i, scrn_dist);
|
buffer = build_frame(buffer, term_size, i, scrn_dist);
|
||||||
|
|
||||||
// Dumping the frame into the terminal
|
// Dumping the frame into the terminal
|
||||||
dump_frame(buffer, term_size);
|
dump_frame(buffer, term_size);
|
||||||
|
|
||||||
// Clearing the frame from the terminal
|
// Clearing the frame from the terminal
|
||||||
clear_terminal();
|
clear_terminal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean up the heap
|
||||||
|
cleanup(buffer, term_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
bool limit = false;
|
bool limit = false;
|
||||||
bool dynamic = false;
|
bool dynamic = false;
|
||||||
int frames = 0;
|
size_t frames = 0;
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
for (int i = 1; i < argc; ++i) {
|
for (size_t i = 1; i < argc; ++i) {
|
||||||
if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
|
if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
|
||||||
help(argv[0]);
|
help(argv[0]);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|||||||
Reference in New Issue
Block a user