changeset 27:30b6812fefdd

add cmake config
author Dennis C. M. <dennis@denniscm.com>
date Wed, 28 Jun 2023 08:58:44 +0100
parents 2945f5898960
children 99592fae8ea1
files .gitignore CMakeLists.txt main.c src/main.c
diffstat 4 files changed, 480 insertions(+), 459 deletions(-) [+]
line wrap: on
line diff
--- a/.gitignore	Tue Jun 27 20:17:52 2023 +0100
+++ b/.gitignore	Wed Jun 28 08:58:44 2023 +0100
@@ -1,3 +1,5 @@
+build
+
 # Created by https://www.toptal.com/developers/gitignore/api/c
 # Edit at https://www.toptal.com/developers/gitignore?templates=c
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CMakeLists.txt	Wed Jun 28 08:58:44 2023 +0100
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 3.22)
+project(algo_animator)
+
+set(SOURCES src/main.c)
+set(FREETYPE_DIR /usr/local/include/freetype2)
+
+include_directories(${FREETYPE_DIR})
+
+add_executable(algo_animator ${SOURCES})
+
+target_link_libraries(algo_animator
+    glut
+    GL
+    GLU
+    m
+    freetype
+)
+
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/fonts DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/build)
--- a/main.c	Tue Jun 27 20:17:52 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,459 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <GL/glut.h>
-#include <math.h>
-#include <time.h>
-#include <stdbool.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-
-
-#define WINDOW_WIDTH 1920
-#define WINDOW_HEIGHT 1080
-#define VPADDING 150
-#define RECT_WIDTH 5
-#define SPACE 1
-
-
-/* Helper functions */
-
-struct Element {
-	float value;
-	bool current;
-};
-
-struct Element *arr;
-int arr_size;
-
-void create_array() {
-	arr_size = WINDOW_WIDTH / (RECT_WIDTH + SPACE);
-	arr = malloc(arr_size * sizeof(struct Element));
-
-	float rect_increase = (WINDOW_HEIGHT - VPADDING * 2) / (float)(arr_size - 1);
-
-	for (int i = 1; i <= arr_size; i++) {
-		arr[i - 1].value = i * rect_increase;
-		arr[i - 1].current = false;
-	}
-}
-
-
-void swap_elements(int x, int y) {
-	struct Element temp = arr[x];
-	arr[x] = arr[y];
-	arr[y] = temp;
-}
-
-
-void randomize_array() {
-	srand(time(NULL));
-
-	// Fisher-Yates shuffle
-	for (int i = arr_size - 1; i > 0; i--) {
-		int j = rand() % (i + 1);
-
-		// Swap
-		swap_elements(i, j);
-	}
-}
-
-
-bool array_sorted() {
-	for (int i = 0; i < arr_size - 1; i++) {
-		if (arr[i].value > arr[i + 1].value) {
-			return false;
-		}
-	}
-
-	return true;
-}
-
-
-struct Algo {
-	char name[50];
-	void (*function)();
-};
-
-struct Algo algos[2];
-int selected_algo = 0;
-
-void algo_selector(int direction) {
-	int selection = selected_algo + direction;
-	int lower = 0;
-	int upper = (sizeof(algos) / sizeof(algos[0])) - 1;
-
-	if (selection >= lower && selection <= upper) {
-		selected_algo = selection;
-	}
-}
-
-
-/* Algorithms */
-
-// Just some variables to store the state of the running algorithm
-struct AlgoState {
-	int a;
-	int b;
-	int c;
-};
-
-struct AlgoState as;
-
-void reset_state() {
-	as.a = 0;
-	as.b = 0;
-	as.c = 0;
-}
-
-
-void bubble_sort() {
-
-	/*
-	 * a: Index of the current selection
-	 * b: Index boundary of the sorted array
-	 */
-
-	if (as.a < arr_size - 1 - as.b) {
-		arr[as.a].current = true;
-
-		if (arr[as.a].value > arr[as.a + 1].value) {
-			swap_elements(as.a + 1, as.a);
-		}
-
-		as.a++;
-	} else {
-		as.b++;
-		as.a = 0;
-	}
-}
-
-
-void selection_sort() {
-
-	/*
-	 * a: Index of current selection
-	 * b: Index of boundary of sorted array
-	 * c: Index of the minimum element
-	 */
-
-
-	if (as.a < arr_size) {
-		arr[as.a].current = true;
-
-		if (arr[as.a].value < arr[as.c].value) {
-
-			// Save new minimum
-			as.c = as.a;
-		}
-
-		as.a++;
-	} else {
-		swap_elements(as.b, as.c);
-
-		as.b++;
-		as.a = as.b;
-		as.c = as.a;
-	}
-}
-
-
-void quick_sort() {
-
-}
-
-
-void insertion_sort() {
-
-}
-
-
-void merge_sort() {
-
-}
-
-
-/* Render functions */
-
-FT_Library ft_library;
-FT_Face ft_face;
-
-void render_text(int x, int y, char* text) {
-	for (const char *c = text; *c; c++) {
-
-		// Get glyph index from character code
-		FT_UInt glyph_index = FT_Get_Char_Index(ft_face, *c);
-
-		if (glyph_index == 0) {
-			fprintf(stderr, "Given character code has no glyph image in the face\n");
-			exit(1);
-		}
-
-		// Load glyph image
-		if (FT_Load_Glyph(ft_face, glyph_index, FT_LOAD_DEFAULT)) {
-			fprintf(stderr, "Failed to load glyph.\n");
-			exit(1);
-		}
-
-		// Render glyph
-		if (FT_Render_Glyph(ft_face->glyph, FT_RENDER_MODE_NORMAL)) {
-			fprintf(stderr, "Failed to render glyph.\n");
-			exit(1);
-		}
-
-		FT_GlyphSlot slot = ft_face->glyph;
-		FT_Bitmap* glyph_bitmap = &slot->bitmap;
-
-		// Flip the bitmap vertically
-		unsigned char* flipped_bitmap = (unsigned char*)malloc(glyph_bitmap->width * glyph_bitmap->rows);
-
-		for (int row = 0; row < glyph_bitmap->rows; row++) {
-			unsigned char* src_row = glyph_bitmap->buffer + (row * glyph_bitmap->width);
-			unsigned char* dest_row = flipped_bitmap + ((glyph_bitmap->rows - row - 1) * glyph_bitmap->width);
-			memcpy(dest_row, src_row, glyph_bitmap->width);
-		}
-
-		glyph_bitmap->buffer = flipped_bitmap;
-
-		// Calculate the adjusted y position based on the glyph's bearing
-		int adjusted_y = y + (slot->bitmap_top - glyph_bitmap->rows);
-
-		glRasterPos2f(x, adjusted_y);
-		glDrawPixels(glyph_bitmap->width, glyph_bitmap->rows, GL_LUMINANCE, GL_UNSIGNED_BYTE, glyph_bitmap->buffer);
-
-		x += slot->advance.x / 64;
-	}
-}
-
-
-int speed = 50;
-int iter_counter = 0;
-
-void display() {
-	glClear(GL_COLOR_BUFFER_BIT);
-
-	glBegin(GL_QUADS);
-
-	int x = 0;
-	for (int i = 0; i < arr_size; i++) {
-
-		if (arr[i].current) {
-			glColor3f(1.0, 1.0, 1.0);
-		} else {
-			glColor3f(1.0, 0.7569, 0.0);
-		}
-
-		// Bottom left
-		glVertex2f(x, VPADDING);
-
-		// Top left
-		glVertex2f(x, VPADDING + arr[i].value);
-
-		// Top right
-		glVertex2f(x + RECT_WIDTH, VPADDING + arr[i].value);
-
-		// Bottom right
-		glVertex2f(x + RECT_WIDTH, VPADDING);
-
-		x += RECT_WIDTH + SPACE;
-
-		arr[i].current = false;
-	}
-
-	glEnd();
-
-	// Render text
-	char text[256];
-
-	// Top: Column 1
-	sprintf(text, "Algorithm: %s", algos[selected_algo].name);
-	render_text(20, WINDOW_HEIGHT - 50, text);
-
-	sprintf(text, "Speed: %i", speed);
-	render_text(20, WINDOW_HEIGHT - 80, text);
-
-	// Top: Column 2
-	sprintf(text, "Number of elements: %i", arr_size);
-	render_text(500, WINDOW_HEIGHT - 50, text);
-
-	sprintf(text, "Iterations: %i", iter_counter);
-	render_text(500, WINDOW_HEIGHT - 80, text);
-
-
-	// Bottom: Column 1
-	render_text(20, VPADDING - 50, "Press a or s to select an algorithm.");
-	render_text(20, VPADDING - 80, "Press u or d to modify speed.");
-	render_text(20, VPADDING - 110, "Press r to randomize the array.");
-
-	// Bottom: Column 2
-	render_text(800, VPADDING - 50, "Press enter to run the algorithm.");
-	render_text(800, VPADDING - 80, "Press p to pause the algorithm.");
-
-	glutSwapBuffers();
-}
-
-
-/* Refresh function */
-
-
-bool run;
-int refresh_counter = 0;
-
-void idle() {
-	if (run) {
-		algos[selected_algo].function();
-		refresh_counter++;
-		iter_counter++;
-
-		if (refresh_counter == speed) {
-			glutPostRedisplay();
-			refresh_counter = 0;
-		}
-
-	} else {
-		glutPostRedisplay();
-	}
-
-	if (array_sorted()) {
-		run = false;
-	}
-}
-
-
-/* User input handler */
-
-void keyboard(unsigned char key, int x, int y) {
-
-	// s: Next algorithm
-	if (key == 115) {
-		algo_selector(1);
-	}
-
-	// a: Previous algorithm
-	if (key == 97) {
-		algo_selector(-1);
-	}
-
-	// r: Reset state
-	if (key == 114) {
-		randomize_array();
-
-		// Reset state
-		iter_counter = 0;
-		refresh_counter = 0;
-		run = false;
-
-		// Reset algo steps
-		reset_state();
-	}
-
-	// u: Increase speed
-	if (key == 117) {
-		speed++;
-	}
-
-	// d: reduce speed
-	if (key == 100) {
-		if (speed > 1) {
-			speed--;
-		}
-	}
-
-	// enter: Run program
-	if (key == 13) {
-		run = true;
-	}
-
-	// p: Pause program
-	if (key == 112) {
-		run = false;
-	}
-}
-
-
-/* Set up functions */
-
-void setup_gl() {
-
-	// Set background dark
-	glClearColor(0.0, 0.0, 0.0, 1.0);
-
-	// Set point color and size to 1 pixel
-	glColor3f(1.0, 0.7569, 0.0);
-	glPointSize(5.0);
-
-	// Matrix projection and reset with identity
-	glMatrixMode(GL_PROJECTION);
-	glLoadIdentity();
-
-	/* 
-	 * Creates projection matrix
-	 * x increases from left to right (0 to WINDOW_WIDTH)
-	 * y increases from bottom to top (0 to WINDOW_HEIGHT)
-	 */
-
-	gluOrtho2D(0, WINDOW_WIDTH, 0, WINDOW_HEIGHT);
-
-	/* 
-	 * This fucking line... I spent a day rendering weird symbols
-	 * because the padding that adds FreeType to each row of the bitmap
-	 * does not match the padding expected by GL.
-	 */
-
-	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-}
-
-
-void setup_freetype() {
-
-	// Init library
-	if (FT_Init_FreeType(&ft_library)) {
-		fprintf(stderr, "Failed to initialize FreeType library\n");
-		exit(1);
-	}
-
-	// Load font
-	if (FT_New_Face(ft_library, "fonts/JetBrainsMono-Regular.ttf", 0, &ft_face)) {
-		fprintf(stderr, "Failed to load font\n");
-		exit(1);
-	}
-
-	// Set font size
-	if (FT_Set_Pixel_Sizes(ft_face, 0, 24)) {
-		fprintf(stderr, "Failed to set font size.\n");
-		FT_Done_Face(ft_face);
-		FT_Done_FreeType(ft_library);
-
-		exit(1);
-	}
-}
-
-
-int main(int argc, char** argv) {
-	strcpy(algos[0].name, "Bubble sort");
-	algos[0].function = &bubble_sort;
-
-	strcpy(algos[1].name, "Selection sort");
-	algos[1].function = &selection_sort;
-
-	create_array();
-
-	glutInit(&argc, argv);
-	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
-	glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
-	glutCreateWindow("Algorithm animator");
-
-	setup_gl();
-	setup_freetype();
-
-	glutDisplayFunc(display);
-	glutKeyboardFunc(keyboard);
-	glutIdleFunc(idle);
-	glutMainLoop();
-
-	free(arr);
-
-	FT_Done_Face(ft_face);
-	FT_Done_FreeType(ft_library);
-
-	return 0;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main.c	Wed Jun 28 08:58:44 2023 +0100
@@ -0,0 +1,459 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <GL/glut.h>
+#include <math.h>
+#include <time.h>
+#include <stdbool.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+
+#define WINDOW_WIDTH 1920
+#define WINDOW_HEIGHT 1080
+#define VPADDING 150
+#define RECT_WIDTH 5
+#define SPACE 1
+
+
+/* Helper functions */
+
+struct Element {
+	float value;
+	bool current;
+};
+
+struct Element *arr;
+int arr_size;
+
+void create_array() {
+	arr_size = WINDOW_WIDTH / (RECT_WIDTH + SPACE);
+	arr = malloc(arr_size * sizeof(struct Element));
+
+	float rect_increase = (WINDOW_HEIGHT - VPADDING * 2) / (float)(arr_size - 1);
+
+	for (int i = 1; i <= arr_size; i++) {
+		arr[i - 1].value = i * rect_increase;
+		arr[i - 1].current = false;
+	}
+}
+
+
+void swap_elements(int x, int y) {
+	struct Element temp = arr[x];
+	arr[x] = arr[y];
+	arr[y] = temp;
+}
+
+
+void randomize_array() {
+	srand(time(NULL));
+
+	// Fisher-Yates shuffle
+	for (int i = arr_size - 1; i > 0; i--) {
+		int j = rand() % (i + 1);
+
+		// Swap
+		swap_elements(i, j);
+	}
+}
+
+
+bool array_sorted() {
+	for (int i = 0; i < arr_size - 1; i++) {
+		if (arr[i].value > arr[i + 1].value) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
+
+struct Algo {
+	char name[50];
+	void (*function)();
+};
+
+struct Algo algos[2];
+int selected_algo = 0;
+
+void algo_selector(int direction) {
+	int selection = selected_algo + direction;
+	int lower = 0;
+	int upper = (sizeof(algos) / sizeof(algos[0])) - 1;
+
+	if (selection >= lower && selection <= upper) {
+		selected_algo = selection;
+	}
+}
+
+
+/* Algorithms */
+
+// Just some variables to store the state of the running algorithm
+struct AlgoState {
+	int a;
+	int b;
+	int c;
+};
+
+struct AlgoState as;
+
+void reset_state() {
+	as.a = 0;
+	as.b = 0;
+	as.c = 0;
+}
+
+
+void bubble_sort() {
+
+	/*
+	 * a: Index of the current selection
+	 * b: Index boundary of the sorted array
+	 */
+
+	if (as.a < arr_size - 1 - as.b) {
+		arr[as.a].current = true;
+
+		if (arr[as.a].value > arr[as.a + 1].value) {
+			swap_elements(as.a + 1, as.a);
+		}
+
+		as.a++;
+	} else {
+		as.b++;
+		as.a = 0;
+	}
+}
+
+
+void selection_sort() {
+
+	/*
+	 * a: Index of current selection
+	 * b: Index of boundary of sorted array
+	 * c: Index of the minimum element
+	 */
+
+
+	if (as.a < arr_size) {
+		arr[as.a].current = true;
+
+		if (arr[as.a].value < arr[as.c].value) {
+
+			// Save new minimum
+			as.c = as.a;
+		}
+
+		as.a++;
+	} else {
+		swap_elements(as.b, as.c);
+
+		as.b++;
+		as.a = as.b;
+		as.c = as.a;
+	}
+}
+
+
+void quick_sort() {
+
+}
+
+
+void insertion_sort() {
+
+}
+
+
+void merge_sort() {
+
+}
+
+
+/* Render functions */
+
+FT_Library ft_library;
+FT_Face ft_face;
+
+void render_text(int x, int y, char* text) {
+	for (const char *c = text; *c; c++) {
+
+		// Get glyph index from character code
+		FT_UInt glyph_index = FT_Get_Char_Index(ft_face, *c);
+
+		if (glyph_index == 0) {
+			fprintf(stderr, "Given character code has no glyph image in the face\n");
+			exit(1);
+		}
+
+		// Load glyph image
+		if (FT_Load_Glyph(ft_face, glyph_index, FT_LOAD_DEFAULT)) {
+			fprintf(stderr, "Failed to load glyph.\n");
+			exit(1);
+		}
+
+		// Render glyph
+		if (FT_Render_Glyph(ft_face->glyph, FT_RENDER_MODE_NORMAL)) {
+			fprintf(stderr, "Failed to render glyph.\n");
+			exit(1);
+		}
+
+		FT_GlyphSlot slot = ft_face->glyph;
+		FT_Bitmap* glyph_bitmap = &slot->bitmap;
+
+		// Flip the bitmap vertically
+		unsigned char* flipped_bitmap = (unsigned char*)malloc(glyph_bitmap->width * glyph_bitmap->rows);
+
+		for (int row = 0; row < glyph_bitmap->rows; row++) {
+			unsigned char* src_row = glyph_bitmap->buffer + (row * glyph_bitmap->width);
+			unsigned char* dest_row = flipped_bitmap + ((glyph_bitmap->rows - row - 1) * glyph_bitmap->width);
+			memcpy(dest_row, src_row, glyph_bitmap->width);
+		}
+
+		glyph_bitmap->buffer = flipped_bitmap;
+
+		// Calculate the adjusted y position based on the glyph's bearing
+		int adjusted_y = y + (slot->bitmap_top - glyph_bitmap->rows);
+
+		glRasterPos2f(x, adjusted_y);
+		glDrawPixels(glyph_bitmap->width, glyph_bitmap->rows, GL_LUMINANCE, GL_UNSIGNED_BYTE, glyph_bitmap->buffer);
+
+		x += slot->advance.x / 64;
+	}
+}
+
+
+int speed = 50;
+int iter_counter = 0;
+
+void display() {
+	glClear(GL_COLOR_BUFFER_BIT);
+
+	glBegin(GL_QUADS);
+
+	int x = 0;
+	for (int i = 0; i < arr_size; i++) {
+
+		if (arr[i].current) {
+			glColor3f(1.0, 1.0, 1.0);
+		} else {
+			glColor3f(1.0, 0.7569, 0.0);
+		}
+
+		// Bottom left
+		glVertex2f(x, VPADDING);
+
+		// Top left
+		glVertex2f(x, VPADDING + arr[i].value);
+
+		// Top right
+		glVertex2f(x + RECT_WIDTH, VPADDING + arr[i].value);
+
+		// Bottom right
+		glVertex2f(x + RECT_WIDTH, VPADDING);
+
+		x += RECT_WIDTH + SPACE;
+
+		arr[i].current = false;
+	}
+
+	glEnd();
+
+	// Render text
+	char text[256];
+
+	// Top: Column 1
+	sprintf(text, "Algorithm: %s", algos[selected_algo].name);
+	render_text(20, WINDOW_HEIGHT - 50, text);
+
+	sprintf(text, "Speed: %i", speed);
+	render_text(20, WINDOW_HEIGHT - 80, text);
+
+	// Top: Column 2
+	sprintf(text, "Number of elements: %i", arr_size);
+	render_text(500, WINDOW_HEIGHT - 50, text);
+
+	sprintf(text, "Iterations: %i", iter_counter);
+	render_text(500, WINDOW_HEIGHT - 80, text);
+
+
+	// Bottom: Column 1
+	render_text(20, VPADDING - 50, "Press a or s to select an algorithm.");
+	render_text(20, VPADDING - 80, "Press u or d to modify speed.");
+	render_text(20, VPADDING - 110, "Press r to randomize the array.");
+
+	// Bottom: Column 2
+	render_text(800, VPADDING - 50, "Press enter to run the algorithm.");
+	render_text(800, VPADDING - 80, "Press p to pause the algorithm.");
+
+	glutSwapBuffers();
+}
+
+
+/* Refresh function */
+
+
+bool run;
+int refresh_counter = 0;
+
+void idle() {
+	if (run) {
+		algos[selected_algo].function();
+		refresh_counter++;
+		iter_counter++;
+
+		if (refresh_counter == speed) {
+			glutPostRedisplay();
+			refresh_counter = 0;
+		}
+
+	} else {
+		glutPostRedisplay();
+	}
+
+	if (array_sorted()) {
+		run = false;
+	}
+}
+
+
+/* User input handler */
+
+void keyboard(unsigned char key, int x, int y) {
+
+	// s: Next algorithm
+	if (key == 115) {
+		algo_selector(1);
+	}
+
+	// a: Previous algorithm
+	if (key == 97) {
+		algo_selector(-1);
+	}
+
+	// r: Reset state
+	if (key == 114) {
+		randomize_array();
+
+		// Reset state
+		iter_counter = 0;
+		refresh_counter = 0;
+		run = false;
+
+		// Reset algo steps
+		reset_state();
+	}
+
+	// u: Increase speed
+	if (key == 117) {
+		speed++;
+	}
+
+	// d: reduce speed
+	if (key == 100) {
+		if (speed > 1) {
+			speed--;
+		}
+	}
+
+	// enter: Run program
+	if (key == 13) {
+		run = true;
+	}
+
+	// p: Pause program
+	if (key == 112) {
+		run = false;
+	}
+}
+
+
+/* Set up functions */
+
+void setup_gl() {
+
+	// Set background dark
+	glClearColor(0.0, 0.0, 0.0, 1.0);
+
+	// Set point color and size to 1 pixel
+	glColor3f(1.0, 0.7569, 0.0);
+	glPointSize(5.0);
+
+	// Matrix projection and reset with identity
+	glMatrixMode(GL_PROJECTION);
+	glLoadIdentity();
+
+	/* 
+	 * Creates projection matrix
+	 * x increases from left to right (0 to WINDOW_WIDTH)
+	 * y increases from bottom to top (0 to WINDOW_HEIGHT)
+	 */
+
+	gluOrtho2D(0, WINDOW_WIDTH, 0, WINDOW_HEIGHT);
+
+	/* 
+	 * This fucking line... I spent a day rendering weird symbols
+	 * because the padding that adds FreeType to each row of the bitmap
+	 * does not match the padding expected by GL.
+	 */
+
+	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+}
+
+
+void setup_freetype() {
+
+	// Init library
+	if (FT_Init_FreeType(&ft_library)) {
+		fprintf(stderr, "Failed to initialize FreeType library\n");
+		exit(1);
+	}
+
+	// Load font
+	if (FT_New_Face(ft_library, "fonts/JetBrainsMono-Regular.ttf", 0, &ft_face)) {
+		fprintf(stderr, "Failed to load font\n");
+		exit(1);
+	}
+
+	// Set font size
+	if (FT_Set_Pixel_Sizes(ft_face, 0, 24)) {
+		fprintf(stderr, "Failed to set font size.\n");
+		FT_Done_Face(ft_face);
+		FT_Done_FreeType(ft_library);
+
+		exit(1);
+	}
+}
+
+
+int main(int argc, char** argv) {
+	strcpy(algos[0].name, "Bubble sort");
+	algos[0].function = &bubble_sort;
+
+	strcpy(algos[1].name, "Selection sort");
+	algos[1].function = &selection_sort;
+
+	create_array();
+
+	glutInit(&argc, argv);
+	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
+	glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
+	glutCreateWindow("Algorithm animator");
+
+	setup_gl();
+	setup_freetype();
+
+	glutDisplayFunc(display);
+	glutKeyboardFunc(keyboard);
+	glutIdleFunc(idle);
+	glutMainLoop();
+
+	free(arr);
+
+	FT_Done_Face(ft_face);
+	FT_Done_FreeType(ft_library);
+
+	return 0;
+}