Add MLX42 V2
This commit is contained in:
3543
MLX42/src/font/font.h
Normal file
3543
MLX42/src/font/font.h
Normal file
File diff suppressed because it is too large
Load Diff
80
MLX42/src/font/mlx_font.c
Normal file
80
MLX42/src/font/mlx_font.c
Normal file
@ -0,0 +1,80 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* :::::::: */
|
||||
/* mlx_font.c :+: :+: */
|
||||
/* +:+ */
|
||||
/* By: W2Wizard <w2.wizzard@gmail.com> +#+ */
|
||||
/* +#+ */
|
||||
/* Created: 2022/02/22 12:01:37 by W2Wizard #+# #+# */
|
||||
/* Updated: 2022/06/27 19:53:36 by lde-la-h ######## odam.nl */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "font.h"
|
||||
#include "MLX42/MLX42_Int.h"
|
||||
|
||||
//= Private =//
|
||||
|
||||
/**
|
||||
* Does the actual copying of pixels form the atlas buffer to the
|
||||
* image buffer.
|
||||
*
|
||||
* Skips any non-printable characters.
|
||||
*
|
||||
* @param image The image to draw on.
|
||||
* @param texture The font_atlas.
|
||||
* @param texoffset The character texture X offset.
|
||||
* @param imgoffset The image X offset.
|
||||
*/
|
||||
static void mlx_draw_char(mlx_image_t* image, int32_t texoffset, int32_t imgoffset)
|
||||
{
|
||||
if (texoffset < 0)
|
||||
return;
|
||||
|
||||
char* pixelx;
|
||||
uint8_t* pixeli;
|
||||
for (uint32_t y = 0; y < FONT_HEIGHT; y++)
|
||||
{
|
||||
pixelx = &font_atlas.pixels[(y * font_atlas.width + texoffset) * BPP];
|
||||
pixeli = image->pixels + ((y * image->width + imgoffset) * BPP);
|
||||
memcpy(pixeli, pixelx, FONT_WIDTH * BPP);
|
||||
}
|
||||
}
|
||||
|
||||
//= Public =//
|
||||
|
||||
const mlx_texture_t* mlx_get_font(void)
|
||||
{
|
||||
return ((const mlx_texture_t*)&font_atlas);
|
||||
}
|
||||
|
||||
int32_t mlx_get_texoffset(char c)
|
||||
{
|
||||
const bool _isprint = isprint(c);
|
||||
|
||||
// NOTE: Cheesy branchless operation :D
|
||||
// +2 To skip line separator in texture
|
||||
return (-1 * !_isprint + ((FONT_WIDTH + 2) * (c - 32)) * _isprint);
|
||||
}
|
||||
|
||||
mlx_image_t* mlx_put_string(mlx_t* mlx, const char* str, int32_t x, int32_t y)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
MLX_NONNULL(str);
|
||||
|
||||
mlx_image_t* strimage;
|
||||
const size_t len = strlen(str);
|
||||
if (len > MLX_MAX_STRING)
|
||||
return ((void*)mlx_error(MLX_STRTOOBIG));
|
||||
if (!(strimage = mlx_new_image(mlx, len * FONT_WIDTH, FONT_HEIGHT)))
|
||||
return (NULL);
|
||||
|
||||
// Draw the text itself
|
||||
int32_t imgoffset = 0;
|
||||
for (size_t i = 0; i < len; i++, imgoffset += FONT_WIDTH)
|
||||
mlx_draw_char(strimage, mlx_get_texoffset(str[i]), imgoffset);
|
||||
|
||||
if (mlx_image_to_window(mlx, strimage, x, y) == -1)
|
||||
return (mlx_delete_image(mlx, strimage), NULL);
|
||||
return (strimage);
|
||||
}
|
63
MLX42/src/mlx_cursor.c
Normal file
63
MLX42/src/mlx_cursor.c
Normal file
@ -0,0 +1,63 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* :::::::: */
|
||||
/* mlx_cursor.c :+: :+: */
|
||||
/* +:+ */
|
||||
/* By: W2Wizard <main@w2wizard.dev> +#+ */
|
||||
/* +#+ */
|
||||
/* Created: 2022/01/18 20:10:54 by W2Wizard #+# #+# */
|
||||
/* Updated: 2023/03/09 11:11:45 by W2Wizard ######## odam.nl */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "MLX42/MLX42_Int.h"
|
||||
|
||||
//= Public =//
|
||||
|
||||
mlx_win_cursor_t* mlx_create_std_cursor(cursor_t type)
|
||||
{
|
||||
MLX_ASSERT(type >= MLX_CURSOR_ARROW && type < MLX_CURSOR_VRESIZE, "Invalid standard cursor type");
|
||||
|
||||
GLFWcursor* cursor;
|
||||
if ((cursor = glfwCreateStandardCursor(type)))
|
||||
return (cursor);
|
||||
return ((void *)mlx_error(MLX_MEMFAIL));
|
||||
}
|
||||
|
||||
mlx_win_cursor_t* mlx_create_cursor(mlx_texture_t* texture)
|
||||
{
|
||||
MLX_NONNULL(texture);
|
||||
|
||||
GLFWcursor* cursor;
|
||||
GLFWimage image = (GLFWimage) {
|
||||
.width = texture->width,
|
||||
.height = texture->height,
|
||||
.pixels = texture->pixels
|
||||
};
|
||||
|
||||
if ((cursor = glfwCreateCursor(&image, 0, 0)))
|
||||
return (cursor);
|
||||
return ((void *)mlx_error(MLX_MEMFAIL));
|
||||
}
|
||||
|
||||
void mlx_destroy_cursor(mlx_win_cursor_t* cursor)
|
||||
{
|
||||
MLX_NONNULL(cursor);
|
||||
|
||||
glfwDestroyCursor(cursor);
|
||||
}
|
||||
|
||||
void mlx_set_cursor(mlx_t* mlx, mlx_win_cursor_t* cursor)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
MLX_NONNULL(cursor);
|
||||
|
||||
glfwSetCursor(mlx->window, cursor);
|
||||
}
|
||||
|
||||
void mlx_set_cursor_mode(mlx_t* mlx, mouse_mode_t mode)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
|
||||
glfwSetInputMode(mlx->window, GLFW_CURSOR, mode);
|
||||
}
|
47
MLX42/src/mlx_exit.c
Normal file
47
MLX42/src/mlx_exit.c
Normal file
@ -0,0 +1,47 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* :::::::: */
|
||||
/* mlx_exit.c :+: :+: */
|
||||
/* +:+ */
|
||||
/* By: W2Wizard <w2.wizzard@gmail.com> +#+ */
|
||||
/* +#+ */
|
||||
/* Created: 2021/12/28 02:43:22 by W2Wizard #+# #+# */
|
||||
/* Updated: 2022/11/26 14:23:55 by jvan-hal ######## odam.nl */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "MLX42/MLX42_Int.h"
|
||||
|
||||
//= Private =//
|
||||
|
||||
static void mlx_free_image(void* content)
|
||||
{
|
||||
mlx_image_t* img = content;
|
||||
|
||||
mlx_freen(4, img->context, img->pixels, img->instances, img);
|
||||
}
|
||||
|
||||
//= Public =//
|
||||
|
||||
void mlx_close_window(mlx_t* mlx)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
glfwSetWindowShouldClose(mlx->window, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* All of glfw & glads resources are cleaned up by the terminate function.
|
||||
* Now it's time to clean up our own mess.
|
||||
*/
|
||||
void mlx_terminate(mlx_t* mlx)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
|
||||
mlx_ctx_t *const mlxctx = mlx->context;
|
||||
|
||||
glfwTerminate();
|
||||
mlx_lstclear((mlx_list_t**)(&mlxctx->hooks), &free);
|
||||
mlx_lstclear((mlx_list_t**)(&mlxctx->render_queue), &free);
|
||||
mlx_lstclear((mlx_list_t**)(&mlxctx->images), &mlx_free_image);
|
||||
mlx_freen(2, mlxctx, mlx);
|
||||
}
|
251
MLX42/src/mlx_images.c
Normal file
251
MLX42/src/mlx_images.c
Normal file
@ -0,0 +1,251 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* :::::::: */
|
||||
/* mlx_images.c :+: :+: */
|
||||
/* +:+ */
|
||||
/* By: W2Wizard <main@w2wizard.dev> +#+ */
|
||||
/* +#+ */
|
||||
/* Created: 2021/12/28 02:29:06 by W2Wizard #+# #+# */
|
||||
/* Updated: 2023/03/30 16:36:39 by ntamayo- ######## odam.nl */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "MLX42/MLX42_Int.h"
|
||||
|
||||
//= Private =//
|
||||
|
||||
void mlx_flush_batch(mlx_ctx_t* mlx)
|
||||
{
|
||||
if (mlx->batch_size <= 0)
|
||||
return;
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mlx->vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, mlx->batch_size * sizeof(vertex_t), mlx->batch_vertices, GL_STATIC_DRAW);
|
||||
glDrawArrays(GL_TRIANGLES, 0, mlx->batch_size);
|
||||
|
||||
mlx->batch_size = 0;
|
||||
memset(mlx->bound_textures, 0, sizeof(mlx->bound_textures));
|
||||
}
|
||||
|
||||
static int8_t mlx_bind_texture(mlx_ctx_t* mlx, mlx_image_t* img)
|
||||
{
|
||||
const GLint handle = (GLint)((mlx_image_ctx_t*)img->context)->texture;
|
||||
|
||||
// Attempt to bind the texture, or obtain the index if it is already bound.
|
||||
for (int8_t i = 0; i < 16; i++)
|
||||
{
|
||||
if (mlx->bound_textures[i] == handle)
|
||||
return (i);
|
||||
|
||||
if (mlx->bound_textures[i] == 0)
|
||||
{
|
||||
mlx->bound_textures[i] = handle;
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
glBindTexture(GL_TEXTURE_2D, handle);
|
||||
return (i);
|
||||
}
|
||||
}
|
||||
|
||||
// If no free slot was found, flush the batch and assign the texture to the first available slot
|
||||
mlx_flush_batch(mlx);
|
||||
|
||||
mlx->bound_textures[0] = handle;
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, handle);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to draw a single instance of an image
|
||||
* to the screen.
|
||||
*/
|
||||
void mlx_draw_instance(mlx_ctx_t* mlx, mlx_image_t* img, mlx_instance_t* instance)
|
||||
{
|
||||
float w = (float) img->width;
|
||||
float h = (float) img->height;
|
||||
float x = (float) instance->x;
|
||||
float y = (float) instance->y;
|
||||
float z = (float) instance->z;
|
||||
int8_t tex = mlx_bind_texture(mlx, img);
|
||||
|
||||
vertex_t vertices[6] = {
|
||||
(vertex_t){x, y, z, 0.f, 0.f, tex},
|
||||
(vertex_t){x + w, y + h, z, 1.f, 1.f, tex},
|
||||
(vertex_t){x + w, y, z, 1.f, 0.f, tex},
|
||||
(vertex_t){x, y, z, 0.f, 0.f, tex},
|
||||
(vertex_t){x, y + h, z, 0.f, 1.f, tex},
|
||||
(vertex_t){x + w, y + h, z, 1.f, 1.f, tex},
|
||||
};
|
||||
memmove(mlx->batch_vertices + mlx->batch_size, vertices, sizeof(vertices));
|
||||
mlx->batch_size += 6;
|
||||
|
||||
if (mlx->batch_size >= MLX_BATCH_SIZE)
|
||||
mlx_flush_batch(mlx);
|
||||
}
|
||||
|
||||
mlx_instance_t* mlx_grow_instances(mlx_image_t* img, bool* did_realloc)
|
||||
{
|
||||
mlx_image_ctx_t* const ctx = img->context;
|
||||
if (img->count >= ctx->instances_capacity)
|
||||
{
|
||||
if (ctx->instances_capacity == 0)
|
||||
ctx->instances_capacity = img->count;
|
||||
else
|
||||
ctx->instances_capacity *= 2;
|
||||
*did_realloc = true;
|
||||
return realloc(img->instances, ctx->instances_capacity * sizeof(mlx_instance_t));
|
||||
}
|
||||
*did_realloc = false;
|
||||
return img->instances;
|
||||
}
|
||||
|
||||
//= Public =//
|
||||
|
||||
void mlx_set_instance_depth(mlx_instance_t* instance, int32_t zdepth)
|
||||
{
|
||||
MLX_NONNULL(instance);
|
||||
|
||||
if (instance->z == zdepth)
|
||||
return;
|
||||
instance->z = zdepth;
|
||||
|
||||
/**
|
||||
* NOTE: The reason why we don't sort directly is that
|
||||
* the user might call this function multiple times in a row and we don't
|
||||
* want to sort for every change. Pre-loop wise that is.
|
||||
*/
|
||||
sort_queue = true;
|
||||
}
|
||||
|
||||
int32_t mlx_image_to_window(mlx_t* mlx, mlx_image_t* img, int32_t x, int32_t y)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
MLX_NONNULL(img);
|
||||
|
||||
// Allocate buffers...
|
||||
img->count++;
|
||||
bool did_realloc;
|
||||
mlx_instance_t* instances = mlx_grow_instances(img, &did_realloc);
|
||||
draw_queue_t* queue = calloc(1, sizeof(draw_queue_t));
|
||||
if (!instances || !queue)
|
||||
{
|
||||
if (did_realloc)
|
||||
free(instances);
|
||||
return (free(queue), mlx_error(MLX_MEMFAIL), -1);
|
||||
}
|
||||
|
||||
// Set data...
|
||||
queue->image = img;
|
||||
int32_t index = queue->instanceid = img->count - 1;
|
||||
img->instances = instances;
|
||||
img->instances[index].x = x;
|
||||
img->instances[index].y = y;
|
||||
|
||||
// NOTE: We keep updating the Z for the convenience of the user.
|
||||
// Always update Z depth to prevent overlapping images by default.
|
||||
img->instances[index].z = ((mlx_ctx_t*)mlx->context)->zdepth++;
|
||||
img->instances[index].enabled = true;
|
||||
|
||||
// Add draw call...
|
||||
sort_queue = true;
|
||||
mlx_list_t* templst;
|
||||
if ((templst = mlx_lstnew(queue)))
|
||||
{
|
||||
mlx_lstadd_front(&((mlx_ctx_t*)mlx->context)->render_queue, templst);
|
||||
return (index);
|
||||
}
|
||||
return (mlx_freen(2, instances, queue), mlx_error(MLX_MEMFAIL), -1);
|
||||
}
|
||||
|
||||
mlx_image_t* mlx_new_image(mlx_t* mlx, uint32_t width, uint32_t height)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
|
||||
if (!width || !height || width > INT16_MAX || height > INT16_MAX)
|
||||
return ((void*)mlx_error(MLX_INVDIM));
|
||||
|
||||
const mlx_ctx_t* mlxctx = mlx->context;
|
||||
mlx_image_t* newimg = calloc(1, sizeof(mlx_image_t));
|
||||
mlx_image_ctx_t* newctx = calloc(1, sizeof(mlx_image_ctx_t));
|
||||
if (!newimg || !newctx)
|
||||
{
|
||||
mlx_freen(2, newimg, newctx);
|
||||
return ((void *)mlx_error(MLX_MEMFAIL));
|
||||
}
|
||||
newimg->enabled = true;
|
||||
newimg->context = newctx;
|
||||
(*(uint32_t*)&newimg->width) = width;
|
||||
(*(uint32_t*)&newimg->height) = height;
|
||||
if (!(newimg->pixels = calloc(width * height, sizeof(int32_t))))
|
||||
{
|
||||
mlx_freen(2, newimg, newctx);
|
||||
return ((void *)mlx_error(MLX_MEMFAIL));
|
||||
}
|
||||
|
||||
mlx_list_t* newentry;
|
||||
if (!(newentry = mlx_lstnew(newimg)))
|
||||
{
|
||||
mlx_freen(3, newimg->pixels, newimg->context, newimg);
|
||||
return ((void *)mlx_error(MLX_MEMFAIL));
|
||||
}
|
||||
|
||||
// Generate OpenGL texture
|
||||
glGenTextures(1, &newctx->texture);
|
||||
glBindTexture(GL_TEXTURE_2D, newctx->texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
mlx_lstadd_front((mlx_list_t**)(&mlxctx->images), newentry);
|
||||
return (newimg);
|
||||
}
|
||||
|
||||
void mlx_delete_image(mlx_t* mlx, mlx_image_t* image)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
MLX_NONNULL(image);
|
||||
|
||||
mlx_ctx_t* mlxctx = mlx->context;
|
||||
|
||||
// Delete all instances in the render queue
|
||||
mlx_list_t* quelst;
|
||||
while ((quelst = mlx_lstremove(&mlxctx->render_queue, image, &mlx_equal_inst)))
|
||||
mlx_freen(2, quelst->content, quelst);
|
||||
|
||||
mlx_list_t* imglst;
|
||||
if ((imglst = mlx_lstremove(&mlxctx->images, image, &mlx_equal_image)))
|
||||
{
|
||||
glDeleteTextures(1, &((mlx_image_ctx_t*)image->context)->texture);
|
||||
mlx_freen(5, image->pixels, image->instances, image->context, imglst, image);
|
||||
}
|
||||
}
|
||||
|
||||
bool mlx_resize_image(mlx_image_t* img, uint32_t nwidth, uint32_t nheight)
|
||||
{
|
||||
MLX_NONNULL(img);
|
||||
|
||||
if (!nwidth || !nheight || nwidth > INT16_MAX || nheight > INT16_MAX)
|
||||
return (mlx_error(MLX_INVDIM));
|
||||
if (nwidth != img->width || nheight != img->height)
|
||||
{
|
||||
uint32_t* origin = (uint32_t*)img->pixels;
|
||||
float wstep = (float)img->width / nwidth;
|
||||
float hstep = (float)img->height / nheight;
|
||||
|
||||
uint8_t* tempbuff = calloc(nwidth * nheight, BPP);
|
||||
if (!tempbuff)
|
||||
return (mlx_error(MLX_MEMFAIL));
|
||||
img->pixels = tempbuff;
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, nwidth, nheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, img->pixels);
|
||||
|
||||
uint32_t* destin = (uint32_t*)img->pixels;
|
||||
for (uint32_t j = 0; j < nheight; j++)
|
||||
for (uint32_t i = 0; i < nwidth; i++)
|
||||
destin[j * nwidth + i] = origin[(uint32_t)(j * hstep) * img->width + (uint32_t)(i * wstep)];
|
||||
(*(uint32_t*)&img->width) = nwidth;
|
||||
(*(uint32_t*)&img->height) = nheight;
|
||||
free(origin);
|
||||
}
|
||||
return (true);
|
||||
}
|
195
MLX42/src/mlx_init.c
Normal file
195
MLX42/src/mlx_init.c
Normal file
@ -0,0 +1,195 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* :::::::: */
|
||||
/* mlx_init.c :+: :+: */
|
||||
/* +:+ */
|
||||
/* By: W2Wizard <main@w2wizard.dev> +#+ */
|
||||
/* +#+ */
|
||||
/* Created: 2021/12/28 00:24:30 by W2Wizard #+# #+# */
|
||||
/* Updated: 2023/02/13 11:36:27 by W2Wizard ######## odam.nl */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "MLX42/MLX42_Int.h"
|
||||
|
||||
//= Private =//
|
||||
|
||||
static void framebuffer_callback(GLFWwindow *window, int width, int height)
|
||||
{
|
||||
(void)window;
|
||||
glViewport(0, 0, width, height);
|
||||
}
|
||||
|
||||
static bool mlx_create_buffers(mlx_t* mlx)
|
||||
{
|
||||
mlx_ctx_t* mlxctx = mlx->context;
|
||||
|
||||
mlxctx->zdepth = 0;
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glGenVertexArrays(1, &(mlxctx->vao));
|
||||
glGenBuffers(1, &(mlxctx->vbo));
|
||||
glBindVertexArray(mlxctx->vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mlxctx->vbo);
|
||||
|
||||
// Vertex XYZ coordinates
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertex_t), NULL);
|
||||
glEnableVertexAttribArray(0);
|
||||
|
||||
// UV Coordinates
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (void *)(sizeof(float) * 3));
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
// Texture index
|
||||
glVertexAttribIPointer(2, 1, GL_BYTE, sizeof(vertex_t), (void *)(sizeof(float) * 5));
|
||||
glEnableVertexAttribArray(2);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glUniform1i(glGetUniformLocation(mlxctx->shaderprogram, "Texture0"), 0);
|
||||
glUniform1i(glGetUniformLocation(mlxctx->shaderprogram, "Texture1"), 1);
|
||||
glUniform1i(glGetUniformLocation(mlxctx->shaderprogram, "Texture2"), 2);
|
||||
glUniform1i(glGetUniformLocation(mlxctx->shaderprogram, "Texture3"), 3);
|
||||
glUniform1i(glGetUniformLocation(mlxctx->shaderprogram, "Texture4"), 4);
|
||||
glUniform1i(glGetUniformLocation(mlxctx->shaderprogram, "Texture5"), 5);
|
||||
glUniform1i(glGetUniformLocation(mlxctx->shaderprogram, "Texture6"), 6);
|
||||
glUniform1i(glGetUniformLocation(mlxctx->shaderprogram, "Texture7"), 7);
|
||||
glUniform1i(glGetUniformLocation(mlxctx->shaderprogram, "Texture8"), 8);
|
||||
glUniform1i(glGetUniformLocation(mlxctx->shaderprogram, "Texture9"), 9);
|
||||
glUniform1i(glGetUniformLocation(mlxctx->shaderprogram, "Texture10"), 10);
|
||||
glUniform1i(glGetUniformLocation(mlxctx->shaderprogram, "Texture11"), 11);
|
||||
glUniform1i(glGetUniformLocation(mlxctx->shaderprogram, "Texture12"), 12);
|
||||
glUniform1i(glGetUniformLocation(mlxctx->shaderprogram, "Texture13"), 13);
|
||||
glUniform1i(glGetUniformLocation(mlxctx->shaderprogram, "Texture14"), 14);
|
||||
glUniform1i(glGetUniformLocation(mlxctx->shaderprogram, "Texture15"), 15);
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the given shader source code of a given shader type.
|
||||
* Returns shader object via param.
|
||||
*
|
||||
* @param code The shader source code.
|
||||
* @param Type GL_VERTEX_SHADER, GL_FRAGMENT_SHADER, GL_GEOMETRY_SHADER, ...
|
||||
* @return Non-zero on success, else 0.
|
||||
*/
|
||||
static uint32_t mlx_compile_shader(const char* code, int32_t type)
|
||||
{
|
||||
GLuint shader;
|
||||
int32_t success;
|
||||
char infolog[512] = {0};
|
||||
|
||||
if (!code || (shader = glCreateShader(type)) == 0)
|
||||
return (0);
|
||||
|
||||
GLint len = strlen(code);
|
||||
glShaderSource(shader, 1, &code, &len);
|
||||
glCompileShader(shader);
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||||
if (!success)
|
||||
{
|
||||
glGetShaderInfoLog(shader, sizeof(infolog), NULL, infolog);
|
||||
fprintf(stderr, "%s", infolog);
|
||||
return (0);
|
||||
}
|
||||
return (shader);
|
||||
}
|
||||
|
||||
static bool mlx_init_render(mlx_t* mlx)
|
||||
{
|
||||
uint32_t vshader = 0;
|
||||
uint32_t fshader = 0;
|
||||
char infolog[512] = {0};
|
||||
mlx_ctx_t* mlxctx = mlx->context;
|
||||
|
||||
glfwMakeContextCurrent(mlx->window);
|
||||
glfwSetFramebufferSizeCallback(mlx->window, framebuffer_callback);
|
||||
glfwSetWindowUserPointer(mlx->window, mlx);
|
||||
glfwSwapInterval(MLX_SWAP_INTERVAL);
|
||||
|
||||
// Load all OpenGL function pointers
|
||||
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
|
||||
return (mlx_error(MLX_GLADFAIL));
|
||||
|
||||
if (!(vshader = mlx_compile_shader(vert_shader, GL_VERTEX_SHADER)))
|
||||
return (mlx_error(MLX_VERTFAIL));
|
||||
if (!(fshader = mlx_compile_shader(frag_shader, GL_FRAGMENT_SHADER)))
|
||||
return (mlx_error(MLX_FRAGFAIL));
|
||||
if (!(mlxctx->shaderprogram = glCreateProgram()))
|
||||
return (mlx_error(MLX_SHDRFAIL));
|
||||
glAttachShader(mlxctx->shaderprogram, vshader);
|
||||
glAttachShader(mlxctx->shaderprogram, fshader);
|
||||
glLinkProgram(mlxctx->shaderprogram);
|
||||
|
||||
int32_t success;
|
||||
glGetProgramiv(mlxctx->shaderprogram, GL_LINK_STATUS, &success);
|
||||
if (!success)
|
||||
{
|
||||
glGetProgramInfoLog(mlxctx->shaderprogram, sizeof(infolog), NULL, infolog);
|
||||
fprintf(stderr, "%s", infolog);
|
||||
return (mlx_error(MLX_SHDRFAIL));
|
||||
}
|
||||
glDeleteShader(vshader);
|
||||
glDeleteShader(fshader);
|
||||
glUseProgram(mlxctx->shaderprogram);
|
||||
|
||||
for (size_t i = 0; i < 16; i++)
|
||||
mlxctx->bound_textures[i] = 0;
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
//= Public =//
|
||||
|
||||
// NOTE: https://www.glfw.org/docs/3.3/group__window.html
|
||||
|
||||
// Default settings
|
||||
int32_t mlx_settings[MLX_SETTINGS_MAX] = {false, false, false, true, false};
|
||||
mlx_errno_t mlx_errno = MLX_SUCCESS;
|
||||
bool sort_queue = false;
|
||||
|
||||
mlx_t* mlx_init(int32_t width, int32_t height, const char* title, bool resize)
|
||||
{
|
||||
MLX_NONNULL(title);
|
||||
MLX_ASSERT(width > 0, "Window width must be positive");
|
||||
MLX_ASSERT(height > 0, "Window height must be positive");
|
||||
|
||||
bool init;
|
||||
mlx_t* mlx;
|
||||
if (!(init = glfwInit()))
|
||||
return ((void*)mlx_error(MLX_GLFWFAIL));
|
||||
if (!(mlx = calloc(1, sizeof(mlx_t))))
|
||||
return ((void*)mlx_error(MLX_MEMFAIL));
|
||||
if (!(mlx->context = calloc(1, sizeof(mlx_ctx_t))))
|
||||
return (free(mlx), (void*)mlx_error(MLX_MEMFAIL));
|
||||
|
||||
mlx_ctx_t* const mlxctx = mlx->context;
|
||||
mlx->width = width;
|
||||
mlx->height = height;
|
||||
mlxctx->initialWidth = width;
|
||||
mlxctx->initialHeight = height;
|
||||
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_MAXIMIZED, mlx_settings[MLX_MAXIMIZED]);
|
||||
glfwWindowHint(GLFW_DECORATED, mlx_settings[MLX_DECORATED]);
|
||||
glfwWindowHint(GLFW_VISIBLE, !mlx_settings[MLX_HEADLESS]);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
#ifdef __APPLE__
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||
#endif
|
||||
glfwWindowHint(GLFW_RESIZABLE, resize);
|
||||
if (!(mlx->window = glfwCreateWindow(width, height, title, mlx_settings[MLX_FULLSCREEN] ? glfwGetPrimaryMonitor() : NULL, NULL)))
|
||||
return (mlx_terminate(mlx), (void*)mlx_error(MLX_WINFAIL));
|
||||
if (!mlx_init_render(mlx) || !mlx_create_buffers(mlx))
|
||||
return (mlx_terminate(mlx), NULL);
|
||||
return (mlx);
|
||||
}
|
||||
|
||||
void mlx_set_setting(mlx_settings_t setting, int32_t value)
|
||||
{
|
||||
MLX_ASSERT(setting >= 0 && setting < MLX_SETTINGS_MAX, "Invalid settings value");
|
||||
mlx_settings[setting] = value;
|
||||
}
|
49
MLX42/src/mlx_keys.c
Normal file
49
MLX42/src/mlx_keys.c
Normal file
@ -0,0 +1,49 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* :::::::: */
|
||||
/* mlx_keys.c :+: :+: */
|
||||
/* +:+ */
|
||||
/* By: W2Wizard <main@w2wizard.dev> +#+ */
|
||||
/* +#+ */
|
||||
/* Created: 2022/01/01 21:06:45 by W2Wizard #+# #+# */
|
||||
/* Updated: 2023/02/13 12:24:40 by W2Wizard ######## odam.nl */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "MLX42/MLX42_Int.h"
|
||||
|
||||
//= Private =//
|
||||
|
||||
static void mlx_key_callback(GLFWwindow* window, int32_t key, int32_t scancode, int32_t action, int32_t mods)
|
||||
{
|
||||
const mlx_t* mlx = glfwGetWindowUserPointer(window);
|
||||
const mlx_key_t key_hook = ((mlx_ctx_t*)mlx->context)->key_hook;
|
||||
const mlx_key_data_t callback_data = {
|
||||
key,
|
||||
action,
|
||||
scancode,
|
||||
mods,
|
||||
};
|
||||
|
||||
key_hook.func(callback_data, key_hook.param);
|
||||
}
|
||||
|
||||
//= Public =//
|
||||
|
||||
void mlx_key_hook(mlx_t* mlx, mlx_keyfunc func, void* param)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
MLX_NONNULL(func);
|
||||
|
||||
mlx_ctx_t* mlxctx = mlx->context;
|
||||
mlxctx->key_hook.func = func;
|
||||
mlxctx->key_hook.param = param;
|
||||
glfwSetKeyCallback(mlx->window, mlx_key_callback);
|
||||
}
|
||||
|
||||
bool mlx_is_key_down(mlx_t* mlx, keys_t key)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
|
||||
return (glfwGetKey(mlx->window, key) == GLFW_PRESS);
|
||||
}
|
118
MLX42/src/mlx_loop.c
Normal file
118
MLX42/src/mlx_loop.c
Normal file
@ -0,0 +1,118 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* :::::::: */
|
||||
/* mlx_loop.c :+: :+: */
|
||||
/* +:+ */
|
||||
/* By: W2Wizard <main@w2wizard.dev> +#+ */
|
||||
/* +#+ */
|
||||
/* Created: 2021/12/28 01:24:36 by W2Wizard #+# #+# */
|
||||
/* Updated: 2023/03/28 16:34:17 by W2Wizard ######## odam.nl */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "MLX42/MLX42_Int.h"
|
||||
|
||||
//= Private =//
|
||||
|
||||
static void mlx_exec_loop_hooks(mlx_t* mlx)
|
||||
{
|
||||
const mlx_ctx_t* mlxctx = mlx->context;
|
||||
|
||||
mlx_list_t* lstcpy = mlxctx->hooks;
|
||||
while (lstcpy && !glfwWindowShouldClose(mlx->window))
|
||||
{
|
||||
mlx_hook_t* hook = ((mlx_hook_t*)lstcpy->content);
|
||||
hook->func(hook->param);
|
||||
lstcpy = lstcpy->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void mlx_render_images(mlx_t* mlx)
|
||||
{
|
||||
mlx_ctx_t* mlxctx = mlx->context;
|
||||
mlx_list_t* imglst = mlxctx->images;
|
||||
|
||||
if (sort_queue)
|
||||
{
|
||||
sort_queue = false;
|
||||
mlx_sort_renderqueue(&mlxctx->render_queue);
|
||||
}
|
||||
|
||||
// Upload image textures to GPU
|
||||
while (imglst)
|
||||
{
|
||||
mlx_image_t* image;
|
||||
if (!(image = imglst->content)) {
|
||||
mlx_error(MLX_INVIMG);
|
||||
return;
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, ((mlx_image_ctx_t*)image->context)->texture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image->width, image->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);
|
||||
imglst = imglst->next;
|
||||
}
|
||||
|
||||
// Execute draw calls
|
||||
mlx_list_t* render_queue = mlxctx->render_queue;
|
||||
while (render_queue)
|
||||
{
|
||||
draw_queue_t* drawcall = render_queue->content;
|
||||
mlx_instance_t* instance = &drawcall->image->instances[drawcall->instanceid];
|
||||
|
||||
if (drawcall && drawcall->image->enabled && instance->enabled)
|
||||
mlx_draw_instance(mlx->context, drawcall->image, instance);
|
||||
render_queue = render_queue->next;
|
||||
}
|
||||
}
|
||||
|
||||
//= Public =//
|
||||
|
||||
bool mlx_loop_hook(mlx_t* mlx, void (*f)(void*), void* param)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
MLX_NONNULL(f);
|
||||
|
||||
mlx_hook_t* hook;
|
||||
if (!(hook = malloc(sizeof(mlx_hook_t))))
|
||||
return (mlx_error(MLX_MEMFAIL));
|
||||
|
||||
mlx_list_t* lst;
|
||||
if (!(lst = mlx_lstnew(hook)))
|
||||
{
|
||||
free(hook);
|
||||
return (mlx_error(MLX_MEMFAIL));
|
||||
}
|
||||
hook->func = f;
|
||||
hook->param = param;
|
||||
const mlx_ctx_t *mlxctx = mlx->context;
|
||||
mlx_lstadd_back((mlx_list_t**)(&mlxctx->hooks), lst);
|
||||
return (true);
|
||||
}
|
||||
|
||||
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
void mlx_loop(mlx_t* mlx)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
|
||||
double start, oldstart = 0;
|
||||
while (!glfwWindowShouldClose(mlx->window))
|
||||
{
|
||||
start = glfwGetTime();
|
||||
mlx->delta_time = start - oldstart;
|
||||
oldstart = start;
|
||||
|
||||
glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glfwGetWindowSize(mlx->window, &(mlx->width), &(mlx->height));
|
||||
|
||||
if ((mlx->width > 1 || mlx->height > 1))
|
||||
mlx_update_matrix(mlx, mlx->width, mlx->height);
|
||||
|
||||
mlx_exec_loop_hooks(mlx);
|
||||
mlx_render_images(mlx);
|
||||
mlx_flush_batch(mlx->context);
|
||||
|
||||
glfwSwapBuffers(mlx->window);
|
||||
glfwPollEvents();
|
||||
}
|
||||
}
|
37
MLX42/src/mlx_monitor.c
Normal file
37
MLX42/src/mlx_monitor.c
Normal file
@ -0,0 +1,37 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* :::::::: */
|
||||
/* mlx_monitor.c :+: :+: */
|
||||
/* +:+ */
|
||||
/* By: W2Wizard <w2.wizzard@gmail.com> +#+ */
|
||||
/* +#+ */
|
||||
/* Created: 2022/01/19 17:18:59 by W2Wizard #+# #+# */
|
||||
/* Updated: 2022/06/27 20:02:38 by lde-la-h ######## odam.nl */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "MLX42/MLX42_Int.h"
|
||||
|
||||
//= Public =//
|
||||
|
||||
void mlx_get_monitor_size(int32_t index, int32_t* width, int32_t* height)
|
||||
{
|
||||
MLX_ASSERT(index >= 0, "Index out of bounds");
|
||||
MLX_NONNULL(width);
|
||||
MLX_NONNULL(height);
|
||||
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
|
||||
int32_t monitor_count;
|
||||
GLFWmonitor** monitors = glfwGetMonitors(&monitor_count);
|
||||
if (index > monitor_count || !monitors)
|
||||
return;
|
||||
|
||||
const GLFWvidmode* vidmode;
|
||||
if ((vidmode = glfwGetVideoMode(monitors[index])))
|
||||
{
|
||||
*width = vidmode->width;
|
||||
*height = vidmode->height;
|
||||
}
|
||||
}
|
100
MLX42/src/mlx_mouse.c
Normal file
100
MLX42/src/mlx_mouse.c
Normal file
@ -0,0 +1,100 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* :::::::: */
|
||||
/* mlx_mouse.c :+: :+: */
|
||||
/* +:+ */
|
||||
/* By: W2Wizard <w2.wizzard@gmail.com> +#+ */
|
||||
/* +#+ */
|
||||
/* Created: 2022/01/01 23:20:13 by W2Wizard #+# #+# */
|
||||
/* Updated: 2022/06/29 15:34:25 by lde-la-h ######## odam.nl */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "MLX42/MLX42_Int.h"
|
||||
|
||||
//= Private =//
|
||||
|
||||
static void mlx_scroll_cb(GLFWwindow* window, double xoffset, double yoffset)
|
||||
{
|
||||
const mlx_t* mlx = glfwGetWindowUserPointer(window);
|
||||
const mlx_scroll_t scroll_hook = ((mlx_ctx_t*)mlx->context)->scroll_hook;
|
||||
|
||||
scroll_hook.func(xoffset, yoffset, scroll_hook.param);
|
||||
}
|
||||
|
||||
static void mlx_mouse_cb(GLFWwindow* window, int32_t button, int32_t action, int32_t mods)
|
||||
{
|
||||
const mlx_t* mlx = glfwGetWindowUserPointer(window);
|
||||
const mlx_mouse_t mouse_hook = ((mlx_ctx_t*)mlx->context)->mouse_hook;
|
||||
|
||||
mouse_hook.func(button, action, mods, mouse_hook.param);
|
||||
}
|
||||
|
||||
static void mlx_cursor_cb(GLFWwindow* window, double xpos, double ypos)
|
||||
{
|
||||
const mlx_t* mlx = glfwGetWindowUserPointer(window);
|
||||
const mlx_cursor_t cursor_hook = ((mlx_ctx_t*)mlx->context)->cursor_hook;
|
||||
|
||||
cursor_hook.func(xpos, ypos, cursor_hook.param);
|
||||
}
|
||||
|
||||
//= Public =//
|
||||
|
||||
void mlx_scroll_hook(mlx_t* mlx, mlx_scrollfunc func, void* param)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
MLX_NONNULL(func);
|
||||
|
||||
mlx_ctx_t* const mlxctx = mlx->context;
|
||||
mlxctx->scroll_hook.func = func;
|
||||
mlxctx->scroll_hook.param = param;
|
||||
glfwSetScrollCallback(mlx->window, mlx_scroll_cb);
|
||||
}
|
||||
|
||||
void mlx_mouse_hook(mlx_t* mlx, mlx_mousefunc func, void* param)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
MLX_NONNULL(func);
|
||||
|
||||
mlx_ctx_t* const mlxctx = mlx->context;
|
||||
mlxctx->mouse_hook.func = func;
|
||||
mlxctx->mouse_hook.param = param;
|
||||
glfwSetMouseButtonCallback(mlx->window, mlx_mouse_cb);
|
||||
}
|
||||
|
||||
void mlx_cursor_hook(mlx_t* mlx, mlx_cursorfunc func, void* param)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
MLX_NONNULL(func);
|
||||
|
||||
mlx_ctx_t* const mlxctx = mlx->context;
|
||||
mlxctx->cursor_hook.func = func;
|
||||
mlxctx->cursor_hook.param = param;
|
||||
glfwSetCursorPosCallback(mlx->window, mlx_cursor_cb);
|
||||
}
|
||||
|
||||
bool mlx_is_mouse_down(mlx_t* mlx, mouse_key_t key)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
|
||||
return (glfwGetMouseButton(mlx->window, key) == GLFW_PRESS);
|
||||
}
|
||||
|
||||
void mlx_set_mouse_pos(mlx_t* mlx, int32_t x, int32_t y)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
|
||||
glfwSetCursorPos(mlx->window, (double)x, (double)y);
|
||||
}
|
||||
|
||||
void mlx_get_mouse_pos(mlx_t* mlx, int32_t* x, int32_t* y)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
MLX_NONNULL(x);
|
||||
MLX_NONNULL(y);
|
||||
|
||||
double xd, yd;
|
||||
glfwGetCursorPos(mlx->window, &xd, &yd);
|
||||
*x = (int32_t)xd;
|
||||
*y = (int32_t)yd;
|
||||
}
|
34
MLX42/src/mlx_put_pixel.c
Normal file
34
MLX42/src/mlx_put_pixel.c
Normal file
@ -0,0 +1,34 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* :::::::: */
|
||||
/* mlx_put_pixel.c :+: :+: */
|
||||
/* +:+ */
|
||||
/* By: W2Wizard <w2.wizzard@gmail.com> +#+ */
|
||||
/* +#+ */
|
||||
/* Created: 2021/12/28 03:30:13 by W2Wizard #+# #+# */
|
||||
/* Updated: 2022/06/29 16:00:30 by lde-la-h ######## odam.nl */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "MLX42/MLX42_Int.h"
|
||||
|
||||
// BUG: Linux may experience a red hue instead due to endiannes
|
||||
void mlx_draw_pixel(uint8_t* pixel, uint32_t color)
|
||||
{
|
||||
*(pixel++) = (uint8_t)(color >> 24);
|
||||
*(pixel++) = (uint8_t)(color >> 16);
|
||||
*(pixel++) = (uint8_t)(color >> 8);
|
||||
*(pixel++) = (uint8_t)(color & 0xFF);
|
||||
}
|
||||
|
||||
//= Public =//
|
||||
|
||||
void mlx_put_pixel(mlx_image_t* image, uint32_t x, uint32_t y, uint32_t color)
|
||||
{
|
||||
MLX_NONNULL(image);
|
||||
MLX_ASSERT(x < image->width, "Pixel is out of bounds");
|
||||
MLX_ASSERT(y < image->height, "Pixel is out of bounds");
|
||||
|
||||
uint8_t* pixelstart = &image->pixels[(y * image->width + x) * BPP];
|
||||
mlx_draw_pixel(pixelstart, color);
|
||||
}
|
137
MLX42/src/mlx_window.c
Normal file
137
MLX42/src/mlx_window.c
Normal file
@ -0,0 +1,137 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* :::::::: */
|
||||
/* mlx_window.c :+: :+: */
|
||||
/* +:+ */
|
||||
/* By: W2wizard <w2wizzard@gmail.com> +#+ */
|
||||
/* +#+ */
|
||||
/* Created: 2022/02/08 01:14:59 by W2wizard #+# #+# */
|
||||
/* Updated: 2022/11/22 09:06:54 by jvan-hal ######## odam.nl */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "MLX42/MLX42_Int.h"
|
||||
|
||||
//= Private =//
|
||||
|
||||
/**
|
||||
* Recalculate the view projection matrix, used by images for screen pos
|
||||
* Reference: https://bit.ly/3KuHOu1 (Matrix View Projection)
|
||||
*/
|
||||
void mlx_update_matrix(const mlx_t* mlx, int32_t width, int32_t height)
|
||||
{
|
||||
const mlx_ctx_t* mlxctx = mlx->context;
|
||||
const float depth = mlxctx->zdepth;
|
||||
|
||||
/**
|
||||
* In case the setting to stretch the image is set, we maintain the width and height but not
|
||||
* the depth.
|
||||
*/
|
||||
width = mlx_settings[MLX_STRETCH_IMAGE] ? mlxctx->initialWidth : mlx->width;
|
||||
height = mlx_settings[MLX_STRETCH_IMAGE] ? mlxctx->initialHeight : mlx->height;
|
||||
|
||||
const float matrix[16] = {
|
||||
2.f / width, 0, 0, 0,
|
||||
0, 2.f / -(height), 0, 0,
|
||||
0, 0, -2.f / (depth - -depth), 0,
|
||||
-1, -(height / -height),
|
||||
-((depth + -depth) / (depth - -depth)), 1
|
||||
};
|
||||
|
||||
glUniformMatrix4fv(glGetUniformLocation(mlxctx->shaderprogram, "ProjMatrix"), 1, GL_FALSE, matrix);
|
||||
}
|
||||
|
||||
static void mlx_resize_callback(GLFWwindow* window, int32_t width, int32_t height)
|
||||
{
|
||||
const mlx_t* mlx = glfwGetWindowUserPointer(window);
|
||||
const mlx_ctx_t* mlxctx = mlx->context;
|
||||
|
||||
if (mlxctx->resize_hook.func)
|
||||
mlxctx->resize_hook.func(width, height, mlxctx->resize_hook.param);
|
||||
}
|
||||
|
||||
static void mlx_close_callback(GLFWwindow* window)
|
||||
{
|
||||
const mlx_t* mlx = glfwGetWindowUserPointer(window);
|
||||
const mlx_close_t close_hook = ((mlx_ctx_t*)mlx->context)->close_hook;
|
||||
|
||||
close_hook.func(close_hook.param);
|
||||
}
|
||||
|
||||
//= Public =//
|
||||
|
||||
void mlx_close_hook(mlx_t* mlx, mlx_closefunc func, void* param)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
MLX_NONNULL(func);
|
||||
|
||||
mlx_ctx_t* mlxctx = mlx->context;
|
||||
mlxctx->close_hook.func = func;
|
||||
mlxctx->close_hook.param = param;
|
||||
glfwSetWindowCloseCallback(mlx->window, mlx_close_callback);
|
||||
}
|
||||
|
||||
void mlx_resize_hook(mlx_t* mlx, mlx_resizefunc func, void* param)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
MLX_NONNULL(func);
|
||||
|
||||
mlx_ctx_t* mlxctx = mlx->context;
|
||||
mlxctx->resize_hook.func = func;
|
||||
mlxctx->resize_hook.param = param;
|
||||
glfwSetWindowSizeCallback(mlx->window, mlx_resize_callback);
|
||||
}
|
||||
|
||||
void mlx_set_icon(mlx_t* mlx, mlx_texture_t* image)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
MLX_NONNULL(image);
|
||||
|
||||
const GLFWimage icon = {
|
||||
.width = image->width,
|
||||
.height = image->height,
|
||||
.pixels = image->pixels
|
||||
};
|
||||
|
||||
glfwSetWindowIcon(mlx->window, 1, &icon);
|
||||
}
|
||||
|
||||
void mlx_set_window_pos(mlx_t* mlx, int32_t xpos, int32_t ypos)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
|
||||
glfwSetWindowPos(mlx->window, xpos, ypos);
|
||||
}
|
||||
|
||||
void mlx_get_window_pos(mlx_t* mlx, int32_t* xpos, int32_t* ypos)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
MLX_NONNULL(xpos);
|
||||
MLX_NONNULL(ypos);
|
||||
|
||||
glfwGetWindowPos(mlx->window, xpos, ypos);
|
||||
}
|
||||
|
||||
void mlx_set_window_size(mlx_t* mlx, int32_t new_width, int32_t new_height)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
|
||||
mlx->width = new_width;
|
||||
mlx->height = new_height;
|
||||
glfwSetWindowSize(mlx->window, new_width, new_height);
|
||||
}
|
||||
|
||||
void mlx_set_window_limit(mlx_t* mlx, int32_t min_w, int32_t min_h, int32_t max_w, int32_t max_h)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
|
||||
glfwSetWindowSizeLimits(mlx->window, min_w, min_h, max_w, max_h);
|
||||
}
|
||||
|
||||
void mlx_set_window_title(mlx_t* mlx, const char* title)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
MLX_NONNULL(title);
|
||||
|
||||
glfwSetWindowTitle(mlx->window, title);
|
||||
}
|
35
MLX42/src/textures/mlx_png.c
Normal file
35
MLX42/src/textures/mlx_png.c
Normal file
@ -0,0 +1,35 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* :::::::: */
|
||||
/* mlx_png.c :+: :+: */
|
||||
/* +:+ */
|
||||
/* By: W2Wizard <w2.wizzard@gmail.com> +#+ */
|
||||
/* +#+ */
|
||||
/* Created: 2022/02/16 23:11:29 by W2Wizard #+# #+# */
|
||||
/* Updated: 2022/06/27 19:55:06 by lde-la-h ######## odam.nl */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "MLX42/MLX42_Int.h"
|
||||
|
||||
//= Public =//
|
||||
|
||||
mlx_texture_t* mlx_load_png(const char* path)
|
||||
{
|
||||
MLX_NONNULL(path);
|
||||
|
||||
mlx_texture_t* image;
|
||||
if (!(image = malloc(sizeof(mlx_texture_t))))
|
||||
return ((void*)mlx_error(MLX_MEMFAIL));
|
||||
|
||||
uint32_t error;
|
||||
image->bytes_per_pixel = BPP;
|
||||
if ((error = lodepng_decode32_file(&image->pixels, &image->width, &image->height, path)))
|
||||
{
|
||||
free(image);
|
||||
// Explicitly print error on purpose
|
||||
fprintf(stderr, "MLX42: LodePNG: %s\n", lodepng_error_text(error));
|
||||
return ((void*)mlx_error(MLX_INVPNG));
|
||||
}
|
||||
return (image);
|
||||
}
|
42
MLX42/src/textures/mlx_texture.c
Normal file
42
MLX42/src/textures/mlx_texture.c
Normal file
@ -0,0 +1,42 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* :::::::: */
|
||||
/* mlx_texture.c :+: :+: */
|
||||
/* +:+ */
|
||||
/* By: W2Wizard <main@w2wizard.dev> +#+ */
|
||||
/* +#+ */
|
||||
/* Created: 2022/02/17 01:02:24 by W2Wizard #+# #+# */
|
||||
/* Updated: 2023/03/09 11:03:47 by W2Wizard ######## odam.nl */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "MLX42/MLX42_Int.h"
|
||||
|
||||
//= Public =//
|
||||
|
||||
mlx_image_t* mlx_texture_to_image(mlx_t* mlx, mlx_texture_t* texture)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
MLX_NONNULL(texture);
|
||||
|
||||
mlx_image_t* image = mlx_new_image(mlx, texture->width, texture->height);
|
||||
if (image == NULL)
|
||||
return (NULL);
|
||||
|
||||
uint8_t* pixelx;
|
||||
uint8_t* pixeli;
|
||||
for (uint32_t i = 0; i < texture->height; i++)
|
||||
{
|
||||
pixelx = &texture->pixels[(i * texture->width) * texture->bytes_per_pixel];
|
||||
pixeli = &image->pixels[(i * image->width) * texture->bytes_per_pixel];
|
||||
memmove(pixeli, pixelx, texture->width * texture->bytes_per_pixel);
|
||||
}
|
||||
return (image);
|
||||
}
|
||||
|
||||
void mlx_delete_texture(mlx_texture_t* texture)
|
||||
{
|
||||
MLX_NONNULL(texture);
|
||||
|
||||
mlx_freen(2, texture->pixels, texture);
|
||||
}
|
208
MLX42/src/textures/mlx_xpm42.c
Normal file
208
MLX42/src/textures/mlx_xpm42.c
Normal file
@ -0,0 +1,208 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* :::::::: */
|
||||
/* mlx_xpm42.c :+: :+: */
|
||||
/* +:+ */
|
||||
/* By: W2Wizard <w2.wizzard@gmail.com> +#+ */
|
||||
/* +#+ */
|
||||
/* Created: 2021/12/28 03:42:29 by W2Wizard #+# #+# */
|
||||
/* Updated: 2022/06/27 19:58:33 by lde-la-h ######## odam.nl */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "MLX42/MLX42_Int.h"
|
||||
|
||||
/**
|
||||
* XPM is an obscure image format which can't seem to make up its mind
|
||||
* whether it wants to be written in C code or not.
|
||||
*
|
||||
* https://en.wikipedia.org/wiki/X_PixMap
|
||||
*
|
||||
* This might anger some but instead I decided to write my own
|
||||
* image format, very similar to XPM2, which seems to be the better
|
||||
* option between the 3 versions. The only difference is in the
|
||||
* header which carries the file type, width, height, color count
|
||||
* and finally color type aka 'c' for RGBA8 or 'm' for monochrome
|
||||
* output.
|
||||
*
|
||||
* The changes, in my opinion, very much simplify the XPM format
|
||||
* into something literally anybody can use without much guessing
|
||||
* as to what does what.
|
||||
*
|
||||
* Additionally with the C style format, the idea is that you simply include
|
||||
* it directly into the compilation of the program (since it's just C).
|
||||
*
|
||||
* As convenient as this is, I just find it hideous especially the XPM3 variant.
|
||||
* By sticking to the XPM style format, conversion should be very easy and
|
||||
* straightforward to this format however.
|
||||
*/
|
||||
|
||||
//= Private =//
|
||||
|
||||
/**
|
||||
* Parses HEX color channel e.g: "0F"
|
||||
*
|
||||
* @param channel The 2 character string to parse.
|
||||
* @return Int value of the channel.
|
||||
*/
|
||||
static uint8_t mlx_parse_hex_channel(char* channel)
|
||||
{
|
||||
char temp_chan[] = {channel[0], channel[1], '\0'};
|
||||
return (strtol(temp_chan, NULL, 16));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the XPM color value entry e.g: ".X #00FF00FF"
|
||||
* into the color table while also verifying the format.
|
||||
*
|
||||
* @param xpm The XPM.
|
||||
* @param line The line to parse.
|
||||
* @param ctable The color hash table.
|
||||
* @param s Size of the hash table
|
||||
* @return True or false depending on if it sucessfully parsed the line.
|
||||
*/
|
||||
static bool mlx_insert_xpm_entry(xpm_t* xpm, char* line, uint32_t* ctable, size_t s)
|
||||
{
|
||||
// NOTE: uintptr because windows likes to complain...
|
||||
// Verify the length of the Pixel string by checking backwards for the first
|
||||
// occurence of a space and then check the distance by comparing with cpp.
|
||||
if (((uintptr_t)strrchr(line, ' ') - (uintptr_t)line) != (uint64_t)xpm->cpp)
|
||||
return (false);
|
||||
if (!isspace(line[xpm->cpp]) || line[xpm->cpp + 1] != '#' || !isalnum(line[xpm->cpp + 2]))
|
||||
return (false);
|
||||
|
||||
uint32_t color = 0;
|
||||
size_t start_offset = xpm->cpp + 2;
|
||||
color |= mlx_parse_hex_channel(line + start_offset) << 24;
|
||||
color |= mlx_parse_hex_channel(line + start_offset + 2) << 16;
|
||||
color |= mlx_parse_hex_channel(line + start_offset + 4) << 8;
|
||||
color |= mlx_parse_hex_channel(line + start_offset + 6);
|
||||
|
||||
int32_t index = mlx_fnv_hash(line, xpm->cpp) % s;
|
||||
ctable[index] = xpm->mode == 'm' ? mlx_rgba_to_mono(color) : color;
|
||||
return (true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the pixel data line by line and then processes each pixel
|
||||
* by hashing the characters and looking it up from the color table.
|
||||
*
|
||||
* @param xpm The XPM.
|
||||
* @param file The filepath to the XPM42 file.
|
||||
* @param ctable The color hash table.
|
||||
* @param s Size of the hash table.
|
||||
* @return True or false depending on if it sucessfully parsed the line.
|
||||
*/
|
||||
static bool mlx_read_data(xpm_t* xpm, FILE* file, uint32_t* ctable, size_t s)
|
||||
{
|
||||
size_t line_len;
|
||||
char* line = NULL;
|
||||
|
||||
for (int64_t y_xpm = 0; y_xpm < xpm->texture.height; y_xpm++)
|
||||
{
|
||||
if (!mlx_getline(&line, &line_len, file))
|
||||
return (free(line), false);
|
||||
if (line[line_len - 1] == '\n')
|
||||
line_len--;
|
||||
if (line_len != xpm->texture.width * xpm->cpp)
|
||||
return (free(line), false);
|
||||
|
||||
// NOTE: Copy pixel by pixel as we need to retrieve the hash table.
|
||||
for (int64_t x_xpm = 0, x_line = 0; x_xpm < xpm->texture.width; x_xpm++, x_line += xpm->cpp)
|
||||
{
|
||||
uint8_t* pixelstart = &xpm->texture.pixels[(y_xpm * xpm->texture.width + x_xpm) * BPP];
|
||||
mlx_draw_pixel(pixelstart, ctable[mlx_fnv_hash(&line[x_line], xpm->cpp) % s]);
|
||||
}
|
||||
}
|
||||
free(line);
|
||||
return (true);
|
||||
}
|
||||
|
||||
/**
|
||||
* For quick lookups we basically create a stack allocated lookup
|
||||
* table with every ascii character in it. This should help avoid a O(n)
|
||||
* case and give us a O(1) for very fast look ups.
|
||||
*
|
||||
* Downside is we still need to iterate over each pixel to solve its color.
|
||||
* So I hope this makes it at least a bit faster.
|
||||
*
|
||||
* TODO: This buffer might be way to big! Do actual collision checks,
|
||||
* for now just straight up raw dog this.
|
||||
*/
|
||||
static bool mlx_read_table(xpm_t* xpm, FILE* file)
|
||||
{
|
||||
char* line = NULL;
|
||||
size_t line_len;
|
||||
uint32_t ctable[UINT16_MAX] = {0};
|
||||
|
||||
for (int32_t i = 0; i < xpm->color_count; i++)
|
||||
{
|
||||
if (!mlx_getline(&line, &line_len, file))
|
||||
return (free(line), false);
|
||||
if (!mlx_insert_xpm_entry(xpm, line, ctable, (sizeof(ctable) / BPP)))
|
||||
return (free(line), false);
|
||||
}
|
||||
free(line);
|
||||
return (mlx_read_data(xpm, file, ctable, (sizeof(ctable) / BPP)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the XPM42 file header which usually consists of a
|
||||
* file type declaration of "!XPM42" followed by the next line
|
||||
* containing image information such as width, height, unique color
|
||||
* count and finally the color mode. Which is either c for Color or
|
||||
* m for Monochrome.
|
||||
*/
|
||||
static bool mlx_read_xpm_header(xpm_t* xpm, FILE *file)
|
||||
{
|
||||
int32_t flagc;
|
||||
char buffer[64] = {0};
|
||||
|
||||
// Check file type dec...
|
||||
if (!fgets(buffer, sizeof(buffer), file))
|
||||
return (false);
|
||||
if (strncmp(buffer, "!XPM42\n", sizeof(buffer)) != 0)
|
||||
return (false);
|
||||
|
||||
// Get header info ...
|
||||
if (!fgets(buffer, sizeof(buffer), file))
|
||||
return (false);
|
||||
flagc = sscanf(buffer, "%i %i %i %i %c\n", &xpm->texture.width, &xpm->texture.height, &xpm->color_count, &xpm->cpp, &xpm->mode);
|
||||
if (flagc < 4 || xpm->texture.width > INT16_MAX || xpm->texture.height > INT16_MAX || \
|
||||
!(xpm->mode == 'c' || xpm->mode == 'm') || xpm->cpp > 10)
|
||||
return (false);
|
||||
xpm->texture.bytes_per_pixel = BPP;
|
||||
xpm->texture.pixels = calloc(xpm->texture.width * xpm->texture.height, sizeof(int32_t));
|
||||
return (xpm->texture.pixels != NULL ? mlx_read_table(xpm, file) : false);
|
||||
}
|
||||
|
||||
//= Public =//
|
||||
|
||||
xpm_t* mlx_load_xpm42(const char* path)
|
||||
{
|
||||
FILE* file;
|
||||
xpm_t* xpm = NULL;
|
||||
|
||||
MLX_NONNULL(path);
|
||||
if (!strstr(path, ".xpm42"))
|
||||
return ((void*)mlx_error(MLX_INVEXT));
|
||||
if (!(file = fopen(path, "r")))
|
||||
return ((void*)mlx_error(MLX_INVFILE));
|
||||
if (!(xpm = calloc(1, sizeof(xpm_t))))
|
||||
return ((void*)mlx_error(MLX_MEMFAIL));
|
||||
if (!mlx_read_xpm_header(xpm, file))
|
||||
{
|
||||
mlx_freen(2, xpm->texture.pixels, xpm);
|
||||
mlx_error(MLX_INVXPM);
|
||||
xpm = NULL;
|
||||
}
|
||||
fclose(file);
|
||||
return (xpm);
|
||||
}
|
||||
|
||||
void mlx_delete_xpm42(xpm_t* xpm)
|
||||
{
|
||||
MLX_NONNULL(xpm);
|
||||
free(xpm->texture.pixels);
|
||||
free(xpm);
|
||||
}
|
31
MLX42/src/utils/mlx_compare.c
Normal file
31
MLX42/src/utils/mlx_compare.c
Normal file
@ -0,0 +1,31 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* :::::::: */
|
||||
/* mlx_comparison.c :+: :+: */
|
||||
/* +:+ */
|
||||
/* By: jvan-hal <jvan-hal@student.codam.nl> +#+ */
|
||||
/* +#+ */
|
||||
/* Created: 2023/01/31 17:20:19 by jvan-hal #+# #+# */
|
||||
/* Updated: 2023/01/31 17:23:49 by jvan-hal ######## odam.nl */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "MLX42/MLX42_Int.h"
|
||||
|
||||
//= Private =//
|
||||
|
||||
bool mlx_equal_image(void* lstcontent, void* value)
|
||||
{
|
||||
const mlx_image_t* lcontent = lstcontent;
|
||||
const mlx_image_t* lvalue = value;
|
||||
|
||||
return (lcontent == lvalue);
|
||||
}
|
||||
|
||||
bool mlx_equal_inst(void* lstcontent, void* value)
|
||||
{
|
||||
const draw_queue_t* lcontent = lstcontent;
|
||||
const mlx_image_t* lvalue = value;
|
||||
|
||||
return (lcontent->image == lvalue);
|
||||
}
|
60
MLX42/src/utils/mlx_error.c
Normal file
60
MLX42/src/utils/mlx_error.c
Normal file
@ -0,0 +1,60 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* :::::::: */
|
||||
/* mlx_error.c :+: :+: */
|
||||
/* +:+ */
|
||||
/* By: W2Wizard <w2.wizzard@gmail.com> +#+ */
|
||||
/* +#+ */
|
||||
/* Created: 2021/12/28 02:51:54 by W2Wizard #+# #+# */
|
||||
/* Updated: 2022/11/22 08:50:15 by jvan-hal ######## odam.nl */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "MLX42/MLX42_Int.h"
|
||||
|
||||
//= Private =//
|
||||
|
||||
// English description of the error codes.
|
||||
static const char* mlx_errors[MLX_ERRMAX] = {
|
||||
"No Errors",
|
||||
"File has invalid extension",
|
||||
"Failed to open the file",
|
||||
"PNG file is invalid or corrupted",
|
||||
"XPM42 file is invalid or corrupted",
|
||||
"The specified X or Y positions are out of bounds",
|
||||
"The specified Width or Height dimensions are out of bounds",
|
||||
"The provided image is invalid, might indicate mismanagement of images",
|
||||
"Failed to compile the vertex shader.",
|
||||
"Failed to compile the fragment shader.",
|
||||
"Failed to compile the shaders.",
|
||||
"Failed to allocate memory",
|
||||
"Failed to initialize GLAD",
|
||||
"Failed to initialize GLFW",
|
||||
"Failed to create window",
|
||||
"String is too big to be drawn",
|
||||
};
|
||||
|
||||
/**
|
||||
* Functions to set the error number, simply for convenience.
|
||||
*
|
||||
* @param val The error value.
|
||||
* @return Always false
|
||||
*/
|
||||
bool mlx_error(mlx_errno_t val)
|
||||
{
|
||||
mlx_errno = val;
|
||||
#ifndef NDEBUG
|
||||
fprintf(stderr, "MLX42: %s", mlx_strerror(mlx_errno));
|
||||
#endif
|
||||
return (false);
|
||||
}
|
||||
|
||||
//= Public =//
|
||||
|
||||
const char* mlx_strerror(mlx_errno_t val)
|
||||
{
|
||||
MLX_ASSERT(val >= 0, "Index must be positive");
|
||||
MLX_ASSERT(val < MLX_ERRMAX, "Index out of bounds");
|
||||
|
||||
return (mlx_errors[val]);
|
||||
}
|
176
MLX42/src/utils/mlx_list.c
Normal file
176
MLX42/src/utils/mlx_list.c
Normal file
@ -0,0 +1,176 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* :::::::: */
|
||||
/* mlx_list.c :+: :+: */
|
||||
/* +:+ */
|
||||
/* By: W2Wizard <main@w2wizard.dev> +#+ */
|
||||
/* +#+ */
|
||||
/* Created: 2021/12/28 01:53:51 by W2Wizard #+# #+# */
|
||||
/* Updated: 2023/02/27 11:31:01 by W2Wizard ######## odam.nl */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "MLX42/MLX42_Int.h"
|
||||
|
||||
//= Private =//
|
||||
|
||||
int32_t mlx_lstsize(mlx_list_t* lst)
|
||||
{
|
||||
int32_t i;
|
||||
|
||||
for (i = 0; lst != NULL; i++)
|
||||
lst = lst->next;
|
||||
return (i);
|
||||
}
|
||||
|
||||
static void mlx_lstdelone(mlx_list_t* lst, void (*del)(void *))
|
||||
{
|
||||
if (del != NULL)
|
||||
del(lst->content);
|
||||
free(lst);
|
||||
}
|
||||
|
||||
void mlx_lstclear(mlx_list_t** lst, void (*del)(void*))
|
||||
{
|
||||
mlx_list_t* next_lst;
|
||||
|
||||
while (*lst != NULL)
|
||||
{
|
||||
next_lst = (*lst)->next;
|
||||
mlx_lstdelone(*lst, del);
|
||||
*lst = next_lst;
|
||||
}
|
||||
}
|
||||
|
||||
mlx_list_t* mlx_lstnew(void* content)
|
||||
{
|
||||
mlx_list_t* out = NULL;
|
||||
|
||||
if ((out = malloc(sizeof(mlx_list_t))))
|
||||
{
|
||||
out->content = content;
|
||||
out->next = NULL;
|
||||
out->prev = NULL;
|
||||
}
|
||||
return (out);
|
||||
}
|
||||
|
||||
mlx_list_t* mlx_lstlast(mlx_list_t* lst)
|
||||
{
|
||||
if (!lst)
|
||||
return (NULL);
|
||||
while (lst->next)
|
||||
lst = lst->next;
|
||||
return (lst);
|
||||
}
|
||||
|
||||
void mlx_lstadd_back(mlx_list_t** lst, mlx_list_t* new)
|
||||
{
|
||||
if (!lst || !new)
|
||||
return;
|
||||
if (!*lst)
|
||||
*lst = new;
|
||||
else
|
||||
{
|
||||
mlx_list_t* temp = mlx_lstlast(*lst);
|
||||
new->prev = temp;
|
||||
temp->next = new;
|
||||
}
|
||||
}
|
||||
|
||||
void mlx_lstadd_front(mlx_list_t** lst, mlx_list_t* new)
|
||||
{
|
||||
if (!lst || !new)
|
||||
return;
|
||||
if ((*lst) != NULL)
|
||||
(*lst)->prev = new;
|
||||
new->next = *lst;
|
||||
new->prev = NULL;
|
||||
*lst = new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified content from the list, if found.
|
||||
* Also fixes any relinking that might be needed.
|
||||
*
|
||||
* @param[in] lst The list
|
||||
* @param[in] comp Function to check if the content and value are the same.
|
||||
* @returns The removed element, clean up as you wish.
|
||||
*/
|
||||
mlx_list_t* mlx_lstremove(mlx_list_t** lst, void* value, bool (*comp)(void*, void*))
|
||||
{
|
||||
mlx_list_t* lstcpy = *lst;
|
||||
|
||||
while (lstcpy && !comp(lstcpy->content, value))
|
||||
lstcpy = lstcpy->next;
|
||||
if (lstcpy == NULL)
|
||||
return (NULL);
|
||||
if (lstcpy == *lst)
|
||||
*lst = lstcpy->next;
|
||||
if (lstcpy->next != NULL)
|
||||
lstcpy->next->prev = lstcpy->prev;
|
||||
if (lstcpy->prev != NULL)
|
||||
lstcpy->prev->next = lstcpy->next;
|
||||
return (lstcpy);
|
||||
}
|
||||
|
||||
// Retrieve Z value from queue.
|
||||
static int32_t mlx_getzdata(mlx_list_t* entry)
|
||||
{
|
||||
const draw_queue_t* queue = entry->content;
|
||||
|
||||
return (queue->image->instances[queue->instanceid].z);
|
||||
}
|
||||
|
||||
// Insert the entry back into head sorted.
|
||||
static void mlx_insertsort(mlx_list_t** head, mlx_list_t* new)
|
||||
{
|
||||
mlx_list_t* current;
|
||||
|
||||
if (*head == NULL)
|
||||
*head = new;
|
||||
else if (mlx_getzdata(*head) >= mlx_getzdata(new))
|
||||
{
|
||||
new->next = *head;
|
||||
new->next->prev = new;
|
||||
*head = new;
|
||||
}
|
||||
else
|
||||
{
|
||||
current = *head;
|
||||
|
||||
// Find insertion location.
|
||||
while (current->next != NULL && mlx_getzdata(current->next) < mlx_getzdata(new))
|
||||
current = current->next;
|
||||
new->next = current->next;
|
||||
|
||||
// Insert at the end
|
||||
if (current->next != NULL)
|
||||
new->next->prev = new;
|
||||
current->next = new;
|
||||
new->prev = current;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Okay-ish sorting algorithm to sort the render queue / doubly linked list.
|
||||
* We need to do this to fix transparency.
|
||||
*
|
||||
* @param lst The render queue.
|
||||
*/
|
||||
void mlx_sort_renderqueue(mlx_list_t** lst)
|
||||
{
|
||||
mlx_list_t* sorted = NULL;
|
||||
mlx_list_t* lstcpy = *lst;
|
||||
|
||||
while (lstcpy != NULL)
|
||||
{
|
||||
mlx_list_t* next = lstcpy->next;
|
||||
|
||||
// Separate entry out of list and insert it back but sorted.
|
||||
lstcpy->prev = lstcpy->next = NULL;
|
||||
mlx_insertsort(&sorted, lstcpy);
|
||||
lstcpy = next;
|
||||
}
|
||||
*lst = sorted;
|
||||
}
|
131
MLX42/src/utils/mlx_utils.c
Normal file
131
MLX42/src/utils/mlx_utils.c
Normal file
@ -0,0 +1,131 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* :::::::: */
|
||||
/* mlx_utils.c :+: :+: */
|
||||
/* +:+ */
|
||||
/* By: W2Wizard <w2.wizzard@gmail.com> +#+ */
|
||||
/* +#+ */
|
||||
/* Created: 2022/01/03 20:13:17 by W2Wizard #+# #+# */
|
||||
/* Updated: 2022/11/22 10:56:09 by jvan-hal ######## odam.nl */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "MLX42/MLX42_Int.h"
|
||||
|
||||
//= Private =//
|
||||
|
||||
/**
|
||||
* Function to read a file stream line by line, reusing the same output pointer.
|
||||
* Since the same output pointer is reused it should only be freed once, either on success or failure.
|
||||
* This function is made to be somewhat similar to getline.
|
||||
* Getline can't be used directly since it's not standard and therefore not available on all platforms.
|
||||
*
|
||||
* @param out Pointer to store output string.
|
||||
* @param out_size Pointer to store output strings length.
|
||||
* @param file File stream to read from.
|
||||
* @return True if line was read, false if EOF was reached or an error occurred.
|
||||
*/
|
||||
bool mlx_getline(char** out, size_t* out_size, FILE* file)
|
||||
{
|
||||
MLX_NONNULL(out);
|
||||
MLX_NONNULL(out_size);
|
||||
MLX_NONNULL(file);
|
||||
|
||||
size_t size = 0;
|
||||
char* temp = NULL;
|
||||
static char BUFF[GETLINE_BUFF + 1]; // Add space for '\0'
|
||||
|
||||
if (*out) *out[0] = '\0';
|
||||
|
||||
while (fgets(BUFF, sizeof(BUFF), file))
|
||||
{
|
||||
size += strlen(BUFF);
|
||||
if (!(temp = realloc(*out, sizeof(char) * size + 1)))
|
||||
return (false);
|
||||
if (*out == NULL)
|
||||
memset(temp, '\0', size);
|
||||
temp[size] = '\0';
|
||||
|
||||
*out = temp;
|
||||
*out_size = size;
|
||||
|
||||
strncat(*out, BUFF, size);
|
||||
if (strrchr(BUFF, '\n'))
|
||||
return (true);
|
||||
memset(BUFF, '\0', sizeof(BUFF));
|
||||
}
|
||||
return (size);
|
||||
}
|
||||
|
||||
/**
|
||||
* String hashing algorithm using FNV-1a.
|
||||
* Source: https://bit.ly/3JcRGHa
|
||||
*
|
||||
* @param str The string to hash
|
||||
* @param len The length of the string.
|
||||
* @return The hashed output.
|
||||
*/
|
||||
uint64_t mlx_fnv_hash(char* str, size_t len)
|
||||
{
|
||||
const uint64_t fnv_prime = 0x100000001b3;
|
||||
const uint64_t fnv_offset = 0xcbf29ce484222325;
|
||||
uint64_t hash = fnv_offset;
|
||||
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
hash ^= str[i];
|
||||
hash *= fnv_prime;
|
||||
}
|
||||
return (hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function that lets you free x amount of pointers.
|
||||
*
|
||||
* @param count The amount of args provided.
|
||||
* @param ... Any form of pointer.
|
||||
* @return False, this is simply for convenience when necessary.
|
||||
*/
|
||||
bool mlx_freen(int32_t count, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, count);
|
||||
for (int32_t i = 0; i < count; i++)
|
||||
free(va_arg(args, void*));
|
||||
va_end(args);
|
||||
return (false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an RGBA value to a monochrome/grayscale value.
|
||||
* It does so using specific weights for each channel.
|
||||
*
|
||||
* @see https://goodcalculators.com/rgb-to-grayscale-conversion-calculator/
|
||||
*
|
||||
* @param color The input RGBA value.
|
||||
* @return The rgba value converted to a grayscale color.
|
||||
*/
|
||||
uint32_t mlx_rgba_to_mono(uint32_t color)
|
||||
{
|
||||
const uint8_t r = 0.299f * ((color >> 24) & 0xFF);
|
||||
const uint8_t g = 0.587f * ((color >> 16) & 0xFF);
|
||||
const uint8_t b = 0.114f * ((color >> 8) & 0xFF);
|
||||
const uint8_t y = r + g + b;
|
||||
|
||||
return (y << 24 | y << 16 | y << 8 | (color & 0xFF));
|
||||
}
|
||||
|
||||
//= Public =//
|
||||
|
||||
double mlx_get_time(void)
|
||||
{
|
||||
return (glfwGetTime());
|
||||
}
|
||||
|
||||
void mlx_focus(mlx_t* mlx)
|
||||
{
|
||||
MLX_NONNULL(mlx);
|
||||
|
||||
glfwFocusWindow(mlx->window);
|
||||
}
|
Reference in New Issue
Block a user