#include "../../include/mgui/image.h" #include "../../include/resource_loader.h" #include "../../include/common.h" #include "../../include/alloc.h" #include "../../include/async_image.h" #include #include #include #include #include /* TODO: Support network files */ /* TODO: Set a target size and use that for calculating size and resize image to that */ static mgl_vec2i wrap_to_size_x(mgl_vec2i size, int clamp_size) { mgl_vec2i new_size; if(size.x == 0) { new_size.x = 0; new_size.y = 0; return new_size; } float size_ratio = (float)size.y / (float)size.x; new_size.x = clamp_size; new_size.y = new_size.x * size_ratio; return new_size; } static mgl_vec2i wrap_to_size_y(mgl_vec2i size, int clamp_size) { mgl_vec2i new_size; if(size.y == 0) { new_size.x = 0; new_size.y = 0; return new_size; } float size_ratio = (float)size.x / (float)size.y; new_size.y = clamp_size; new_size.x = new_size.y * size_ratio; return new_size; } static mgl_vec2i wrap_to_size(const mgl_vec2i size, const mgl_vec2i clamp_size) { mgl_vec2i new_size = wrap_to_size_x(size, clamp_size.x); if(new_size.y > clamp_size.y) new_size = wrap_to_size_y(size, clamp_size.y); return new_size; } static mgl_vec2i clamp_to_size(mgl_vec2i size, mgl_vec2i clamp_size) { mgl_vec2i new_size = size; if(size.x > clamp_size.x || size.y > clamp_size.y) new_size = wrap_to_size(new_size, clamp_size); return new_size; } mgui_image* mgui_image_create(const char *filepath) { mgui_image *image = mgui_alloc(sizeof(mgui_image)); mgui_widget_init(&image->widget, MGUI_WIDGET_IMAGE); mgl_sprite_init(&image->sprite, NULL); image->max_size = (mgl_vec2i){ 0, 0 }; if(filepath) { image->async_image = mgui_async_image_get_by_path(filepath); if(image->async_image->state == MGUI_ASYNC_IMAGE_APPLIED) mgl_sprite_set_texture(&image->sprite, &image->async_image->texture); } else { image->async_image = NULL; } return image; } void mgui_image_destroy(mgui_image *image) { if(image->async_image) mgui_async_image_unref(image->async_image); image->sprite.texture = NULL; mgui_free(image); } mgui_widget* mgui_image_to_widget(mgui_image *list) { return &list->widget; } mgui_image* mgui_widget_to_image(mgui_widget *widget) { assert(widget->type == MGUI_WIDGET_IMAGE); return (mgui_image*)widget; } void mgui_image_set_position(mgui_image *self, mgl_vec2i position) { mgl_sprite_set_position(&self->sprite, (mgl_vec2f){ position.x, position.y }); } void mgui_image_calculate_size(mgui_image *self, mgl_vec2i max_size) { self->max_size = max_size; if(self->sprite.texture) { const mgl_vec2i texture_size = (mgl_vec2i){ self->sprite.texture->width, self->sprite.texture->height }; const mgl_vec2i new_size = clamp_to_size(texture_size, max_size); self->sprite.scale.x = (float)new_size.x / (float)texture_size.x; self->sprite.scale.y = (float)new_size.y / (float)texture_size.y; self->widget.size = new_size; } else { self->widget.size = (mgl_vec2i){ 1, 1 }; } } void mgui_image_on_event(mgui_image *self, mgl_window *window, mgl_event *event) { (void)self; (void)window; (void)event; /* TODO: Implement */ } void mgui_image_draw(mgui_image *self, mgl_window *window) { if(self->async_image && mgui_rectangle_intersects_with_scissor((mgl_vec2i){ self->sprite.position.x, self->sprite.position.y }, self->widget.size, window)) { mgui_async_image_update(self->async_image); if(self->async_image->state == MGUI_ASYNC_IMAGE_APPLIED) { mgl_sprite_set_texture(&self->sprite, &self->async_image->texture); /* TODO: Check if this is correct when taking margin into consideration */ mgui_image_calculate_size(self, self->max_size); if(self->sprite.texture && self->sprite.texture->id) mgl_sprite_draw(mgl_get_context(), &self->sprite); } } }