236 lines
6.7 KiB
C
236 lines
6.7 KiB
C
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include "cube.h"
|
|
#include "lodepng.h"
|
|
#include "matrix.h"
|
|
#include "util.h"
|
|
|
|
int chunked(float x) {
|
|
return floorf(roundf(x) / CHUNK_SIZE);
|
|
}
|
|
|
|
int rand_int(int n) {
|
|
int result;
|
|
while (n <= (result = rand() / (RAND_MAX / n)));
|
|
return result;
|
|
}
|
|
|
|
double rand_double() {
|
|
return (double)rand() / (double)RAND_MAX;
|
|
}
|
|
|
|
void update_fps(FPS *fps) {
|
|
fps->frames++;
|
|
double now = glfwGetTime();
|
|
double elapsed = now - fps->since;
|
|
if (elapsed >= 1) {
|
|
fps->fps = round(fps->frames / elapsed);
|
|
fps->frames = 0;
|
|
fps->since = now;
|
|
}
|
|
}
|
|
|
|
char *load_file(const char *path) {
|
|
FILE *file = fopen(path, "rb");
|
|
if (!file) {
|
|
fprintf(stderr, "fopen %s failed: %d %s\n", path, errno, strerror(errno));
|
|
exit(1);
|
|
}
|
|
fseek(file, 0, SEEK_END);
|
|
int length = ftell(file);
|
|
rewind(file);
|
|
char *data = calloc(length + 1, sizeof(char));
|
|
if(fread(data, 1, length, file) != length) {
|
|
fprintf(stderr, "fread failed to read desired length\n");
|
|
exit(-1);
|
|
}
|
|
fclose(file);
|
|
return data;
|
|
}
|
|
|
|
GLuint gen_buffer(GLsizei size, GLfloat *data) {
|
|
GLuint buffer;
|
|
glGenBuffers(1, &buffer);
|
|
glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
|
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
return buffer;
|
|
}
|
|
|
|
void del_buffer(GLuint buffer) {
|
|
if(buffer) {
|
|
glDeleteBuffers(1, &buffer);
|
|
}
|
|
}
|
|
|
|
GLfloat *malloc_faces(int components, int faces) {
|
|
return malloc(sizeof(GLfloat) * 6 * components * faces);
|
|
}
|
|
|
|
GLuint gen_faces(int components, int faces, GLfloat *data) {
|
|
GLuint buffer = gen_buffer(
|
|
sizeof(GLfloat) * 6 * components * faces, data);
|
|
free(data);
|
|
return buffer;
|
|
}
|
|
|
|
GLuint make_shader(GLenum type, const char *source) {
|
|
GLuint shader = glCreateShader(type);
|
|
glShaderSource(shader, 1, &source, NULL);
|
|
glCompileShader(shader);
|
|
GLint status;
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
|
if (status == GL_FALSE) {
|
|
GLint length;
|
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
|
|
GLchar *info = calloc(length, sizeof(GLchar));
|
|
glGetShaderInfoLog(shader, length, NULL, info);
|
|
fprintf(stderr, "glCompileShader failed:\n%s\n", info);
|
|
free(info);
|
|
}
|
|
return shader;
|
|
}
|
|
|
|
GLuint load_shader(GLenum type, const char *path) {
|
|
char *data = load_file(path);
|
|
GLuint result = make_shader(type, data);
|
|
free(data);
|
|
return result;
|
|
}
|
|
|
|
GLuint make_program(GLuint shader1, GLuint shader2) {
|
|
GLuint program = glCreateProgram();
|
|
glAttachShader(program, shader1);
|
|
glAttachShader(program, shader2);
|
|
glLinkProgram(program);
|
|
GLint status;
|
|
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
|
if (status == GL_FALSE) {
|
|
GLint length;
|
|
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
|
|
GLchar *info = calloc(length, sizeof(GLchar));
|
|
glGetProgramInfoLog(program, length, NULL, info);
|
|
fprintf(stderr, "glLinkProgram failed: %s\n", info);
|
|
free(info);
|
|
}
|
|
glDetachShader(program, shader1);
|
|
glDetachShader(program, shader2);
|
|
glDeleteShader(shader1);
|
|
glDeleteShader(shader2);
|
|
return program;
|
|
}
|
|
|
|
GLuint load_program(const char *path1, const char *path2) {
|
|
GLuint shader1 = load_shader(GL_VERTEX_SHADER, path1);
|
|
GLuint shader2 = load_shader(GL_FRAGMENT_SHADER, path2);
|
|
GLuint program = make_program(shader1, shader2);
|
|
return program;
|
|
}
|
|
|
|
void flip_image_vertical(
|
|
unsigned char *data, unsigned int width, unsigned int height)
|
|
{
|
|
unsigned int size = width * height * 4;
|
|
unsigned int stride = sizeof(char) * width * 4;
|
|
unsigned char *new_data = malloc(sizeof(unsigned char) * size);
|
|
for (unsigned int i = 0; i < height; i++) {
|
|
unsigned int j = height - i - 1;
|
|
memcpy(new_data + j * stride, data + i * stride, stride);
|
|
}
|
|
memcpy(data, new_data, size);
|
|
free(new_data);
|
|
}
|
|
|
|
void load_png_texture(const char *file_name) {
|
|
unsigned int error;
|
|
unsigned char *data;
|
|
unsigned int width, height;
|
|
error = lodepng_decode32_file(&data, &width, &height, file_name);
|
|
if (error) {
|
|
fprintf(stderr, "load_png_texture %s failed, error %u: %s\n", file_name, error, lodepng_error_text(error));
|
|
exit(1);
|
|
}
|
|
flip_image_vertical(data, width, height);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
|
|
GL_UNSIGNED_BYTE, data);
|
|
free(data);
|
|
}
|
|
|
|
char *tokenize(char *str, const char *delim, char **key) {
|
|
char *result;
|
|
if (str == NULL) {
|
|
str = *key;
|
|
}
|
|
str += strspn(str, delim);
|
|
if (*str == '\0') {
|
|
return NULL;
|
|
}
|
|
result = str;
|
|
str += strcspn(str, delim);
|
|
if (*str) {
|
|
*str++ = '\0';
|
|
}
|
|
*key = str;
|
|
return result;
|
|
}
|
|
|
|
int char_width(char input) {
|
|
static const int lookup[128] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
4, 2, 4, 7, 6, 9, 7, 2, 3, 3, 4, 6, 3, 5, 2, 7,
|
|
6, 3, 6, 6, 6, 6, 6, 6, 6, 6, 2, 3, 5, 6, 5, 7,
|
|
8, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 6, 5, 8, 8, 6,
|
|
6, 7, 6, 6, 6, 6, 8,10, 8, 6, 6, 3, 6, 3, 6, 6,
|
|
4, 7, 6, 6, 6, 6, 5, 6, 6, 2, 5, 5, 2, 9, 6, 6,
|
|
6, 6, 6, 6, 5, 6, 6, 6, 6, 6, 6, 4, 2, 5, 7, 0
|
|
};
|
|
return lookup[input];
|
|
}
|
|
|
|
int string_width(const char *input) {
|
|
int result = 0;
|
|
int length = strlen(input);
|
|
for (int i = 0; i < length; i++) {
|
|
result += char_width(input[i]);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int wrap(const char *input, int max_width, char *output, int max_length) {
|
|
*output = '\0';
|
|
char *text = malloc(sizeof(char) * (strlen(input) + 1));
|
|
strcpy(text, input);
|
|
int space_width = char_width(' ');
|
|
int line_number = 0;
|
|
char *key1, *key2;
|
|
char *line = tokenize(text, "\r\n", &key1);
|
|
while (line) {
|
|
int line_width = 0;
|
|
char *token = tokenize(line, " ", &key2);
|
|
while (token) {
|
|
int token_width = string_width(token);
|
|
if (line_width) {
|
|
if (line_width + token_width > max_width) {
|
|
line_width = 0;
|
|
line_number++;
|
|
strncat(output, "\n", max_length - strlen(output) - 1);
|
|
}
|
|
else {
|
|
strncat(output, " ", max_length - strlen(output) - 1);
|
|
}
|
|
}
|
|
strncat(output, token, max_length - strlen(output) - 1);
|
|
line_width += token_width + space_width;
|
|
token = tokenize(NULL, " ", &key2);
|
|
}
|
|
line_number++;
|
|
strncat(output, "\n", max_length - strlen(output) - 1);
|
|
line = tokenize(NULL, "\r\n", &key1);
|
|
}
|
|
free(text);
|
|
return line_number;
|
|
}
|