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