commit b64dc431124861b691be132c1d5e2867506aa884 Author: overflowerror Date: Mon May 10 19:17:33 2021 +0200 frist commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8dd95d5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/obj/** +gravity +bars +font diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8ce67b1 --- /dev/null +++ b/Makefile @@ -0,0 +1,41 @@ +CC = gcc +CFLAGS = -std=c99 -Wall -D_POSIX_C_SOURCE=201112L -D_XOPEN_SOURCE=500 -D_GNU_SOURCE -static -g +LD = gcc +LDFLAGS = -lm + +COMMON = obj/common/graphics.o\ + obj/common/compat.o\ + obj/common/utils.o +DEPS = $(OBJS:%.o=%.d) + +all: bars gravity font + +bars: obj/bars.o $(COMMON) + $(LD) -o $@ $^ $(LDFLAGS) + +gravity: obj/gravity.o $(COMMON) + $(LD) -o $@ $^ $(LDFLAGS) + +font: obj/font.o $(COMMON) + $(LD) -o $@ $^ $(LDFLAGS) + +test: obj/test.o $(COMMON) + $(LD) -o $@ $^ $(LDFLAGS) + +-include $(DEPS) + +obj/%.o: src/%.c obj + $(CC) $(CFLAGS) -MMD -c -o $@ $< + +obj: + @mkdir -p obj/common/ + +clean: + @echo "Cleaning up..." + @rm -f obj/*.o + @rm -f obj/*.d + @rm -f obj/*/*.o + @rm -f obj/*/*.d + @rm -f bars + @rm -f gravity + @rm -f font diff --git a/obj/common/.gitkeep b/obj/common/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/bars.c b/src/bars.c new file mode 100644 index 0000000..35541ce --- /dev/null +++ b/src/bars.c @@ -0,0 +1,136 @@ +#include +#include +#include +#include + +#include "common/compat.h" +#include "common/graphics.h" +#include "common/utils.h" + +#define WIDTH (40) +#define NUMBER_OF_CHARACTERS (8) +#define NUMBER_OF_BLOCKS (20) +#define SLEEP_TIME (50000l) + + +#define NO_CHARACTER (-1) + +wchar_t chars[] = { + 0x258F, + 0x258E, + 0x258D, + 0x258C, + 0x258B, + 0x258A, + 0x2589, + 0x2588 +}; + +enum direction { + left, right +}; + +struct block { + enum direction direction; + int character; + float position; + float speed; +}; + +struct buffer { + int characters[WIDTH]; +}; + +struct block randomBlock() { + return (struct block){ + direction: (randomInt() % 2) ? left : right, + character: (randomInt() % NUMBER_OF_CHARACTERS), + position: (randomInt() % WIDTH), + speed: 1 + }; +} + + +void printBuffer(struct buffer* buffer) { + for (int i = 0; i < WIDTH; i++) { + if (buffer->characters[i] < 0) { + cprintf(" "); + } else { + cprintf("%lc", chars[buffer->characters[i]]); + } + } +} + +void clearBuffer(struct buffer* buffer) { + for (int i = 0; i < WIDTH; i++) { + buffer->characters[i] = -1; + } +} + +void applyBlockToBuffer(struct block* block, struct buffer* buffer) { + if (buffer->characters[(int) block->position] <= block->character) + buffer->characters[(int) block->position] = block->character; +} + +void tickBlock(struct block* block) { + if (block->direction == right) { + block->position += block->speed; + if (block->position >= WIDTH - 1) { + block->position = WIDTH - 1; + block->direction = left; + } + } else { + block->position -= block->speed; + if (block->position <= 0) { + block->position = 0; + block->direction = right; + } + } +} + +void doTick(struct block blocks[]) { + struct buffer buffer; + clearBuffer(&buffer); + + moveCursorRelative(- (WIDTH + 2), 0); + eraseLine(); + + for (int i = 0; i < NUMBER_OF_BLOCKS; i++) { + tickBlock(&(blocks[i])); + + applyBlockToBuffer(&(blocks[i]), &buffer); + } + + cprintf("["); + printBuffer(&buffer); + cprintf("]"); +} + +void makeBlocks(struct block blocks[]) { + for (int i = 0; i < NUMBER_OF_BLOCKS; i++) { + blocks[i] = randomBlock(); + } +} + +int main() { + setlocale(LC_CTYPE, ""); + + enable_compat_mode(PRINT_WCHAR); + + initRandom(); + + hideCursor(); + + struct block blocks[NUMBER_OF_BLOCKS]; + + makeBlocks(blocks); + + while (true) { + doTick(blocks); + fflush(stdout); + usleep(SLEEP_TIME); + } + + cprintf("\n"); + +} diff --git a/src/common/compat.c b/src/common/compat.c new file mode 100644 index 0000000..81e1b15 --- /dev/null +++ b/src/common/compat.c @@ -0,0 +1,42 @@ +#include "compat.h" + +#include +#include +#include +#include + +int compat_mode = 0; + +void enable_compat_mode(int mode) { + compat_mode |= mode; +} + +void disable_compat_mode(int mode) { + compat_mode &= ~(mode); +} + +int cfprintf(FILE* file, char* format, ...) { + va_list(args); + + int result; + + va_start(args, format); + if (compat_mode & PRINT_WCHAR) { + size_t size = mbstowcs(NULL, format, 0) + 1; + wchar_t* buffer = malloc(size * sizeof(wchar_t)); + if (buffer == NULL) { + return -1; + } + + mbstowcs(buffer, format, size); + + result = vfwprintf(file, buffer, args); + + free(buffer); + } else { + result = vfprintf(file, format, args); + } + va_end(args); + + return result; +} diff --git a/src/common/compat.h b/src/common/compat.h new file mode 100644 index 0000000..4a30504 --- /dev/null +++ b/src/common/compat.h @@ -0,0 +1,20 @@ +#ifndef COMPAT_H +#define COMPAT_H + +#include + +#define PRINT_WCHAR (1<<0) + +void enable_compat_mode(int); +void disable_compat_mode(int); + +int cfprintf(FILE* file, char* format, ...); + +#define cprintf(...) cfprintf(stdout, __VA_ARGS__) + +#ifdef SUBSTITUDE_PRINTS + #define printf(...) cprintf(__VA_ARGS__) + #define fprintf(...) cfprintf(__VA_ARGS__) +#endif + +#endif diff --git a/src/common/graphics.c b/src/common/graphics.c new file mode 100644 index 0000000..acef9a2 --- /dev/null +++ b/src/common/graphics.c @@ -0,0 +1,67 @@ +#include "graphics.h" + +#include "compat.h" + +#include +#include +#include + +void moveCursorRelative(int x, int y) { + if (x < 0) { + cprintf("\033[%dD", -x); + } else if (x > 0) { + cprintf("\033[%dC", x); + } + if (y < 0) { + cprintf("\033[%dA", -x); + } else if (y > 0) { + cprintf("\033[%dB", x); + } +} + +void moveCursorAbsolute(int x, int y) { + cprintf("\033[%d;%dH", y + 1, x + 1); +} + +void eraseLine() { + cprintf("\033[K"); +} + +void eraseScreen() { + cprintf("\033[2J"); +} + +void hideCursor() { + cprintf("\033[?25l"); +} + +void showCursor() { + cprintf("\033[?25h"); +} + +struct dimensions getScreenSize() { + moveCursorAbsolute(999, 999); + cprintf("\033[6n"); + + char buffer[12]; + int i = 0; + while (true) { + cprintf("--\n"); + int m = fread(&(buffer[i++]), 1, 1, stdin); + cprintf("%d\n", m); + cprintf("%c\n", buffer[i - 1]); + if (buffer[i - 1] == 'R') + break; + } + buffer[i] = '\0'; + + struct dimensions d; + + char* endptr = &(buffer[2]); + int tmp = strtol(endptr, &endptr, 10); + d.width = tmp; + tmp = strtol(endptr, &endptr, 10); + d.height = tmp; + + return d; +} diff --git a/src/common/graphics.h b/src/common/graphics.h new file mode 100644 index 0000000..cb89763 --- /dev/null +++ b/src/common/graphics.h @@ -0,0 +1,19 @@ +#ifndef GRAPHICS_H +#define GRAPHICS_H + +struct dimensions { + int width; + int height; +}; + +void moveCursorRelative(int x, int y); +void moveCursorAbsolute(int x, int y); +void eraseLine(); +void eraseScreen(); + +void hideCursor(); +void showCursor(); + +struct dimensions getScreenSize(); + +#endif diff --git a/src/common/utils.c b/src/common/utils.c new file mode 100644 index 0000000..2669d5a --- /dev/null +++ b/src/common/utils.c @@ -0,0 +1,16 @@ +#include "utils.h" + +#include +#include + +void initRandom() { + srandom(time(NULL)); +} + +int randomInt() { + return random(); +} + +float randomFloat() { + return random() * 1.0 / RAND_MAX; +} diff --git a/src/common/utils.h b/src/common/utils.h new file mode 100644 index 0000000..5f72223 --- /dev/null +++ b/src/common/utils.h @@ -0,0 +1,19 @@ +#ifndef UTILS_H +#define UTILS_H + +#include "compat.h" +#include +#include + +void initRandom(); + +int randomInt(); +float randomFloat(); + +#ifndef EXIT_PANIC + #define EXIT_PANIC (1) +#endif + +#define panic(format, ...) { cfprintf(stderr, "panic: " format "\n", #__VA_ARGS__); exit(EXIT_PANIC ); } + +#endif diff --git a/src/font.c b/src/font.c new file mode 100644 index 0000000..373bf61 --- /dev/null +++ b/src/font.c @@ -0,0 +1,545 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/graphics.h" +#include "common/utils.h" + +#define SUBSTITUDE_PRINTS +#include "common/compat.h" + +#define MAX_VELOCITY (3) + +#define ANIMATION_SLEEP_TIME (100000) +#define SCATTER_SLEEP_TIME (2000000) + +#define OFFSET_X (-50) +#define OFFSET_Y (-15) + +#define SCREEN_WIDTH (100) +#define SCREEN_HEIGHT (30) + +#define ASPECT_RATIO (3.0/2.0) +#define FACTOR_X (1.0) +#define FACTOR_Y (FACTOR_X * ASPECT_RATIO) + +#define BRAILLE_PREFIX (0x2800) +#define BRAILLE_TOP_LEFT (0x01) +#define BRAILLE_MIDDLE_LEFT (0x02) +#define BRAILLE_BOTTOM_LEFT (0x04) +#define BRAILLE_TOP_RIGHT (0x08) +#define BRAILLE_MIDDLE_RIGHT (0x10) +#define BRAILLE_BOTTOM_RIGHT (0x20) + +struct vector { + float x; + float y; +}; + +struct point { + struct vector position; + struct vector source; + struct vector target; +}; + +float distance(struct vector a, struct vector b) { + float dx = b.x - a.x; + float dy = b.y - a.y; + + return sqrt((dx * dx) + (dy * dy)); +} + +struct vector direction(struct vector a, struct vector b) { + float dx = b.x - a.x; + float dy = b.y - a.y; + + float r = sqrt((dx * dx) + (dy * dy)); + + return (struct vector) { + x: dx / r, + y: dy / r + }; + +} + +void zeroVector(struct vector* vector) { + vector->x = 0; + vector->y = 0; +} + +struct patternAtom { + int x; // 0-1 + int y; // 0-2 +}; + +wchar_t getPattern(struct patternAtom atoms[], int number) { + if (number == 0) { + return L' '; + } + + wchar_t result = BRAILLE_PREFIX; + + for (int i = 0; i < number; i++) { + if (atoms[i].x == 0) { + if (atoms[i].y == 0) { + result |= BRAILLE_TOP_LEFT; + } else if (atoms[i].y == 1) { + result |= BRAILLE_MIDDLE_LEFT; + } else { + result |= BRAILLE_BOTTOM_LEFT; + } + } else { + if (atoms[i].y == 0) { + result |= BRAILLE_TOP_RIGHT; + } else if (atoms[i].y == 1) { + result |= BRAILLE_MIDDLE_RIGHT; + } else { + result |= BRAILLE_BOTTOM_RIGHT; + } + } + } + + return result; +} + +struct point randomPoint() { + struct point p = { + source: { + x: randomFloat() * 20 - 10, + y: randomFloat() * 20 - 10 + }, + target: { + x: randomFloat() * 20 - 10, + y: randomFloat() * 20 - 10 + } + }; + + p.position = p.source; + + return p; +} + +void initPoints(struct point points[], int number) { + for (int i = 0; i < number; i++) { + points[i] = randomPoint(); + } +} + +float velocity(float x) { + if (x > 1.0) { + return MAX_VELOCITY * (-0.2)*(x - 1); + } else if (x > 0.5) { + return MAX_VELOCITY * (-2)*(x - 1); + } else { + return MAX_VELOCITY * 2*x + 0.2; + } +} + +bool tickPoint(struct point* p) { + struct vector d = direction(p->position, p->target); + + float x = distance(p->source, p->target); + if (fabs(x) < 0.01) { + x = 1.0; + } else { + x = distance(p->source, p->position) / x; + } + + float v = fabs(velocity(x)); + + if (fabs(1 - x) < 0.01) { + p->position = p->target; + return true; + } else { + p->position.x += d.x * v; + p->position.y += d.y * v; + return false; + } +} + +bool tickPoints(struct point points[], int number) { + bool finished = true; + + for (int i = 0; i < number; i++) { + if (!tickPoint(&(points[i]))) + finished = false; + } + + return finished; +} + +struct screenCell { + struct patternAtom* atoms; + int number; +}; + +void displayPoints(struct point points[], int number) { + struct screenCell screen[SCREEN_WIDTH][SCREEN_HEIGHT]; + for (int x = 0; x < SCREEN_WIDTH; x++) { + for (int y = 0; y < SCREEN_HEIGHT; y++) { + screen[x][y].atoms = NULL; + screen[x][y].number = 0; + } + } + + for (int i = 0; i < number; i++) { + struct point p = points[i]; + float x = p.position.x * FACTOR_X - OFFSET_X; + float y = p.position.y * FACTOR_Y - OFFSET_Y; + + int screenX = floor(x); + int screenY = floor(y); + + if (screenX < 0 || screenX >= SCREEN_WIDTH) { + continue; + } + if (screenY < 0 || screenY >= SCREEN_HEIGHT) { + continue; + } + + struct patternAtom atom = { + x: floor((x - screenX) * 2), + y: floor((y - screenY) * 3) + }; + + struct screenCell* cell = &(screen[screenX][screenY]); + cell->atoms = realloc(cell->atoms, ++cell->number * sizeof(struct patternAtom)); + if (cell->atoms == NULL) { + panic("couldn't allocate screen buffer: %s", strerror(errno)); + } + cell->atoms[cell->number - 1] = atom; + } + + for (int x = 0; x < SCREEN_WIDTH + 2; x++) { + cprintf("-"); + } + cprintf("\n"); + for (int y = 0; y < SCREEN_HEIGHT; y++) { + cprintf("|"); + for (int x = 0; x < SCREEN_WIDTH; x++) { + cprintf("%lc", getPattern(screen[x][y].atoms, screen[x][y].number)); + } + cprintf("|\n"); + } + for (int x = 0; x < SCREEN_WIDTH + 2; x++) { + cprintf("-"); + } + cprintf("\n"); +} + +void createPoint(struct point points[], int i, struct vector position) { + if (points == NULL) + return; + + struct vector source = { + x: randomFloat() * SCREEN_WIDTH - SCREEN_WIDTH / 2, + y: (randomFloat() * SCREEN_HEIGHT - SCREEN_HEIGHT / 2) / ASPECT_RATIO + }; + + points[i] = (struct point) { + target: position, + source: source, + position: source + }; +} + +struct vector add(struct vector vector, float x, float y) { + return (struct vector) { + x: vector.x + x, + y: (vector.y + y) / ASPECT_RATIO + }; +} + +int char2points(char c, struct point points[], struct vector position) { + int i = 0; + switch(c) { + case 'A': + createPoint(points, i++, add(position, 1.0, 0.0)); + createPoint(points, i++, add(position, 1.5, 0.0)); + createPoint(points, i++, add(position, 1.0, 0.4)); + createPoint(points, i++, add(position, 1.5, 0.4)); + createPoint(points, i++, add(position, 0.5, 0.7)); + createPoint(points, i++, add(position, 2.0, 0.7)); + createPoint(points, i++, add(position, 0.0, 1.0)); + createPoint(points, i++, add(position, 0.5, 1.0)); + createPoint(points, i++, add(position, 2.0, 1.0)); + createPoint(points, i++, add(position, 2.5, 1.0)); + createPoint(points, i++, add(position, 0.0, 1.4)); + createPoint(points, i++, add(position, 0.5, 1.4)); + createPoint(points, i++, add(position, 1.0, 1.4)); + createPoint(points, i++, add(position, 1.5, 1.4)); + createPoint(points, i++, add(position, 2.0, 1.4)); + createPoint(points, i++, add(position, 2.5, 1.4)); + createPoint(points, i++, add(position, 0.0, 1.7)); + createPoint(points, i++, add(position, 0.5, 1.7)); + createPoint(points, i++, add(position, 1.0, 1.7)); + createPoint(points, i++, add(position, 1.5, 1.7)); + createPoint(points, i++, add(position, 2.0, 1.7)); + createPoint(points, i++, add(position, 2.5, 1.7)); + createPoint(points, i++, add(position, 0.0, 2.0)); + createPoint(points, i++, add(position, 0.5, 2.0)); + createPoint(points, i++, add(position, 2.0, 2.0)); + createPoint(points, i++, add(position, 2.5, 2.0)); + createPoint(points, i++, add(position, 0.0, 2.4)); + createPoint(points, i++, add(position, 0.5, 2.4)); + createPoint(points, i++, add(position, 2.0, 2.4)); + createPoint(points, i++, add(position, 2.5, 2.4)); + createPoint(points, i++, add(position, 0.0, 2.7)); + createPoint(points, i++, add(position, 0.5, 2.7)); + createPoint(points, i++, add(position, 2.0, 2.7)); + createPoint(points, i++, add(position, 2.5, 2.7)); + return i; + case 'C': + return i; + case 'D': + return i; + case 'E': + return i; + case 'F': + return i; + case 'G': + return i; + case 'H': + createPoint(points, i++, add(position, 0.0, 0.0)); + createPoint(points, i++, add(position, 0.0, 0.4)); + createPoint(points, i++, add(position, 0.0, 0.7)); + createPoint(points, i++, add(position, 0.0, 1.0)); + createPoint(points, i++, add(position, 0.0, 1.4)); + createPoint(points, i++, add(position, 0.0, 1.7)); + createPoint(points, i++, add(position, 0.0, 2.0)); + createPoint(points, i++, add(position, 0.0, 2.4)); + createPoint(points, i++, add(position, 0.0, 2.7)); + createPoint(points, i++, add(position, 0.5, 0.0)); + createPoint(points, i++, add(position, 0.5, 0.4)); + createPoint(points, i++, add(position, 0.5, 0.7)); + createPoint(points, i++, add(position, 0.5, 1.0)); + createPoint(points, i++, add(position, 0.5, 1.4)); + createPoint(points, i++, add(position, 0.5, 1.7)); + createPoint(points, i++, add(position, 0.5, 2.0)); + createPoint(points, i++, add(position, 0.5, 2.4)); + createPoint(points, i++, add(position, 0.5, 2.7)); + createPoint(points, i++, add(position, 1.0, 1.0)); + createPoint(points, i++, add(position, 1.0, 1.4)); + createPoint(points, i++, add(position, 1.0, 1.7)); + createPoint(points, i++, add(position, 1.5, 1.0)); + createPoint(points, i++, add(position, 1.5, 1.4)); + createPoint(points, i++, add(position, 1.5, 1.7)); + createPoint(points, i++, add(position, 2.0, 0.0)); + createPoint(points, i++, add(position, 2.0, 0.4)); + createPoint(points, i++, add(position, 2.0, 0.7)); + createPoint(points, i++, add(position, 2.0, 1.0)); + createPoint(points, i++, add(position, 2.0, 1.4)); + createPoint(points, i++, add(position, 2.0, 1.7)); + createPoint(points, i++, add(position, 2.0, 2.0)); + createPoint(points, i++, add(position, 2.0, 2.4)); + createPoint(points, i++, add(position, 2.0, 2.7)); + createPoint(points, i++, add(position, 2.5, 0.0)); + createPoint(points, i++, add(position, 2.5, 0.4)); + createPoint(points, i++, add(position, 2.5, 0.7)); + createPoint(points, i++, add(position, 2.5, 1.0)); + createPoint(points, i++, add(position, 2.5, 1.4)); + createPoint(points, i++, add(position, 2.5, 1.7)); + createPoint(points, i++, add(position, 2.5, 2.0)); + createPoint(points, i++, add(position, 2.5, 2.4)); + createPoint(points, i++, add(position, 2.5, 2.7)); + return i; + case 'I': + return i; + case 'J': + return i; + case 'K': + return i; + case 'L': + createPoint(points, i++, add(position, 0.0, 0.0)); + createPoint(points, i++, add(position, 0.0, 0.4)); + createPoint(points, i++, add(position, 0.0, 0.7)); + createPoint(points, i++, add(position, 0.0, 1.0)); + createPoint(points, i++, add(position, 0.0, 1.4)); + createPoint(points, i++, add(position, 0.0, 1.7)); + createPoint(points, i++, add(position, 0.0, 2.0)); + createPoint(points, i++, add(position, 0.0, 2.4)); + createPoint(points, i++, add(position, 0.0, 2.7)); + createPoint(points, i++, add(position, 0.5, 0.0)); + createPoint(points, i++, add(position, 0.5, 0.4)); + createPoint(points, i++, add(position, 0.5, 0.7)); + createPoint(points, i++, add(position, 0.5, 1.0)); + createPoint(points, i++, add(position, 0.5, 1.4)); + createPoint(points, i++, add(position, 0.5, 1.7)); + createPoint(points, i++, add(position, 0.5, 2.0)); + createPoint(points, i++, add(position, 0.5, 2.4)); + createPoint(points, i++, add(position, 0.5, 2.7)); + createPoint(points, i++, add(position, 1.0, 2.4)); + createPoint(points, i++, add(position, 1.0, 2.7)); + createPoint(points, i++, add(position, 1.5, 2.4)); + createPoint(points, i++, add(position, 1.5, 2.7)); + createPoint(points, i++, add(position, 2.0, 2.4)); + createPoint(points, i++, add(position, 2.0, 2.7)); + createPoint(points, i++, add(position, 2.5, 2.4)); + createPoint(points, i++, add(position, 2.5, 2.7)); + return i; + case 'M': + return i; + case 'N': + return i; + case 'O': + createPoint(points, i++, add(position, 0.5, 0.0)); + createPoint(points, i++, add(position, 1.0, 0.0)); + createPoint(points, i++, add(position, 1.5, 0.0)); + createPoint(points, i++, add(position, 2.0, 0.0)); + createPoint(points, i++, add(position, 0.0, 0.4)); + createPoint(points, i++, add(position, 0.5, 0.4)); + createPoint(points, i++, add(position, 1.0, 0.4)); + createPoint(points, i++, add(position, 1.5, 0.4)); + createPoint(points, i++, add(position, 2.0, 0.4)); + createPoint(points, i++, add(position, 2.5, 0.4)); + createPoint(points, i++, add(position, 0.0, 0.7)); + createPoint(points, i++, add(position, 0.5, 0.7)); + createPoint(points, i++, add(position, 1.0, 0.7)); + createPoint(points, i++, add(position, 1.5, 0.7)); + createPoint(points, i++, add(position, 2.0, 0.7)); + createPoint(points, i++, add(position, 2.5, 0.7)); + createPoint(points, i++, add(position, 0.0, 1.0)); + createPoint(points, i++, add(position, 0.5, 1.0)); + createPoint(points, i++, add(position, 2.0, 1.0)); + createPoint(points, i++, add(position, 2.5, 1.0)); + createPoint(points, i++, add(position, 0.0, 1.4)); + createPoint(points, i++, add(position, 0.5, 1.4)); + createPoint(points, i++, add(position, 2.0, 1.4)); + createPoint(points, i++, add(position, 2.5, 1.4)); + createPoint(points, i++, add(position, 0.0, 1.7)); + createPoint(points, i++, add(position, 0.5, 1.7)); + createPoint(points, i++, add(position, 2.0, 1.7)); + createPoint(points, i++, add(position, 2.5, 1.7)); + createPoint(points, i++, add(position, 0.0, 2.0)); + createPoint(points, i++, add(position, 0.5, 2.0)); + createPoint(points, i++, add(position, 1.0, 2.0)); + createPoint(points, i++, add(position, 1.5, 2.0)); + createPoint(points, i++, add(position, 2.0, 2.0)); + createPoint(points, i++, add(position, 2.5, 2.0)); + createPoint(points, i++, add(position, 0.0, 2.4)); + createPoint(points, i++, add(position, 0.5, 2.4)); + createPoint(points, i++, add(position, 1.0, 2.4)); + createPoint(points, i++, add(position, 1.5, 2.4)); + createPoint(points, i++, add(position, 2.0, 2.4)); + createPoint(points, i++, add(position, 2.5, 2.4)); + createPoint(points, i++, add(position, 0.5, 2.7)); + createPoint(points, i++, add(position, 1.0, 2.7)); + createPoint(points, i++, add(position, 1.5, 2.7)); + createPoint(points, i++, add(position, 2.0, 2.7)); + return i; + case 'P': + return i; + case 'Q': + return i; + case 'R': + return i; + case 'S': + return i; + case 'T': + return i; + case 'U': + return i; + case 'V': + return i; + case 'W': + return i; + case 'X': + return i; + case 'Y': + return i; + case 'Z': + return i; + default: + return i; + } +} + +void string2points(const char* string, struct point points[]) { + int length = strlen(string); + + struct vector position = (struct vector) { + x: -(length * 4 / 2), + y: -2 + }; + + int index = 0; + + for (int i = 0; i < length; i++) { + index += char2points(string[i], &(points[index]), position); + + position.x += 4; + } +} + +int numberPoints(const char* string) { + int sum = 0; + + int length = strlen(string); + for (int i = 0; i < length; i++) { + sum += char2points(string[i], NULL, (struct vector) {0, 0}); + } + + return sum; +} + +void scatter(struct point points[], int number) { + for (int i = 0; i < number; i++) { + points[i].source = points[i].position; + + float phi = randomFloat() * M_PI * 2; + float r = sqrt(SCREEN_WIDTH * SCREEN_WIDTH + SCREEN_HEIGHT * SCREEN_HEIGHT) / 2; + + points[i].target = (struct vector) { + x: r * cos(phi), + y: r * sin(phi) + }; + } +} + +int main() { + setlocale(LC_CTYPE, ""); + enable_compat_mode(PRINT_WCHAR); + + initRandom(); + + const char* string = "HALLO"; + + int number = numberPoints(string); + + struct point* points = malloc(number * sizeof(struct point)); + if (points == NULL) + panic("could allocate point array: %s", strerror(errno)); + + string2points(string, points); + + hideCursor(); + + eraseScreen(); + + bool scattered = false; + + while(true) { + moveCursorAbsolute(0, 0); + displayPoints(points, number); + //fflush(stdout); + usleep(ANIMATION_SLEEP_TIME); + + if (tickPoints(points, number)) { + if (scattered) { + return 0; + } else { + scatter(points, number); + scattered = true; + + moveCursorAbsolute(0, 0); + displayPoints(points, number); + usleep(SCATTER_SLEEP_TIME); + } + } + } +} diff --git a/src/gravity.c b/src/gravity.c new file mode 100644 index 0000000..8508a36 --- /dev/null +++ b/src/gravity.c @@ -0,0 +1,320 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/graphics.h" +#include "common/utils.h" + +#define SUBSTITUDE_PRINTS +#include "common/compat.h" + +#define G (10.0) + +#define OFFSET_X (-50) +#define OFFSET_Y (-15) + +#define SCREEN_WIDTH (100) +#define SCREEN_HEIGHT (30) + +#define NUMBER_OF_POINTS (2) + +#define TERMINAL_VELOCITY (100.0) + +#define ASPECT_RATIO (3.0/2.0) +#define FACTOR_X (1.0) +#define FACTOR_Y (FACTOR_X * ASPECT_RATIO) + +#define SLEEP_TIME (100000) + +#define TICKS_PER_TIME (1) + +#define BRAILLE_PREFIX (0x2800) +#define BRAILLE_TOP_LEFT (0x01) +#define BRAILLE_MIDDLE_LEFT (0x02) +#define BRAILLE_BOTTOM_LEFT (0x04) +#define BRAILLE_TOP_RIGHT (0x08) +#define BRAILLE_MIDDLE_RIGHT (0x10) +#define BRAILLE_BOTTOM_RIGHT (0x20) + +struct vector { + float x; + float y; +}; + +struct point { + struct vector position; + struct vector velocity; + struct vector force; + float radius; + float mass; +}; + +float distance(struct point* a, struct point* b) { + float dx = b->position.x - a->position.x; + float dy = b->position.y - a->position.y; + + return sqrt((dx * dx) + (dy * dy)); +} + +struct vector direction(struct point* a, struct point* b) { + float dx = b->position.x - a->position.x; + float dy = b->position.y - a->position.y; + + float r = sqrt((dx * dx) + (dy * dy)); + + return (struct vector) { + x: dx / r, + y: dy / r + }; + +} + +void tickPoint(struct point* point) { + float factor = SLEEP_TIME / 1000000.0 * TICKS_PER_TIME; + + point->position.x += point->velocity.x * factor; + point->position.y += point->velocity.y * factor; +} + +void zeroVector(struct vector* vector) { + vector->x = 0; + vector->y = 0; +} + +void merge(struct point* a, struct point* b) { + a->position.x = (a->position.x + b->position.x) / 2; + a->position.y = (a->position.y + b->position.y) / 2; + b->position.x = a->position.x; + b->position.y = a->position.y; + + a->velocity.x = (a->velocity.x * a->mass + b->velocity.x * b->mass) / (a->mass + b->mass); + a->velocity.y = (a->velocity.y * a->mass + b->velocity.y * b->mass) / (a->mass + b->mass); + b->velocity.x = a->velocity.x; + b->velocity.y = a->velocity.y; +} + +void applyGravityToForce(struct point* a, struct point* b) { + float r = distance(a, b); + + cprintf("%f, ", r); + + if (r <= a->radius + b->radius) { + //merge(a, b); + return; + } + float f = G * (a->mass * b->mass) / (r * r); + + struct vector directionAtoB = direction(a, b); + + a->force.x += f * directionAtoB.x; + a->force.y += f * directionAtoB.y; + b->force.x += f * directionAtoB.x * (-1); + b->force.y += f * directionAtoB.y * (-1); + + //cprintf("%f, %f\n", a->force.x, a->force.y); +} + +void applyForceToVelocity(struct point* point) { + point->velocity.x += point->force.x / point->mass; + point->velocity.y += point->force.y / point->mass; + + float scalarVelocity = sqrt(point->velocity.x * point->velocity.x + point->velocity.y * point->velocity.y); + + if (scalarVelocity > TERMINAL_VELOCITY) { + float capFactor = TERMINAL_VELOCITY / scalarVelocity; + + point->velocity.x *= capFactor; + point->velocity.y *= capFactor; + } + + zeroVector(&(point->force)); +} + +struct patternAtom { + int x; // 0-1 + int y; // 0-2 +}; + +wchar_t getPattern(struct patternAtom atoms[], int number) { + if (number == 0) { + return L' '; + } + + wchar_t result = BRAILLE_PREFIX; + + for (int i = 0; i < number; i++) { + if (atoms[i].x == 0) { + if (atoms[i].y == 0) { + result |= BRAILLE_TOP_LEFT; + } else if (atoms[i].y == 1) { + result |= BRAILLE_MIDDLE_LEFT; + } else { + result |= BRAILLE_BOTTOM_LEFT; + } + } else { + if (atoms[i].y == 0) { + result |= BRAILLE_TOP_RIGHT; + } else if (atoms[i].y == 1) { + result |= BRAILLE_MIDDLE_RIGHT; + } else { + result |= BRAILLE_BOTTOM_RIGHT; + } + } + } + + return result; +} + +struct point randomPoint() { + return (struct point) { + position: { + x: randomFloat() * 20 - 10, + y: randomFloat() * 20 - 10 + }, + velocity: { + x: (randomFloat() - 0.5) / 1000, + y: (randomFloat() - 0.5) / 1000 + }, + force: { + x: 0, + y: 0 + }, + radius: 0.1, + mass: randomFloat() + 0.1 + }; +} + +void initPoints(struct point points[]) { + for (int i = 0; i < NUMBER_OF_POINTS; i++) { + points[i] = randomPoint(); + } +} + +void tickPoints(struct point points[]) { + for (int i = 0; i < NUMBER_OF_POINTS; i++) { + for (int j = 0; j < NUMBER_OF_POINTS; j++) { + if (i == j) + continue; + + applyGravityToForce(&(points[i]), &(points[j])); + } + } + + for (int i = 0; i < NUMBER_OF_POINTS; i++) { + applyForceToVelocity(&(points[i])); + tickPoint(&(points[i])); + } +} + +struct screenCell { + struct patternAtom* atoms; + int number; +}; + +void displayPoints(struct point points[]) { + struct screenCell screen[SCREEN_WIDTH][SCREEN_HEIGHT]; + for (int x = 0; x < SCREEN_WIDTH; x++) { + for (int y = 0; y < SCREEN_HEIGHT; y++) { + screen[x][y].atoms = NULL; + screen[x][y].number = 0; + } + } + + for (int i = 0; i < NUMBER_OF_POINTS; i++) { + struct point p = points[i]; + float x = p.position.x * FACTOR_X - OFFSET_X; + float y = p.position.y * FACTOR_Y - OFFSET_Y; + + int screenX = floor(x); + int screenY = floor(y); + + if (screenX < 0 || screenX >= SCREEN_WIDTH) { + continue; + } + if (screenY < 0 || screenY >= SCREEN_HEIGHT) { + continue; + } + + struct patternAtom atom = { + x: floor((x - screenX) * 2), + y: floor((y - screenY) * 3) + }; + + struct screenCell* cell = &(screen[screenX][screenY]); + cell->atoms = realloc(cell->atoms, ++cell->number * sizeof(struct patternAtom)); + if (cell->atoms == NULL) { + panic("couldn't allocate screen buffer: %s", strerror(errno)); + } + cell->atoms[cell->number - 1] = atom; + } + + for (int y = 0; y < SCREEN_HEIGHT; y++) { + for (int x = 0; x < SCREEN_WIDTH; x++) { + cprintf("%lc", getPattern(screen[x][y].atoms, screen[x][y].number)); + } + cprintf("\n"); + } +} + +int main() { + setlocale(LC_CTYPE, ""); + enable_compat_mode(PRINT_WCHAR); + + initRandom(); + + struct point points[NUMBER_OF_POINTS]; + //initPoints(points); + + // hardcoded points to test orbit example + points[0] = (struct point) { + position: { + x: 0, + y: 0 + }, + velocity: { + x: 0, + y: 0 + }, + force: { + x: 0, + y: 0 + }, + radius: 0.1, + mass: 5 + }; + points[1] = (struct point) { + position: { + x: 10, + y: 0 + }, + velocity: { + x: 0, + y: 10 + }, + force: { + x: 0, + y: 0 + }, + radius: 0.1, + mass: 0.1 + }; + + hideCursor(); + + eraseScreen(); + + while(true) { + moveCursorAbsolute(0, 0); + displayPoints(points); + //fflush(stdout); + usleep(SLEEP_TIME); + for (int i = 0; i < TICKS_PER_TIME; i++) + tickPoints(points); + } +} diff --git a/src/test.c b/src/test.c new file mode 100644 index 0000000..9d405f9 --- /dev/null +++ b/src/test.c @@ -0,0 +1,17 @@ +#include "common/compat.h" +#include "common/graphics.h" +#include "common/utils.h" + +#include +#include +#include + +int main() { + if (setvbuf(stdin, NULL, _IONBF, 0) != 0) { + panic("can't set buffer for stdin: %s", strerror(errno)); + } + + struct dimensions d = getScreenSize(); + + cprintf("%d, %d\n", d.width, d.height); +}