Files
armorpaint/base/sources/iron.h
T
2026-08-21 22:35:30 +02:00

1008 lines
25 KiB
C

#pragma once
#pragma clang diagnostic ignored "-Wincompatible-pointer-types"
#include "const_data.h"
#include "iron_armpack.h"
#include "iron_array.h"
#include "iron_draw.h"
#include "iron_file.h"
#include "iron_alloc.h"
#include "iron_gpu.h"
#include "iron_json.h"
#include "iron_lz4.h"
#include "iron_map.h"
#include "iron_math.h"
#include "iron_obj.h"
#include "iron_path.h"
#include "iron_string.h"
#include "iron_system.h"
#include "iron_thread.h"
#include "iron_ui.h"
#include "libs/minic.h"
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#ifdef IRON_WINDOWS
#include <Windows.h>
#elif defined(IRON_WASM)
#else
#include <sys/stat.h>
#endif
#ifdef IRON_AUDIO
#include "iron_audio.h"
#endif
#ifdef WITH_BC7
#include "libs/bc7enc.h"
#endif
#ifdef WITH_EMBED
#include EMBED_H_PATH
#endif
#define ID__(x, y) x ":" #y
#define ID_(x, y) ID__(x, y)
#define __ID__ ID_(__FILE__, __LINE__)
int _argc;
char **_argv;
#ifdef WITH_EMBED
buffer_t *embed_get(char *key) {
#ifdef IRON_WINDOWS
key = string_replace_all(key, "\\", "/");
#endif
for (int i = 0; i < embed_count; ++i) {
if (strcmp(embed_keys[i], key) == 0) {
buffer_t *buffer = buffer_create(0);
buffer->buffer = embed_values[i];
buffer->length = embed_sizes[i];
return buffer;
}
}
return NULL;
}
bool embed_owns(uint8_t *buffer) {
for (int i = 0; i < embed_count; ++i) {
if (embed_values[i] == buffer) {
return true;
}
}
return false;
}
#endif
void _kickstart();
bool enable_window = true;
bool in_background = false;
int paused_frames = 0;
#ifdef IDLE_SLEEP
bool input_down = false;
int last_window_width = 0;
int last_window_height = 0;
#endif
char temp_string[1024 * 128];
char temp_string_vs[1024 * 128];
char temp_string_fs[1024 * 128];
#ifdef IRON_WINDOWS
wchar_t temp_wstring[1024 * 32];
struct HWND__ *iron_windows_window_handle();
#endif
void (*iron_update)(void);
void (*iron_drop_files)(char *);
void (*iron_foreground)(void);
void (*iron_background)(void);
void (*iron_shutdown)(void);
void (*iron_key_down)(int);
void (*iron_key_up)(int);
void (*iron_mouse_down)(int, int, int);
void (*iron_mouse_up)(int, int, int);
void (*iron_mouse_move)(int, int, int, int);
void (*iron_mouse_wheel)(float);
void (*iron_touch_down)(int, int, int);
void (*iron_touch_up)(int, int, int);
void (*iron_touch_move)(int, int, int);
void (*iron_pen_down)(int, int, float);
void (*iron_pen_up)(int, int, float);
void (*iron_pen_move)(int, int, float);
void (*iron_save_and_quit)(bool);
char *_substring(char *s, int32_t start, int32_t end) {
char *buffer = calloc(1, end - start + 1);
for (int i = 0; i < end - start; ++i) {
buffer[i] = s[start + i];
}
return buffer;
}
int kickstart(int argc, char **argv) {
_argc = argc;
_argv = argv;
#ifdef IRON_ANDROID
char *bindir = "/";
#elif defined(IRON_IOS)
char *bindir = "";
#elif defined(IRON_WASM)
char *bindir = "/";
#else
char *bindir = argv[0];
#endif
#ifdef IRON_WINDOWS // Handle non-ascii path
HMODULE hmodule = GetModuleHandleW(NULL);
GetModuleFileNameW(hmodule, temp_wstring, 1024);
WideCharToMultiByte(CP_UTF8, 0, temp_wstring, -1, temp_string, 4096, NULL, NULL);
bindir = _substring(temp_string, 0, string_last_index_of(temp_string, "\\"));
// Running from Visual Studio
if (argc > 1 && strlen(argv[1]) > 4 && argv[1][strlen(argv[1]) - 4] == '\\' && argv[1][strlen(argv[1]) - 3] == 'o' && argv[1][strlen(argv[1]) - 2] == 'u' &&
argv[1][strlen(argv[1]) - 1] == 't') {
bindir = argv[1];
}
#else
bindir = _substring(bindir, 0, string_last_index_of(bindir, "/"));
#endif
for (int i = 2; i < argc; ++i) {
if (strcmp(argv[i], "--nowindow") == 0) {
enable_window = false;
}
}
#if !defined(IRON_MACOS) && !defined(IRON_IOS)
iron_internal_set_files_location(bindir);
#endif
iron_threads_init();
iron_display_init();
_kickstart();
#ifdef IRON_AUDIO
iron_a2_shutdown();
#endif
return 0;
}
i32 iron_get_arg_count() {
return _argc;
}
char *iron_get_arg(i32 index) {
return _argv[index];
}
// ██╗██████╗ ██████╗ ███╗ ██╗ █████╗ ██████╗ ██╗
// ██║██╔══██╗██╔═══██╗████╗ ██║ ██╔══██╗██╔══██╗██║
// ██║██████╔╝██║ ██║██╔██╗ ██║ ███████║██████╔╝██║
// ██║██╔══██╗██║ ██║██║╚██╗██║ ██╔══██║██╔═══╝ ██║
// ██║██║ ██║╚██████╔╝██║ ╚████║ ██║ ██║██║ ██║
// ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝
#include "engine.h"
#include "iron_input.h"
#include "iron_math.h"
#include "iron_net.h"
#include "iron_raycast.h"
#include "iron_shape.h"
#include "iron_sys.h"
#include "iron_tween.h"
#include "kong/dir.h"
#include <lz4x.h>
#include <stdio.h>
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#ifdef IRON_DIRECT3D12
#include <d3d12.h>
#endif
#ifdef WITH_D3DCOMPILER
#include <D3Dcompiler.h>
#include <d3d11.h>
#endif
#ifdef WITH_COMPRESS
#include "iron_compress.h"
void untar_here(const char *path);
#endif
#ifdef WITH_IMAGE_WRITE
#include "iron_image.h"
#endif
#ifdef WITH_VIDEO_WRITE
#include "iron_image.h"
#endif
#if defined(IDLE_SLEEP) && !defined(IRON_WINDOWS)
#include <time.h>
#endif
void _update() {
#ifdef IRON_WINDOWS
if (in_background && ++paused_frames > 3) {
Sleep(1);
return;
}
#endif
#ifdef IDLE_SLEEP
if (last_window_width != iron_window_width() || last_window_height != iron_window_height()) {
last_window_width = iron_window_width();
last_window_height = iron_window_height();
paused_frames = 0;
}
#if defined(IRON_IOS) || defined(IRON_ANDROID)
const int start_sleep = 1200;
#else
const int start_sleep = 120;
#endif
if (++paused_frames > start_sleep && !input_down) {
#ifdef IRON_WINDOWS
Sleep(1);
#elif !defined(IRON_WASM)
struct timespec t;
t.tv_sec = 0;
t.tv_nsec = 1000000;
nanosleep(&t, NULL);
#endif
return;
}
#endif
string_tmp_reset();
iron_net_update();
iron_update();
if (ui_get_current())
ui_end_frame();
gpu_present();
}
void _copy(void *data) {
ui_copy();
}
void _cut(void *data) {
ui_cut();
}
void _paste(char *text, void *data) {
ui_paste(text);
}
void _foreground(void *data) {
iron_foreground();
in_background = false;
paused_frames = 0;
}
void _background(void *data) {
iron_background();
in_background = true;
paused_frames = 0;
}
void _shutdown(void *data) {
iron_shutdown();
}
void _key_down(int code, void *data) {
iron_key_down(code);
if (ui_get_current())
ui_key_down(ui_get_current(), code);
#ifdef IDLE_SLEEP
input_down = true;
paused_frames = 0;
#endif
}
void _key_up(int code, void *data) {
iron_key_up(code);
if (ui_get_current())
ui_key_up(ui_get_current(), code);
#ifdef IDLE_SLEEP
input_down = false;
paused_frames = 0;
#endif
}
void _key_press(unsigned int character, void *data) {
if (ui_get_current())
ui_key_press(ui_get_current(), character);
#ifdef IDLE_SLEEP
paused_frames = 0;
#endif
}
void _mouse_down(int button, int x, int y, void *data) {
iron_mouse_down(button, x, y);
if (ui_get_current())
ui_mouse_down(ui_get_current(), button, x, y);
#ifdef IDLE_SLEEP
input_down = true;
paused_frames = 0;
#endif
}
void _mouse_up(int button, int x, int y, void *data) {
iron_mouse_up(button, x, y);
if (ui_get_current())
ui_mouse_up(ui_get_current(), button, x, y);
#ifdef IDLE_SLEEP
input_down = false;
paused_frames = 0;
#endif
}
void _mouse_move(int x, int y, int mx, int my, void *data) {
iron_mouse_move(x, y, mx, my);
if (ui_get_current())
ui_mouse_move(ui_get_current(), x, y, mx, my);
#ifdef IDLE_SLEEP
paused_frames = 0;
#endif
}
void _mouse_wheel(float delta, void *data) {
iron_mouse_wheel(delta);
if (ui_get_current())
ui_mouse_wheel(ui_get_current(), delta);
#ifdef IDLE_SLEEP
paused_frames = 0;
#endif
}
void _touch_move(int index, int x, int y) {
iron_touch_move(index, x, y);
#if defined(IRON_ANDROID) || defined(IRON_IOS)
if (ui_get_current())
ui_touch_move(ui_get_current(), index, x, y);
#endif
#ifdef IDLE_SLEEP
paused_frames = 0;
#endif
}
void _touch_down(int index, int x, int y) {
iron_touch_down(index, x, y);
#if defined(IRON_ANDROID) || defined(IRON_IOS)
if (ui_get_current())
ui_touch_down(ui_get_current(), index, x, y);
#endif
#ifdef IDLE_SLEEP
input_down = true;
paused_frames = 0;
#endif
}
void _touch_up(int index, int x, int y) {
iron_touch_up(index, x, y);
#if defined(IRON_ANDROID) || defined(IRON_IOS)
if (ui_get_current())
ui_touch_up(ui_get_current(), index, x, y);
#endif
#ifdef IDLE_SLEEP
input_down = false;
paused_frames = 0;
#endif
}
void _pen_down(int x, int y, float pressure) {
iron_pen_down(x, y, pressure);
if (ui_get_current())
ui_pen_down(ui_get_current(), x, y, pressure);
#ifdef IDLE_SLEEP
input_down = true;
paused_frames = 0;
#endif
}
void _pen_up(int x, int y, float pressure) {
iron_pen_up(x, y, pressure);
if (ui_get_current())
ui_pen_up(ui_get_current(), x, y, pressure);
#ifdef IDLE_SLEEP
input_down = false;
paused_frames = 0;
#endif
}
void _pen_move(int x, int y, float pressure) {
iron_pen_move(x, y, pressure);
if (ui_get_current())
ui_pen_move(ui_get_current(), x, y, pressure);
#ifdef IDLE_SLEEP
paused_frames = 0;
#endif
}
void _drop_files(char *file_path, void *data) {
// Update mouse position
#ifdef IRON_WINDOWS
POINT p;
GetCursorPos(&p);
ScreenToClient(iron_windows_window_handle(), &p);
_mouse_move(p.x, p.y, 0, 0, NULL);
#endif
iron_drop_files(file_path);
in_background = false;
#ifdef IDLE_SLEEP
paused_frames = 0;
#endif
}
f32 math_floor(f32 x) {
return floorf(x);
}
f32 math_cos(f32 x) {
return cosf(x);
}
f32 math_sin(f32 x) {
return sinf(x);
}
f32 math_tan(f32 x) {
return tanf(x);
}
f32 math_sqrt(f32 x) {
return sqrtf(x);
}
f32 math_abs(f32 x) {
return fabsf(x);
}
f32 math_random() {
return rand() / (float)RAND_MAX;
}
f32 math_atan2(f32 y, f32 x) {
return atan2f(y, x);
}
f32 math_asin(f32 x) {
return asinf(x);
}
f32 math_pi() {
return 3.14159265358979323846;
}
f32 math_pow(f32 x, f32 y) {
return powf(x, y);
}
f32 math_round(f32 x) {
return roundf(x);
}
f32 math_ceil(f32 x) {
return ceilf(x);
}
f32 math_min(f32 x, f32 y) {
return x < y ? x : y;
}
f32 math_max(f32 x, f32 y) {
return x > y ? x : y;
}
f32 math_log(f32 x) {
return logf(x);
}
f32 math_log2(f32 x) {
return log2f(x);
}
f32 math_atan(f32 x) {
return atanf(x);
}
f32 math_acos(f32 x) {
return acosf(x);
}
f32 math_exp(f32 x) {
return expf(x);
}
f32 math_fmod(f32 x, f32 y) {
return fmod(x, y);
}
#ifdef _WIN32
i32 parse_int(const char *s) {
return _strtoi64(s, NULL, 10);
}
i32 parse_int_hex(const char *s) {
return _strtoi64(s, NULL, 16);
}
#else
i32 parse_int(const char *s) {
return strtol(s, NULL, 10);
}
i32 parse_int_hex(const char *s) {
return strtol(s, NULL, 16);
}
#endif
f32 parse_float(const char *s) {
return strtof(s, NULL);
}
i32 color_from_floats(f32 r, f32 g, f32 b, f32 a) {
return ((int)(a * 255) << 24) | ((int)(r * 255) << 16) | ((int)(g * 255) << 8) | (int)(b * 255);
}
u8 color_get_rb(i32 c) {
return (c & 0x00ff0000) >> 16;
}
u8 color_get_gb(i32 c) {
return (c & 0x0000ff00) >> 8;
}
u8 color_get_bb(i32 c) {
return c & 0x000000ff;
}
u8 color_get_ab(i32 c) {
return c & 0x000000ff;
}
i32 color_set_rb(i32 c, u8 i) {
return (color_get_ab(c) << 24) | (i << 16) | (color_get_gb(c) << 8) | color_get_bb(c);
}
i32 color_set_gb(i32 c, u8 i) {
return (color_get_ab(c) << 24) | (color_get_rb(c) << 16) | (i << 8) | color_get_bb(c);
}
i32 color_set_bb(i32 c, u8 i) {
return (color_get_ab(c) << 24) | (color_get_rb(c) << 16) | (color_get_gb(c) << 8) | i;
}
i32 color_set_ab(i32 c, u8 i) {
return (i << 24) | (color_get_rb(c) << 16) | (color_get_gb(c) << 8) | color_get_bb(c);
}
void _iron_init(iron_window_options_t *ops) {
ops->display_index = -1;
ops->visible = enable_window;
ops->color_bits = 32;
iron_init(ops);
iron_random_init((int)(iron_time() * 1000));
iron_set_cut_callback(_cut, NULL);
iron_set_copy_callback(_copy, NULL);
iron_set_paste_callback(_paste, NULL);
iron_keyboard_set_key_press_callback(_key_press, NULL);
}
void _iron_set_update_callback(void (*callback)(void)) {
iron_update = callback;
iron_set_update_callback(_update);
}
void _iron_set_drop_files_callback(void (*callback)(char *)) {
iron_drop_files = callback;
iron_set_drop_files_callback(_drop_files, NULL);
}
void iron_set_application_state_callback(void (*on_foreground)(void), void (*on_background)(void), void (*on_shutdown)(void)) {
iron_set_foreground_callback(on_foreground != NULL ? _foreground : NULL, NULL);
iron_set_background_callback(on_background != NULL ? _background : NULL, NULL);
iron_set_shutdown_callback(on_shutdown != NULL ? _shutdown : NULL, NULL);
iron_foreground = on_foreground;
iron_background = on_background;
iron_shutdown = on_shutdown;
}
void iron_set_keyboard_down_callback(void (*callback)(int)) {
iron_key_down = callback;
iron_keyboard_set_key_down_callback(_key_down, NULL);
}
void iron_set_keyboard_up_callback(void (*callback)(int)) {
iron_key_up = callback;
iron_keyboard_set_key_up_callback(_key_up, NULL);
}
void iron_set_mouse_down_callback(void (*callback)(int, int, int)) {
iron_mouse_down = callback;
iron_mouse_set_press_callback(_mouse_down, NULL);
}
void iron_set_mouse_up_callback(void (*callback)(int, int, int)) {
iron_mouse_up = callback;
iron_mouse_set_release_callback(_mouse_up, NULL);
}
void iron_set_mouse_move_callback(void (*callback)(int, int, int, int)) {
iron_mouse_move = callback;
iron_mouse_set_move_callback(_mouse_move, NULL);
}
void iron_set_mouse_wheel_callback(void (*callback)(float)) {
iron_mouse_wheel = callback;
iron_mouse_set_scroll_callback(_mouse_wheel, NULL);
}
void iron_set_touch_down_callback(void (*callback)(int, int, int)) {
iron_touch_down = callback;
iron_surface_set_touch_start_callback(_touch_down);
}
void iron_set_touch_up_callback(void (*callback)(int, int, int)) {
iron_touch_up = callback;
iron_surface_set_touch_end_callback(_touch_up);
}
void iron_set_touch_move_callback(void (*callback)(int, int, int)) {
iron_touch_move = callback;
iron_surface_set_move_callback(_touch_move);
}
void iron_set_pen_down_callback(void (*callback)(int, int, float)) {
iron_pen_down = callback;
iron_pen_set_press_callback(_pen_down);
}
void iron_set_pen_up_callback(void (*callback)(int, int, float)) {
iron_pen_up = callback;
iron_pen_set_release_callback(_pen_up);
}
void iron_set_pen_move_callback(void (*callback)(int, int, float)) {
iron_pen_move = callback;
iron_pen_set_move_callback(_pen_move);
}
#ifdef WITH_GAMEPAD
void (*iron_gamepad_axis)(int, int, float);
void (*iron_gamepad_button)(int, int, float);
void _gamepad_axis(int gamepad, int axis, float value, void *data) {
iron_gamepad_axis(gamepad, axis, value);
#ifdef IDLE_SLEEP
paused_frames = 0;
#endif
}
void _gamepad_button(int gamepad, int button, float value, void *data) {
iron_gamepad_button(gamepad, button, value);
#ifdef IDLE_SLEEP
paused_frames = 0;
#endif
}
void iron_set_gamepad_axis_callback(void (*callback)(int, int, float)) {
iron_gamepad_axis = callback;
iron_gamepad_set_axis_callback(_gamepad_axis, NULL);
}
void iron_set_gamepad_button_callback(void (*callback)(int, int, float)) {
iron_gamepad_button = callback;
iron_gamepad_set_button_callback(_gamepad_button, NULL);
}
#endif
void gpu_delete_buffer(gpu_buffer_t *buffer) {
gpu_buffer_destroy(buffer);
free(buffer);
}
void *gpu_create_index_buffer(i32 count) {
gpu_buffer_t *buffer = (gpu_buffer_t *)malloc(sizeof(gpu_buffer_t));
gpu_index_buffer_init(buffer, count);
return buffer;
}
void *gpu_create_vertex_buffer(i32 count, gpu_vertex_structure_t *structure) {
gpu_buffer_t *buffer = (gpu_buffer_t *)malloc(sizeof(gpu_buffer_t));
gpu_vertex_buffer_init(buffer, count, structure);
return buffer;
}
gpu_shader_t *gpu_create_shader(buffer_t *data, i32 shader_type) {
gpu_shader_t *shader = (gpu_shader_t *)malloc(sizeof(gpu_shader_t));
gpu_shader_init(shader, data->buffer, data->length, (gpu_shader_type_t)shader_type);
return shader;
}
void gpu_delete_shader(gpu_shader_t *shader) {
gpu_shader_destroy(shader);
free(shader);
}
#ifdef WITH_KONG
void gpu_create_shaders_from_kong(char *kong, char **vs, char **fs, int *vs_size, int *fs_size);
#endif
gpu_shader_t *gpu_create_shader_from_source(char *source, int source_size, gpu_shader_type_t shader_type) {
gpu_shader_t *shader = (gpu_shader_t *)malloc(sizeof(gpu_shader_t));
char *temp_string_s = shader_type == GPU_SHADER_TYPE_VERTEX ? temp_string_vs : temp_string_fs;
#ifdef WITH_D3DCOMPILER
strcpy(temp_string_s, source);
ID3DBlob *error_message = NULL;
ID3DBlob *shader_buffer = NULL;
UINT flags = D3DCOMPILE_SKIP_OPTIMIZATION | D3DCOMPILE_SKIP_VALIDATION;
HRESULT hr = D3DCompile(temp_string_s, strlen(source) + 1, NULL, NULL, NULL, "main", shader_type == GPU_SHADER_TYPE_VERTEX ? "vs_5_0" : "ps_5_0", flags, 0,
&shader_buffer, &error_message);
if (hr != S_OK) {
iron_log("%s", (char *)error_message->lpVtbl->GetBufferPointer(error_message));
return NULL;
}
int size = shader_buffer->lpVtbl->GetBufferSize(shader_buffer);
gpu_shader_init(shader, (char *)shader_buffer->lpVtbl->GetBufferPointer(shader_buffer), size, shader_type);
shader_buffer->lpVtbl->Release(shader_buffer);
#elif defined(IRON_METAL)
strcpy(temp_string_s, source);
gpu_shader_init(shader, temp_string_s, strlen(temp_string_s), shader_type);
#elif defined(IRON_VULKAN)
gpu_shader_init(shader, source, source_size, shader_type);
#elif defined(IRON_WASM)
strcpy(temp_string_s, source);
gpu_shader_init(shader, temp_string_s, strlen(temp_string_s), shader_type);
#endif
return shader;
}
gpu_pipeline_t *gpu_create_pipeline() {
gpu_pipeline_t *pipeline = (gpu_pipeline_t *)malloc(sizeof(gpu_pipeline_t));
gpu_pipeline_init(pipeline);
return pipeline;
}
void gpu_delete_pipeline(gpu_pipeline_t *pipeline) {
gpu_pipeline_destroy(pipeline);
free(pipeline);
}
gpu_texture_t *gpu_create_render_target(i32 width, i32 height, i32 format) {
gpu_texture_t *render_target = (gpu_texture_t *)malloc(sizeof(gpu_texture_t));
gpu_render_target_init(render_target, width, height, (gpu_texture_format_t)format);
render_target->buffer = NULL;
return render_target;
}
gpu_texture_t *gpu_create_texture_from_bytes(buffer_t *data, i32 width, i32 height, i32 format) {
gpu_texture_t *texture = (gpu_texture_t *)malloc(sizeof(gpu_texture_t));
texture->buffer = NULL;
gpu_texture_init_from_bytes(texture, data->buffer, width, height, (gpu_texture_format_t)format);
return texture;
}
gpu_texture_t *gpu_create_texture_from_encoded_bytes(buffer_t *data, char *format) {
if (data == NULL || data->length == 0) {
return NULL;
}
gpu_texture_t *texture = (gpu_texture_t *)malloc(sizeof(gpu_texture_t));
texture->buffer = NULL;
unsigned char *texture_data;
gpu_texture_format_t texture_format;
int width;
int height;
if (ends_with(format, "k")) {
width = iron_read_s32le(data->buffer);
height = iron_read_s32le(data->buffer + 4);
char fourcc[5];
fourcc[0] = data->buffer[8];
fourcc[1] = data->buffer[9];
fourcc[2] = data->buffer[10];
fourcc[3] = data->buffer[11];
fourcc[4] = 0;
int compressed_size = data->length - 12;
if (strcmp(fourcc, "LZ4 ") == 0) {
int output_size = width * height * 4;
texture_data = (unsigned char *)malloc(output_size);
LZ4_decompress_safe((char *)data->buffer + 12, (char *)texture_data, compressed_size, output_size);
texture_format = GPU_TEXTURE_FORMAT_RGBA32;
}
else { // "LZ4F"
int output_size = width * height * 8;
texture_data = (unsigned char *)malloc(output_size);
LZ4_decompress_safe((char *)data->buffer + 12, (char *)texture_data, compressed_size, output_size);
texture_format = GPU_TEXTURE_FORMAT_RGBA64;
}
}
else if (ends_with(format, "hdr")) {
int comp;
texture_data = (unsigned char *)stbi_loadf_from_memory(data->buffer, data->length, &width, &height, &comp, 4);
texture_format = GPU_TEXTURE_FORMAT_RGBA64;
// F32 to F16
float *f32_data = (float *)texture_data;
uint16_t *f16_data = (uint16_t *)texture_data;
for (int i = 0; i < width * height * 4; ++i) {
f16_data[i] = float_to_half_fast(f32_data[i]);
}
}
else { // jpg, png, ..
int comp;
texture_data = stbi_load_from_memory(data->buffer, data->length, &width, &height, &comp, 4);
texture_format = GPU_TEXTURE_FORMAT_RGBA32;
}
// double t = iron_time(); ////
gpu_texture_init_from_bytes(texture, texture_data, width, height, texture_format);
// iron_log("gpu_texture_init_from_bytes in %fs\n", iron_time() - t); ////
free(texture_data);
return texture;
}
void gpu_delete_texture(gpu_texture_t *texture) {
gpu_texture_destroy(texture);
if (texture->buffer != NULL) { // Cached by gpu_get_texture_pixels
free(texture->buffer->buffer);
free(texture->buffer);
}
free(texture);
}
gpu_texture_t *iron_load_texture(char *file) {
#ifdef WITH_EMBED
buffer_t *b = embed_get(file);
if (b != NULL) {
return gpu_create_texture_from_encoded_bytes(b, ".k");
}
#endif
iron_file_reader_t reader;
if (!iron_file_reader_open(&reader, file, IRON_FILE_TYPE_ASSET)) {
return NULL;
}
int size = (int)iron_file_reader_size(&reader);
unsigned char *data = (unsigned char *)malloc(size);
iron_file_reader_read(&reader, data, size);
iron_file_reader_close(&reader);
buffer_t buf;
buf.buffer = data;
buf.length = size;
gpu_texture_t *texture = gpu_create_texture_from_encoded_bytes(&buf, file);
free(data); // Encoded bytes are decoded into a separate buffer
return texture;
}
void *iron_load_sound(char *file) {
#ifdef IRON_AUDIO
iron_a1_init();
iron_a1_sound_t *sound = iron_a1_sound_create(file);
return sound;
#endif
return NULL;
}
buffer_t *iron_load_blob(char *file) {
#ifdef WITH_EMBED
buffer_t *b = embed_get(file);
if (b != NULL) {
return b;
}
#endif
iron_file_reader_t reader;
if (!iron_file_reader_open(&reader, file, IRON_FILE_TYPE_ASSET)) {
return NULL;
}
uint32_t reader_size = (uint32_t)iron_file_reader_size(&reader);
buffer_t *buffer = buffer_create(reader_size);
iron_file_reader_read(&reader, buffer->buffer, reader_size);
iron_file_reader_close(&reader);
return buffer;
}
void iron_delete_blob(buffer_t *buffer) {
if (buffer == NULL) {
return;
}
#ifdef WITH_EMBED
if (embed_owns(buffer->buffer)) {
free(buffer);
return;
}
#endif
array_free(buffer);
free(buffer);
}
i32 iron_display_ppi(i32 index) {
return iron_display_current_mode(index).pixels_per_inch;
}
i32 iron_display_width(i32 index) {
return iron_display_current_mode(index).width;
}
i32 iron_display_height(i32 index) {
return iron_display_current_mode(index).height;
}
i32 iron_display_x(i32 index) {
return iron_display_current_mode(index).x;
}
i32 iron_display_y(i32 index) {
return iron_display_current_mode(index).y;
}
i32 iron_display_frequency(i32 index) {
return iron_display_current_mode(index).frequency;
}
bool iron_display_is_primary(i32 index) {
return index == iron_primary_display();
}
buffer_t *gpu_get_texture_pixels(gpu_texture_t *image) {
if (image->buffer == NULL) {
image->buffer = malloc(sizeof(buffer_t));
image->buffer->buffer = NULL;
}
image->buffer->length = gpu_texture_format_size(image->format) * image->width * image->height;
if (image->buffer->buffer == NULL) {
image->buffer->buffer = malloc(image->buffer->length);
}
gpu_get_render_target_pixels(image, image->buffer->buffer);
#ifdef WITH_BC7
if (image->format == GPU_TEXTURE_FORMAT_RGBA32_BC7) {
uint8_t *compressed = image->buffer->buffer;
image->buffer->buffer = malloc((size_t)image->width * image->height * 4);
bc7enc_decompress(image->buffer->buffer, compressed, image->width, image->height);
free(compressed);
}
#endif
return image->buffer;
}
void _gpu_begin(gpu_texture_t *render_target, any_array_t *additional, gpu_texture_t *depth_buffer, gpu_clear_t flags, unsigned color, float depth) {
if (render_target == NULL) {
gpu_begin(NULL, 0, NULL, flags, color, depth);
}
else {
int32_t length = 1;
gpu_texture_t *render_targets[8] = {render_target, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
if (additional != NULL) {
length = additional->length + 1;
for (int32_t i = 1; i < length; ++i) {
render_targets[i] = additional->buffer[i - 1];
}
}
gpu_begin(render_targets, length, depth_buffer, flags, color, depth);
}
}
bool _save_and_quit_callback_internal();
bool _save_and_quit_callback(void *data) {
return _save_and_quit_callback_internal();
}
void iron_set_save_and_quit_callback(void (*callback)(bool)) {
iron_save_and_quit = callback;
iron_window_set_close_callback(_save_and_quit_callback, NULL);
}
void iron_delay_idle_sleep() {
paused_frames = 0;
}