1 #include <math.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include "lodepng.h"
5 #include "matrix.h"
6 #include "util.h"
7 
rand_int(int n)8 int rand_int(int n) {
9     int result;
10     while (n <= (result = rand() / (RAND_MAX / n)));
11     return result;
12 }
13 
rand_double()14 double rand_double() {
15     return (double)rand() / (double)RAND_MAX;
16 }
17 
update_fps(FPS * fps)18 void update_fps(FPS *fps) {
19     fps->frames++;
20     double now = glfwGetTime();
21     double elapsed = now - fps->since;
22     if (elapsed >= 1) {
23         fps->fps = round(fps->frames / elapsed);
24         fps->frames = 0;
25         fps->since = now;
26     }
27 }
28 
load_file(const char * path)29 char *load_file(const char *path) {
30     FILE *file = fopen(path, "rb");
31     fseek(file, 0, SEEK_END);
32     int length = ftell(file);
33     rewind(file);
34     char *data = calloc(length + 1, sizeof(char));
35     fread(data, 1, length, file);
36     fclose(file);
37     return data;
38 }
39 
gen_buffer(GLsizei size,GLfloat * data)40 GLuint gen_buffer(GLsizei size, GLfloat *data) {
41     GLuint buffer;
42     glGenBuffers(1, &buffer);
43     glBindBuffer(GL_ARRAY_BUFFER, buffer);
44     glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
45     glBindBuffer(GL_ARRAY_BUFFER, 0);
46     return buffer;
47 }
48 
del_buffer(GLuint buffer)49 void del_buffer(GLuint buffer) {
50     glDeleteBuffers(1, &buffer);
51 }
52 
malloc_faces(int components,int faces)53 GLfloat *malloc_faces(int components, int faces) {
54     return malloc(sizeof(GLfloat) * 6 * components * faces);
55 }
56 
gen_faces(int components,int faces,GLfloat * data)57 GLuint gen_faces(int components, int faces, GLfloat *data) {
58     GLuint buffer = gen_buffer(
59         sizeof(GLfloat) * 6 * components * faces, data);
60     free(data);
61     return buffer;
62 }
63 
make_shader(GLenum type,const char * source)64 GLuint make_shader(GLenum type, const char *source) {
65     GLuint shader = glCreateShader(type);
66     glShaderSource(shader, 1, &source, NULL);
67     glCompileShader(shader);
68     GLint status;
69     glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
70     if (status == GL_FALSE) {
71         GLint length;
72         glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
73         GLchar *info = calloc(length, sizeof(GLchar));
74         glGetShaderInfoLog(shader, length, NULL, info);
75         fprintf(stderr, "glCompileShader failed:\n%s\n", info);
76         free(info);
77     }
78     return shader;
79 }
80 
load_shader(GLenum type,const char * path)81 GLuint load_shader(GLenum type, const char *path) {
82     char *data = load_file(path);
83     GLuint result = make_shader(type, data);
84     free(data);
85     return result;
86 }
87 
make_program(GLuint shader1,GLuint shader2)88 GLuint make_program(GLuint shader1, GLuint shader2) {
89     GLuint program = glCreateProgram();
90     glAttachShader(program, shader1);
91     glAttachShader(program, shader2);
92     glLinkProgram(program);
93     GLint status;
94     glGetProgramiv(program, GL_LINK_STATUS, &status);
95     if (status == GL_FALSE) {
96         GLint length;
97         glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
98         GLchar *info = calloc(length, sizeof(GLchar));
99         glGetProgramInfoLog(program, length, NULL, info);
100         fprintf(stderr, "glLinkProgram failed: %s\n", info);
101         free(info);
102     }
103     glDetachShader(program, shader1);
104     glDetachShader(program, shader2);
105     glDeleteShader(shader1);
106     glDeleteShader(shader2);
107     return program;
108 }
109 
load_program(const char * path1,const char * path2)110 GLuint load_program(const char *path1, const char *path2) {
111     GLuint shader1 = load_shader(GL_VERTEX_SHADER, path1);
112     GLuint shader2 = load_shader(GL_FRAGMENT_SHADER, path2);
113     GLuint program = make_program(shader1, shader2);
114     return program;
115 }
116 
flip_image_vertical(unsigned char * data,unsigned int width,unsigned int height)117 void flip_image_vertical(
118     unsigned char *data, unsigned int width, unsigned int height)
119 {
120     unsigned int size = width * height * 4;
121     unsigned int stride = sizeof(char) * width * 4;
122     unsigned char *new_data = malloc(sizeof(unsigned char) * size);
123     for (unsigned int i = 0; i < height; i++) {
124         unsigned int j = height - i - 1;
125         memcpy(new_data + j * stride, data + i * stride, stride);
126     }
127     memcpy(data, new_data, size);
128     free(new_data);
129 }
130 
load_png_texture(const char * file_name)131 void load_png_texture(const char *file_name) {
132     unsigned int error;
133     unsigned char *data;
134     unsigned int width, height;
135     error = lodepng_decode32_file(&data, &width, &height, file_name);
136     if (error) {
137         fprintf(stderr, "error %u: %s\n", error, lodepng_error_text(error));
138     }
139     flip_image_vertical(data, width, height);
140     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
141         GL_UNSIGNED_BYTE, data);
142     free(data);
143 }
144 
tokenize(char * str,const char * delim,char ** key)145 char *tokenize(char *str, const char *delim, char **key) {
146     char *result;
147     if (str == NULL) {
148         str = *key;
149     }
150     str += strspn(str, delim);
151     if (*str == '\0') {
152         return NULL;
153     }
154     result = str;
155     str += strcspn(str, delim);
156     if (*str) {
157         *str++ = '\0';
158     }
159     *key = str;
160     return result;
161 }
162 
char_width(char input)163 int char_width(char input) {
164     static const int lookup[128] = {
165         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
166         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
167         4, 2, 4, 7, 6, 9, 7, 2, 3, 3, 4, 6, 3, 5, 2, 7,
168         6, 3, 6, 6, 6, 6, 6, 6, 6, 6, 2, 3, 5, 6, 5, 7,
169         8, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 6, 5, 8, 8, 6,
170         6, 7, 6, 6, 6, 6, 8,10, 8, 6, 6, 3, 6, 3, 6, 6,
171         4, 7, 6, 6, 6, 6, 5, 6, 6, 2, 5, 5, 2, 9, 6, 6,
172         6, 6, 6, 6, 5, 6, 6, 6, 6, 6, 6, 4, 2, 5, 7, 0
173     };
174     return lookup[input];
175 }
176 
string_width(const char * input)177 int string_width(const char *input) {
178     int result = 0;
179     int length = strlen(input);
180     for (int i = 0; i < length; i++) {
181         result += char_width(input[i]);
182     }
183     return result;
184 }
185 
wrap(const char * input,int max_width,char * output,int max_length)186 int wrap(const char *input, int max_width, char *output, int max_length) {
187     *output = '\0';
188     char *text = malloc(sizeof(char) * (strlen(input) + 1));
189     strcpy(text, input);
190     int space_width = char_width(' ');
191     int line_number = 0;
192     char *key1, *key2;
193     char *line = tokenize(text, "\r\n", &key1);
194     while (line) {
195         int line_width = 0;
196         char *token = tokenize(line, " ", &key2);
197         while (token) {
198             int token_width = string_width(token);
199             if (line_width) {
200                 if (line_width + token_width > max_width) {
201                     line_width = 0;
202                     line_number++;
203                     strncat(output, "\n", max_length - strlen(output) - 1);
204                 }
205                 else {
206                     strncat(output, " ", max_length - strlen(output) - 1);
207                 }
208             }
209             strncat(output, token, max_length - strlen(output) - 1);
210             line_width += token_width + space_width;
211             token = tokenize(NULL, " ", &key2);
212         }
213         line_number++;
214         strncat(output, "\n", max_length - strlen(output) - 1);
215         line = tokenize(NULL, "\r\n", &key1);
216     }
217     free(text);
218     return line_number;
219 }
220