Compare commits

..

No commits in common. "v1.2.0" and "main" have entirely different histories.
v1.2.0 ... main

3 changed files with 293 additions and 87 deletions

View File

@ -1,7 +1,7 @@
# lavat
Little program that simulates a lava lamp in the terminal.
![demo](https://github.com/AngelJumbo/lavat/blob/demo/demo/3.gif?raw=true)
![demo](https://github.com/AngelJumbo/demos/blob/main/lavat/3.gif?raw=true)
## Installation
Requirements: A Unix-like system, a C compiler and make.
@ -22,41 +22,67 @@ $ paru -S lavat-git
```
Usage: lavat [OPTIONS]
OPTIONS:
-c <COLOR> Set color. Available colours: red, blue, yellow, green, cyan and magenta.
Besides those colors the default one is the normal foreground of your terminal.
-s <SPEED> Set the speed, from 1 to 5. (default 1)
-c <COLOR> Set color. Available colours: red, blue, yellow, green, cyan, magenta, white and black.
-s <SPEED> Set the speed, from 1 to 10. (default 5)
-r <RADIUS> Set the radius of the metaballs, from 1 to 10. (default: 5)
-R <RIM> Set a rim for each metaball, sizes from 1 to 5.(default: none)
This option does not work with the default color.
-b <NBALLS> Set the number of metaballs in the simulation, from 2 to 20. (default: 10)
This option does not work with the default color
If you use Kitty or Alacritty you must use it with the -k option to see the rim.
-k <COLOR> Set the color of the rim if there is one. Available colours: red, blue, yellow, green, cyan, magenta, white and black.
-b <NBALLS> Set the number of metaballs in the simulation, from 5 to 20. (default: 10)
-F <CHARS> Allows for a custom set of chars to be used
Only ascii symbols are supported for now, wide/unicode chars may appear broken.
-C Retain the entire lava inside the terminal.
It may not work well with a lot of balls or with a bigger radius than the default one.
-p <MODE> PARTY!! THREE MODES AVAILABLE (p1, p2 and p3).
-h Print help.
RUNTIME CONTROLS:
i Increase radius of the metaballs.
d Decrease radius of the metaballs.
shift i Increase rim of the metaballs.
shift d Decrease rim of the metaballs.
m Increase the number of metaballs.
l Decrease the number metaballs.
c Change the color of the metaballs.
k Change the rim color of the metaballs.
+ Increase speed.
- Decrease speed.
p TURN ON THE PARTY AND CYCLE THROUGH THE PARTY MODES (it can also turns off the party).
(Tip: Zoom out in your terminal before running the program to get a better resolution of the lava).
```
## Demo
`lavat -p3`
![demo 1](https://github.com/AngelJumbo/demos/blob/main/lavat/6.gif?raw=true)
PARTY MODE!!!
`lavat -c red -R 1`
![demo 1](https://github.com/AngelJumbo/lavat/blob/demo/demo/1.gif?raw=true)
![demo 1](https://github.com/AngelJumbo/demos/blob/main/lavat/1.gif?raw=true)
`lavat -c cyan -R 4 -b 20 -r 2`
![demo 2](https://github.com/AngelJumbo/lavat/blob/demo/demo/2.gif?raw=true)
![demo 2](https://github.com/AngelJumbo/demos/blob/main/lavat/2.gif?raw=true)
If you send more than one character to the -F option you can have 3d-ish effect.
`lavat -c blue -R2 -F @@:::::: -r10`
![demo 2](https://github.com/AngelJumbo/lavat/blob/demo/demo/4.gif?raw=true)
![demo 2](https://github.com/AngelJumbo/demos/blob/main/lavat/4.gif?raw=true)
For the Alacritty and Kitty users I know that the -R option haven't been working for you, but now you can set the color of the rim independently. Try:
`lavat -c yellow -R1 -k red`
![demo 2](https://github.com/AngelJumbo/demos/blob/main/lavat/5.gif?raw=true)
(The colors depend on your color scheme.)
## Credits
- This program is made with [Termbox2](https://github.com/termbox/termbox2).
- [Metaballs](https://en.wikipedia.org/wiki/Metaballs).
- [Lava lamp in JavaScript](https://codeguppy.com/site/tutorials/lava-lamp.html)

324
lavat.c
View File

@ -7,6 +7,9 @@
#include <time.h>
#include <unistd.h>
#define MIN_NBALLS 5
#define MAX_NBALLS 20
typedef struct {
int x;
int y;
@ -15,28 +18,40 @@ typedef struct {
} Ball;
static char *custom = NULL;
static short color = TB_DEFAULT;
static char *custom2 = NULL;
static short color = TB_WHITE;
static short color2 = TB_WHITE;
static short party = 0;
static int nballs = 10;
static short speedMult = 1;
static short rim = 0;
static short speedMult = 5;
static short rim = 1;
static short contained = 0;
static float radius = 100;
static float radiusIn = 100;
static float radius;
static int margin;
static float sumConst;
static float sumConst2;
static int maxX, maxY;
static int speed;
static Ball balls[MAX_NBALLS] = {0};
static struct tb_event event = {0};
static short colors[]={TB_WHITE, TB_RED, TB_YELLOW, TB_BLUE, TB_GREEN, TB_MAGENTA, TB_CYAN, TB_BLACK };
void init_params();
void event_handler();
int parse_options(int argc, char *argv[]);
void print_help();
short next_color(short current);
void fix_rim_color();
void set_random_colors(short level);
int main(int argc, char *argv[]) {
if (!parse_options(argc, argv))
return 0;
if (color == TB_DEFAULT && !custom)
rim = 0;
time_t t;
Ball *balls = malloc(sizeof(Ball) * nballs);
struct tb_event event = {0};
// Ball *balls = malloc(sizeof(Ball) * nballs);
srand((unsigned)time(&t));
@ -44,28 +59,7 @@ int main(int argc, char *argv[]) {
tb_hide_cursor();
int maxX = tb_width();
int maxY = tb_height() * 2;
int speed = (((1 / (float)(maxX + maxY)) * 5000000) + 50000) / speedMult;
radius = (radius * radius + (float)(maxX * maxY)) / 15000;
int margin = contained ? radius * 10 : 0;
float sumConst = 0.0225;
float sumConst2 = sumConst * (1 + (float)(0.25 * rim));
char *custom2 = custom;
if (custom && strlen(custom) > 1 && rim) {
custom2 = custom + 1;
}
for (int i = 0; i < nballs; i++) {
balls[i].x = rand() % (maxX - 2 * margin) + margin;
balls[i].y = rand() % (maxY - 2 * margin) + margin;
balls[i].dx = (rand() % 2 == 0) ? -1 : 1;
balls[i].dy = (rand() % 2 == 0) ? -1 : 1;
}
init_params();
while (1) {
@ -103,12 +97,12 @@ int main(int argc, char *argv[]) {
if (!custom) {
if (sum[0] > sumConst) {
if (sum[1] > sumConst) {
tb_printf(i, j, color | TB_BOLD, 0, "");
tb_printf(i, j, color2, 0, "");
} else {
tb_printf(i, j, color | TB_BOLD, 0, "");
tb_printf(i, j, color2, 0, "");
}
} else if (sum[1] > sumConst) {
tb_printf(i, j, color | TB_BOLD, 0, "");
tb_printf(i, j, color2, 0, "");
}
if (rim) {
@ -116,15 +110,15 @@ int main(int argc, char *argv[]) {
if (sum[1] > sumConst2) {
tb_printf(i, j, color, 0, "");
} else {
tb_printf(i, j, color | TB_BOLD, color, "");
tb_printf(i, j, color2, color, "");
}
} else if (sum[1] > sumConst2) {
tb_printf(i, j, color | TB_BOLD, color, "");
tb_printf(i, j, color2, color, "");
}
}
} else {
if (sum[0] > sumConst) {
tb_printf(i, j, color | TB_BOLD, 0, custom2);
tb_printf(i, j, color2, 0, custom2);
}
if (rim) {
@ -135,49 +129,208 @@ int main(int argc, char *argv[]) {
}
}
}
if (party>0){
set_random_colors(party);
}
tb_present();
usleep(speed);
tb_clear();
tb_peek_event(&event, 10);
if (event.key == TB_KEY_CTRL_C || event.key == TB_KEY_ESC ||
event.ch == 'q' || event.ch == 'Q')
break;
event_handler();
}
tb_shutdown();
free(balls);
// free(balls);
}
void event_handler() {
if (event.type == TB_EVENT_RESIZE) {
do
tb_peek_event(&event, 10);
while (event.type == TB_EVENT_RESIZE);
init_params();
} else if (event.type == TB_EVENT_KEY) {
if (event.key == TB_KEY_CTRL_C || event.key == TB_KEY_ESC) {
tb_shutdown();
exit(0);
}
switch (event.ch) {
case '-':
case '_':
if (speedMult < 10) {
speedMult++;
speed = (((1 / (float)(maxX + maxY)) * 1000000) + 10000) * speedMult;
}
break;
case '+':
case '=':
if (speedMult > 1) {
speedMult--;
speed = (((1 / (float)(maxX + maxY)) * 1000000) + 10000) * speedMult;
}
break;
case 'm':
case 'M':
if (nballs + 1 <= MAX_NBALLS) {
nballs++;
}
break;
case 'l':
case 'L':
if (nballs - 1 >= MIN_NBALLS) {
nballs--;
}
break;
case 'i':
if (radiusIn + 10 <= 150) {
radiusIn += 10;
radius = (radiusIn * radiusIn + (float)(maxX * maxY)) / 15000;
margin = contained ? radius * 10 : 0;
}
break;
case 'd':
if (radiusIn - 10 >= 50) {
radiusIn -= 10;
radius = (radiusIn * radiusIn + (float)(maxX * maxY)) / 15000;
margin = contained ? radius * 10 : 0;
}
break;
case 'I':
if (color != TB_WHITE || custom)
if (rim + 1 <= 5) {
rim++;
sumConst2 = sumConst * (1 + (float)(0.25 * rim));
}
break;
case 'D':
if (color != TB_WHITE || custom)
if (rim - 1 >= 0) {
rim--;
sumConst2 = sumConst * (1 + (float)(0.25 * rim));
}
break;
case 'c':
color = next_color(color);
fix_rim_color();
break;
case 'k':
color2 = next_color(color2);
fix_rim_color();
break;
case 'p':
party = (party+1)%4;
break;
case 'q':
case 'Q':
tb_shutdown();
exit(0);
break;
}
}
}
void init_params() {
maxX = tb_width();
maxY = tb_height() * 2;
speedMult = 11 - speedMult;
speed = (((1 / (float)(maxX + maxY)) * 1000000) + 10000) * speedMult;
radius = (radiusIn * radiusIn + (float)(maxX * maxY)) / 15000;
margin = contained ? radius * 10 : 0;
sumConst = 0.0225;
sumConst2 = sumConst * (1 + (float)(0.25 * rim));
custom2 = custom;
if (color2 == TB_WHITE || !rim)
color2 = color | TB_BOLD;
if (custom && strlen(custom) > 1 && rim) {
custom2 = custom + 1;
}
for (int i = 0; i < MAX_NBALLS; i++) {
balls[i].x = rand() % (maxX - 2 * margin) + margin;
balls[i].y = rand() % (maxY - 2 * margin) + margin;
balls[i].dx = (rand() % 2 == 0) ? -1 : 1;
balls[i].dy = (rand() % 2 == 0) ? -1 : 1;
}
}
short next_color(short current){
for(int i = 0; i<8; i++){
if((current == colors[i])||(current == (colors[i] | TB_BOLD ))){
return colors[(i+1)%8];
}
}
return colors[0];
}
void fix_rim_color(){
if(color2 == color){
color2 = color2 | TB_BOLD;
}
}
void set_random_colors( short level){
if(level==1 || level==3) color = colors[ rand() % 7];
if(level==2 || level==3) color2 = colors[ rand() % 7];
fix_rim_color();
}
int set_color(short *var, char *optarg) {
if (strcmp(optarg, "red") == 0) {
*var = TB_RED;
} else if (strcmp(optarg, "yellow") == 0) {
*var = TB_YELLOW;
} else if (strcmp(optarg, "blue") == 0) {
*var = TB_BLUE;
} else if (strcmp(optarg, "green") == 0) {
*var = TB_GREEN;
} else if (strcmp(optarg, "magenta") == 0) {
*var = TB_MAGENTA;
} else if (strcmp(optarg, "cyan") == 0) {
*var = TB_CYAN;
} else if (strcmp(optarg, "black") == 0) {
*var = TB_BLACK;
} else if (strcmp(optarg, "white") == 0) {
*var = TB_WHITE;
} else {
printf("Unknown color: %s\n", optarg);
return 0;
}
return 1;
}
int parse_options(int argc, char *argv[]) {
if (argc == 1)
return 1;
int c;
while ((c = getopt(argc, argv, ":c:s:r:R:b:F:Ch")) != -1) {
while ((c = getopt(argc, argv, ":c:k:s:r:R:b:F:Cp:h")) != -1) {
switch (c) {
case 'c':
if (strcmp(optarg, "red") == 0) {
color = TB_RED;
} else if (strcmp(optarg, "yellow") == 0) {
color = TB_YELLOW;
} else if (strcmp(optarg, "blue") == 0) {
color = TB_BLUE;
} else if (strcmp(optarg, "green") == 0) {
color = TB_GREEN;
} else if (strcmp(optarg, "magenta") == 0) {
color = TB_MAGENTA;
} else if (strcmp(optarg, "cyan") == 0) {
color = TB_CYAN;
} else {
printf("Unknown color\n");
if (!set_color(&color, optarg))
return 0;
break;
case 'k':
if (!set_color(&color2, optarg))
return 0;
}
break;
case 's':
speedMult = atoi(optarg);
if (speedMult > 5 || speedMult <= 0) {
printf("Invalid speed, only values between 1 and 5 are allowed\n");
if (speedMult > 10 || speedMult <= 0) {
printf("Invalid speed, only values between 1 and 10 are allowed\n");
return 0;
}
break;
@ -189,8 +342,8 @@ int parse_options(int argc, char *argv[]) {
}
break;
case 'r':
radius = 50 + atoi(optarg) * 10;
if (radius > 150 || radius < 50) {
radiusIn = 50 + atoi(optarg) * 10;
if (radiusIn > 150 || radiusIn < 50) {
printf("Invalid radius, only values between 1 and 10 are allowed\n");
return 0;
}
@ -198,10 +351,11 @@ int parse_options(int argc, char *argv[]) {
case 'b':
nballs = atoi(optarg);
if (nballs > 20 || nballs < 2) {
if (nballs > MAX_NBALLS || nballs < MIN_NBALLS) {
printf("Invalid number of metaballs, only values between 2 and 20 are"
"allowed\n");
printf("Invalid number of metaballs, only values between %i and %i are"
"allowed\n",
MIN_NBALLS, MAX_NBALLS);
return 0;
}
break;
@ -211,11 +365,18 @@ int parse_options(int argc, char *argv[]) {
case 'C':
contained = 1;
break;
case 'p':
party = atoi(optarg);
if (party < 0 || party > 3 ) {
printf("Invalid party mode, only values between 1 and 3 are allowed\n");
return 0;
}
break;
case 'h':
print_help();
return 0;
break;
case ':': /* -f or -o without operand */
case ':':
fprintf(stderr, "Option -%c requires an operand\n", optopt);
return 0;
break;
@ -232,25 +393,42 @@ void print_help() {
"Usage: lavat [OPTIONS]\n"
"OPTIONS:\n"
" -c <COLOR> Set color. Available colours: red, blue, yellow, "
"green, cyan and magenta. \n"
" Besides those colors the default one is the normal"
" foreground of your terminal.\n"
" -s <SPEED> Set the speed, from 1 to 5. (default 1)\n"
"green, cyan, magenta, white and black. \n"
" -s <SPEED> Set the speed, from 1 to 10. (default 5)\n"
" -r <RADIUS> Set the radius of the metaballs, from 1 to 10. "
"(default: 5)\n"
" -R <RIM> Set a rim for each metaball, sizes from 1 to 5."
"(default: none)\n"
" This option does not work with the default "
"color.\n"
"color\n"
" If you use Kitty or Alacritty you must use it "
"with the -k option to see the rim.\n"
" -k <COLOR> Set the color of the rim if there is one."
" Available colours: red, blue, yellow, green, cyan, magenta, white and black. \n"
" -b <NBALLS> Set the number of metaballs in the simulation, "
"from 2 to 20. (default: 10)\n"
"from %i to %i. (default: 10)\n"
" -F <CHARS> Allows for a custom set of chars to be used\n"
" Only ascii symbols are supported for now, "
"wide/unicode chars may appear broken.\n"
" -C Retain the entire lava inside the terminal.\n"
" It may not work well with a lot of balls or with"
" a bigger radius than the default one.\n"
" -p <MODE> PARTY!! THREE MODES AVAILABLE (p1, p2 and p3).\n"
" -h Print help.\n"
"RUNTIME CONTROLS:\n"
" i Increase radius of the metaballs.\n"
" d Decrease radius of the metaballs.\n"
" shift i Increase rim of the metaballs.\n"
" shift d Decrease rim of the metaballs.\n"
" m Increase the number of metaballs.\n"
" l Decrease the number metaballs.\n"
" c Change the color of the metaballs.\n"
" k Change the rim color of the metaballs.\n"
" + Increase speed.\n"
" - Decrease speed.\n"
" p TURN ON THE PARTY AND CYCLE THROUGH THE PARTY MODES "
"(it can also turns off the party).\n"
"(Tip: Zoom out in your terminal before running the program to get a "
"better resolution of the lava).\n");
"better resolution of the lava).\n",
MIN_NBALLS, MAX_NBALLS);
}

View File

@ -9,8 +9,10 @@ clean:
.PHONY: install
install: lavat
install -D lavat $(DESTDIR)$(PREFIX)/bin/lavat
mkdir -p $(PREFIX)/bin
install lavat $(PREFIX)/bin/lavat
.PHONY: uninstall
uninstall:
$(RM) $(PREFIX)/bin/lavat
.PHONY: unistall
unistall:
$(RM) $(DESTDIR)$(PREFIX)/bin/lavat