diff --git a/base/sources/iron.h b/base/sources/iron.h index b914574c..d3b239a1 100644 --- a/base/sources/iron.h +++ b/base/sources/iron.h @@ -221,33 +221,15 @@ string_t *iron_get_arg(i32 index) { #include #include #endif -#ifdef WITH_NFD -#include -#elif defined(IRON_ANDROID) -#include "backends/android_file_dialog.h" -#elif defined(IRON_IOS) -#include "backends/ios_file_dialog.h" -#include -#endif -#ifdef WITH_IMAGE_WRITE #ifdef WITH_COMPRESS -unsigned char *iron_deflate_raw(unsigned char *data, int data_len, int *out_len, int quality); -#define STBIW_ZLIB_COMPRESS iron_deflate_raw +#include "iron_compress.h" void untar_here(const char *path); #endif -#define STBI_WINDOWS_UTF8 -#define STB_IMAGE_WRITE_IMPLEMENTATION -#include +#ifdef WITH_IMAGE_WRITE +#include "iron_image.h" #endif #ifdef WITH_VIDEO_WRITE -#include -#include -#endif -#ifdef WITH_COMPRESS -#define SDEFL_IMPLEMENTATION -#include "sdefl.h" -#define SINFL_IMPLEMENTATION -#include "sinfl.h" +#include "iron_image.h" #endif #if defined(IDLE_SLEEP) && !defined(IRON_WINDOWS) #include @@ -789,178 +771,7 @@ gpu_shader_t *gpu_create_shader(buffer_t *data, i32 shader_type) { } #ifdef WITH_KONG - -#include "../../sources/libs/kong/analyzer.h" -#include "../../sources/libs/kong/backends/hlsl.h" -#include "../../sources/libs/kong/backends/metal.h" -#include "../../sources/libs/kong/backends/spirv.h" -#include "../../sources/libs/kong/backends/wgsl.h" -#include "../../sources/libs/kong/compiler.h" -#include "../../sources/libs/kong/disasm.h" -#include "../../sources/libs/kong/errors.h" -#include "../../sources/libs/kong/functions.h" -#include "../../sources/libs/kong/globals.h" -#include "../../sources/libs/kong/libs/stb_ds.h" -#include "../../sources/libs/kong/log.h" -#include "../../sources/libs/kong/names.h" -#include "../../sources/libs/kong/parser.h" -#include "../../sources/libs/kong/tokenizer.h" -#include "../../sources/libs/kong/transformer.h" -#include "../../sources/libs/kong/typer.h" -#include "../../sources/libs/kong/types.h" - -extern uint64_t next_variable_id; -extern size_t allocated_globals_size; -extern function_id next_function_index; -extern global_id globals_size; -extern name_id names_index; -extern size_t sets_count; -extern type_id next_type_index; -extern size_t vertex_inputs_size; -extern size_t fragment_inputs_size; -extern size_t vertex_functions_size; -extern size_t fragment_functions_size; -extern struct { - char *key; - name_id value; -} *hash; -extern int expression_index; -extern int statement_index; -extern bool kong_error; - -uint64_t _next_variable_id; -size_t _allocated_globals_size; -function_id _next_function_index; -global_id _globals_size; -name_id _names_index; -size_t _sets_count; -type_id _next_type_index; -size_t _vertex_inputs_size; -size_t _fragment_inputs_size; -size_t _vertex_functions_size; -size_t _fragment_functions_size; -struct { - char *key; - name_id value; -} *_hash; -int _expression_index; -int _statement_index; -void hlsl_export2(char **vs, char **fs, api_kind d3d, bool debug); -void spirv_export2(char **vs, char **fs, int *vs_size, int *fs_size, bool debug); -void wgsl_export2(char **vs, char **fs); -void console_info(char *s); - -static struct { - char *key; - name_id value; -} *_clone_hash(struct { - char *key; - name_id value; -} * hash) { - struct { - char *key; - name_id value; - } *clone = NULL; - sh_new_arena(clone); - ptrdiff_t len = shlen(hash); - for (ptrdiff_t i = 0; i < len; i++) { - shput(clone, hash[i].key, hash[i].value); - } - return clone; -} - -void gpu_create_shaders_from_kong(char *kong, char **vs, char **fs, int *vs_size, int *fs_size) { - static bool first = true; - if (first) { - first = false; - names_init(); - types_init(); - functions_init(); - globals_init(); - - _next_variable_id = next_variable_id; - _allocated_globals_size = allocated_globals_size; - _next_function_index = next_function_index; - _globals_size = globals_size; - _names_index = names_index; - _sets_count = sets_count; - _next_type_index = next_type_index; - _vertex_inputs_size = vertex_inputs_size; - _fragment_inputs_size = fragment_inputs_size; - _vertex_functions_size = vertex_functions_size; - _fragment_functions_size = fragment_functions_size; - _hash = _clone_hash(hash); - _expression_index = expression_index; - _statement_index = statement_index; - } - else { - next_variable_id = _next_variable_id; - allocated_globals_size = _allocated_globals_size; - next_function_index = _next_function_index; - globals_size = _globals_size; - names_index = _names_index; - sets_count = _sets_count; - next_type_index = _next_type_index; - vertex_inputs_size = _vertex_inputs_size; - fragment_inputs_size = _fragment_inputs_size; - vertex_functions_size = _vertex_functions_size; - fragment_functions_size = _fragment_functions_size; - shfree(hash); - hash = _clone_hash(_hash); - expression_index = _expression_index; - statement_index = _statement_index; - } - - kong_error = false; - char *from = ""; - tokens tokens = tokenize(from, kong); - parse(from, &tokens); - resolve_types(); - - if (kong_error) { - console_info("Warning: Shader compilation failed"); - free(tokens.t); -#if defined(__APPLE__) - *vs = ""; - *fs = ""; -#endif - return; - } - allocate_globals(); - for (function_id i = 0; get_function(i) != NULL; ++i) { - compile_function_block(&get_function(i)->code, get_function(i)->block); - } - analyze(); - -#ifdef _WIN32 - - hlsl_export2(vs, fs, API_DIRECT3D11, false); - -#elif defined(__APPLE__) - - static char vs_temp[1024 * 128]; - strcpy(vs_temp, "//>kong_vert\n"); - char *metal = metal_export(""); - strcat(vs_temp, metal); - *vs = &vs_temp[0]; - *fs = "//>kong_frag\n"; - free(metal); - -#elif defined(IRON_WASM) - - transform(TRANSFORM_FLAG_ONE_COMPONENT_SWIZZLE); - wgsl_export2(vs, fs); - -#else - - transform(TRANSFORM_FLAG_ONE_COMPONENT_SWIZZLE | TRANSFORM_FLAG_BINARY_UNIFY_LENGTH); - spirv_export2(vs, fs, vs_size, fs_size, false); - -#endif - - free(tokens.t); -} - +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(string_t *source, int source_size, gpu_shader_type_t shader_type) { @@ -1199,8 +1010,6 @@ void _gpu_begin(gpu_texture_t *render_target, any_array_t *additional, gpu_textu } } - - bool _save_and_quit_callback_internal(); bool _save_and_quit_callback(void *data) { @@ -1216,366 +1025,4 @@ void iron_delay_idle_sleep() { paused_frames = 0; } -#ifdef WITH_NFD -char_ptr_array_t *iron_open_dialog(char *filter_list, char *default_path, bool open_multiple) { - nfdpathset_t out_paths; - nfdchar_t *out_path; - nfdresult_t result = open_multiple ? NFD_OpenDialogMultiple(filter_list, default_path, &out_paths) : NFD_OpenDialog(filter_list, default_path, &out_path); - - if (result == NFD_OKAY) { - int path_count = open_multiple ? (int)NFD_PathSet_GetCount(&out_paths) : 1; - char_ptr_array_t *result = any_array_create(path_count); - - if (open_multiple) { - for (int i = 0; i < path_count; ++i) { - nfdchar_t *out_path = NFD_PathSet_GetPath(&out_paths, i); - result->buffer[i] = out_path; - } - // NFD_PathSet_Free(&out_paths); - } - else { - result->buffer[0] = out_path; - // free(out_path); - } - return result; - } - return NULL; -} - -static char iron_save_dialog_path[512]; - -char *iron_save_dialog(char *filter_list, char *default_path) { - nfdchar_t *out_path = NULL; - nfdresult_t result = NFD_SaveDialog(filter_list, default_path, &out_path); - if (result == NFD_OKAY) { - strcpy(iron_save_dialog_path, out_path); - free(out_path); - return iron_save_dialog_path; - } - return NULL; -} - -#elif defined(IRON_ANDROID) - -char_ptr_array_t *iron_open_dialog(char *filter_list, char *default_path, bool open_multiple) { - AndroidFileDialogOpen(); - return NULL; -} - -char *iron_save_dialog(char *filter_list, char *default_path) { - wchar_t *out_path = AndroidFileDialogSave(); - wcstombs(temp_string, out_path, sizeof(temp_string)); - return temp_string; -} - -#elif defined(IRON_IOS) - -char_ptr_array_t *iron_open_dialog(char *filter_list, char *default_path, bool open_multiple) { - // Once finished drop_files callback is called - IOSFileDialogOpen(); - return NULL; -} - -char *iron_save_dialog(char *filter_list, char *default_path) { - // Path to app document directory - wchar_t *out_path = IOSFileDialogSave(); - wcstombs(temp_string, out_path, sizeof(temp_string)); - return temp_string; -} - -#elif defined(IRON_WASM) - -__attribute__((import_module("imports"), import_name("js_open_dialog"))) void js_open_dialog(); -__attribute__((import_module("imports"), import_name("js_save_dialog"))) char *js_save_dialog(); - -char_ptr_array_t *iron_open_dialog(char *filter_list, char *default_path, bool open_multiple) { - js_open_dialog(); - return NULL; -} - -char *iron_save_dialog(char *filter_list, char *default_path) { - return js_save_dialog(); -} - -#endif - -#ifdef WITH_COMPRESS -buffer_t *iron_inflate(buffer_t *bytes, bool raw) { - unsigned char *inflated = NULL; - int inflated_len = bytes->length * 2; - int out_len; - while (1) { - inflated = (unsigned char *)realloc(inflated, inflated_len); - out_len = raw ? sinflate(inflated, inflated_len, bytes->buffer, bytes->length) : zsinflate(inflated, inflated_len, bytes->buffer, bytes->length); - if (out_len >= 0 && out_len < inflated_len) { - break; - } - inflated_len *= 2; - } - buffer_t *output = buffer_create(0); - output->buffer = inflated; - output->length = out_len; - return output; -} - -buffer_t *iron_deflate(buffer_t *bytes, bool raw) { - struct sdefl sdefl; - memset(&sdefl, 0, sizeof(sdefl)); - void *deflated = malloc(sdefl_bound(bytes->length)); - int out_len = raw ? sdeflate(&sdefl, deflated, bytes->buffer, bytes->length, SDEFL_LVL_MIN) - : zsdeflate(&sdefl, deflated, bytes->buffer, bytes->length, SDEFL_LVL_MIN); - buffer_t *output = buffer_create(0); - output->buffer = deflated; - output->length = out_len; - return output; -} - -unsigned char *iron_deflate_raw(unsigned char *data, int data_len, int *out_len, int quality) { - struct sdefl sdefl; - memset(&sdefl, 0, sizeof(sdefl)); - void *deflated = malloc(sdefl_bound(data_len)); - *out_len = zsdeflate(&sdefl, deflated, data, data_len, SDEFL_LVL_MIN); - return (unsigned char *)deflated; -} -#endif - -#ifdef WITH_IMAGE_WRITE -void _write_image(char *path, buffer_t *bytes, i32 w, i32 h, i32 format, int image_format, int quality) { - int comp = 0; - unsigned char *pixels = NULL; - unsigned char *rgba = (unsigned char *)bytes->buffer; - if (format == 0) { // RGBA - comp = 4; -#ifdef IRON_BGRA - pixels = (unsigned char *)malloc(w * h * comp); - for (int i = 0; i < w * h; ++i) { - pixels[i * 4] = rgba[i * 4 + 2]; - pixels[i * 4 + 1] = rgba[i * 4 + 1]; - pixels[i * 4 + 2] = rgba[i * 4]; - pixels[i * 4 + 3] = rgba[i * 4 + 3]; - } -#else - pixels = rgba; -#endif - } - else if (format == 1) { // R - comp = 1; - pixels = rgba; - } - else if (format == 2) { // RGB1 - comp = 3; - pixels = (unsigned char *)malloc(w * h * comp); - for (int i = 0; i < w * h; ++i) { -#ifdef IRON_BGRA - pixels[i * 3] = rgba[i * 4 + 2]; - pixels[i * 3 + 1] = rgba[i * 4 + 1]; - pixels[i * 3 + 2] = rgba[i * 4]; -#else - pixels[i * 3] = rgba[i * 4]; - pixels[i * 3 + 1] = rgba[i * 4 + 1]; - pixels[i * 3 + 2] = rgba[i * 4 + 2]; -#endif - } - } - else if (format > 2) { // RRR1, GGG1, BBB1, AAA1 - comp = 1; - pixels = (unsigned char *)malloc(w * h * comp); - int off = format - 3; -#ifdef IRON_BGRA - off = 2 - off; -#endif - for (int i = 0; i < w * h; ++i) { - pixels[i] = rgba[i * 4 + off]; - } - } - - image_format == 0 ? stbi_write_jpg(path, w, h, comp, pixels, quality) : stbi_write_png(path, w, h, comp, pixels, w * comp); - - if (pixels != rgba) { - free(pixels); - } -} - -void iron_write_jpg(char *path, buffer_t *bytes, i32 w, i32 h, i32 format, i32 quality) { - // RGBA, R, RGB1, RRR1, GGG1, BBB1, AAA1 - _write_image(path, bytes, w, h, format, 0, quality); -} - -void iron_write_png(char *path, buffer_t *bytes, i32 w, i32 h, i32 format) { - _write_image(path, bytes, w, h, format, 1, 100); -} - -unsigned char *_encode_data; -int _encode_size; -void _encode_image_func(void *context, void *data, int size) { - memcpy(_encode_data + _encode_size, data, size); - _encode_size += size; -} - -buffer_t *_encode_image(buffer_t *bytes, i32 w, i32 h, i32 format, i32 quality) { -#ifdef IRON_BGRA - unsigned char *pixels = bytes->buffer; - for (int i = 0; i < w * h; ++i) { - unsigned char c = pixels[i * 4]; - pixels[i * 4] = pixels[i * 4 + 2]; - pixels[i * 4 + 2] = c; - } -#endif - _encode_data = (unsigned char *)malloc(w * h * 4); - _encode_size = 0; - format == 0 ? stbi_write_jpg_to_func(&_encode_image_func, NULL, w, h, 4, bytes->buffer, quality) - : stbi_write_png_to_func(&_encode_image_func, NULL, w, h, 4, bytes->buffer, w * 4); - buffer_t *buffer = malloc(sizeof(buffer_t)); - buffer->buffer = _encode_data; - buffer->length = _encode_size; - return buffer; -} - -buffer_t *iron_encode_jpg(buffer_t *bytes, i32 w, i32 h, i32 format, i32 quality) { - return _encode_image(bytes, w, h, 0, quality); -} - -buffer_t *iron_encode_png(buffer_t *bytes, i32 w, i32 h, i32 format) { - return _encode_image(bytes, w, h, 1, 100); -} -#endif - -#ifdef WITH_VIDEO_WRITE - -static FILE *iron_mp4_fp; -static int iron_mp4_w; -static int iron_mp4_h; -static int iron_mp4_stride; -static H264E_persist_t *iron_mp4_enc = NULL; -static H264E_scratch_t *iron_mp4_scratch = NULL; -static char iron_mp4_path[512]; -static char iron_mp4_path_264[512]; -static uint8_t *iron_mp4_yuv_buf; - -static size_t iron_mp4_get_nal_size(uint8_t *buf, size_t size) { - size_t pos = 3; - while ((size - pos) > 3) { - if (buf[pos] == 0 && buf[pos + 1] == 0 && buf[pos + 2] == 1) { - return pos; - } - if (buf[pos] == 0 && buf[pos + 1] == 0 && buf[pos + 2] == 0 && buf[pos + 3] == 1) { - return pos; - } - pos++; - } - return size; -} - -static int iron_mp4_write_callback(int64_t offset, const void *buffer, size_t size, void *token) { - FILE *f = (FILE *)token; - fseek(f, offset, SEEK_SET); - return fwrite(buffer, 1, size, f) != size; -} - -void iron_mp4_begin(char *path, i32 w, i32 h) { - strcpy(iron_mp4_path, path); - strcpy(iron_mp4_path_264, path); - int len = strlen(iron_mp4_path_264); - iron_mp4_path_264[len - 1] = '4'; - iron_mp4_path_264[len - 2] = '6'; - iron_mp4_path_264[len - 3] = '2'; - - iron_mp4_stride = w; - iron_mp4_w = w - w % 16; - iron_mp4_h = h - h % 16; - - H264E_create_param_t create_param = {0}; - create_param.width = iron_mp4_w; - create_param.height = iron_mp4_h; - int sizeof_persist = 0; - int sizeof_scratch = 0; - H264E_sizeof(&create_param, &sizeof_persist, &sizeof_scratch); - - iron_mp4_enc = (H264E_persist_t *)malloc(sizeof_persist); - iron_mp4_scratch = (H264E_scratch_t *)malloc(sizeof_scratch); - H264E_init(iron_mp4_enc, &create_param); - - iron_mp4_fp = fopen(iron_mp4_path_264, "wb"); - int frame_size = (int)(iron_mp4_w * iron_mp4_h * 1.5); - iron_mp4_yuv_buf = malloc(frame_size); -} - -void iron_mp4_end() { - if (iron_mp4_fp == NULL) { - return; - } - - buffer_t *blob = iron_load_blob(iron_mp4_path_264); - uint8_t *buf = blob->buffer; - size_t buf_size = blob->length; - FILE *fout = fopen(iron_mp4_path, "wb"); - MP4E_mux_t *mux = MP4E_open(0, 0, fout, iron_mp4_write_callback); - mp4_h26x_writer_t mp4wr; - mp4_h26x_write_init(&mp4wr, mux, iron_mp4_w, iron_mp4_h, false); - - while (buf_size > 0) { - size_t nal_size = iron_mp4_get_nal_size(buf, buf_size); - if (nal_size < 4) { - buf += 1; - buf_size -= 1; - continue; - } - - int fps = 24; - mp4_h26x_write_nal(&mp4wr, buf, nal_size, 90000 / fps); - buf += nal_size; - buf_size -= nal_size; - } - - MP4E_close(mux); - mp4_h26x_write_close(&mp4wr); - free(iron_mp4_enc); - free(iron_mp4_scratch); - free(iron_mp4_yuv_buf); - fclose(fout); - fclose(iron_mp4_fp); - iron_mp4_fp = NULL; -} - -void iron_mp4_encode(buffer_t *pixels) { - // rgba to yuv420p - for (int i = 0; i < iron_mp4_w; ++i) { - for (int j = 0; j < iron_mp4_h; ++j) { - int k = i + j * iron_mp4_stride; - uint8_t r = pixels->buffer[k * 4]; - uint8_t g = pixels->buffer[k * 4 + 1]; - uint8_t b = pixels->buffer[k * 4 + 2]; - uint8_t y = ((66 * r + 129 * g + 25 * b + 128) / 256) + 16; - uint8_t u = ((-38 * r - 74 * g + 112 * b + 128) / 256) + 128; - uint8_t v = ((112 * r - 94 * g - 18 * b + 128) / 256) + 128; - int l = i + j * iron_mp4_w; - int m = i / 2 + j / 2 * (iron_mp4_w / 2); - iron_mp4_yuv_buf[l] = y; - iron_mp4_yuv_buf[iron_mp4_w * iron_mp4_h + m] = u; - iron_mp4_yuv_buf[iron_mp4_w * iron_mp4_h + (iron_mp4_w * iron_mp4_h) / 4 + m] = v; - } - } - - H264E_run_param_t run_param = {0}; - run_param.frame_type = 0; - run_param.encode_speed = H264E_SPEED_SLOWEST; // H264E_SPEED_FASTEST; - run_param.desired_frame_bytes = (2048 * 4) * 1000 / 8 / 30; // 2048 * 4 kbps - run_param.qp_min = 10; - run_param.qp_max = 50; - - H264E_io_yuv_t yuv; - yuv.yuv[0] = iron_mp4_yuv_buf; - yuv.stride[0] = iron_mp4_w; - yuv.yuv[1] = iron_mp4_yuv_buf + iron_mp4_w * iron_mp4_h; - yuv.stride[1] = iron_mp4_w / 2; - yuv.yuv[2] = iron_mp4_yuv_buf + (int)(iron_mp4_w * iron_mp4_h * 1.25); - yuv.stride[2] = iron_mp4_w / 2; - - uint8_t *coded_data; - int sizeof_coded_data; - H264E_encode(iron_mp4_enc, iron_mp4_scratch, &run_param, &yuv, &coded_data, &sizeof_coded_data); - fwrite(coded_data, sizeof_coded_data, 1, iron_mp4_fp); -} -#endif - #endif // NO_IRON_API diff --git a/base/sources/iron_compress.c b/base/sources/iron_compress.c new file mode 100644 index 00000000..caa47f2b --- /dev/null +++ b/base/sources/iron_compress.c @@ -0,0 +1,49 @@ + +#ifdef WITH_COMPRESS + +#include "iron_compress.h" + +#define SDEFL_IMPLEMENTATION +#include "sdefl.h" +#define SINFL_IMPLEMENTATION +#include "sinfl.h" + +buffer_t *iron_inflate(buffer_t *bytes, bool raw) { + unsigned char *inflated = NULL; + int inflated_len = bytes->length * 2; + int out_len; + while (1) { + inflated = (unsigned char *)realloc(inflated, inflated_len); + out_len = raw ? sinflate(inflated, inflated_len, bytes->buffer, bytes->length) : zsinflate(inflated, inflated_len, bytes->buffer, bytes->length); + if (out_len >= 0 && out_len < inflated_len) { + break; + } + inflated_len *= 2; + } + buffer_t *output = buffer_create(0); + output->buffer = inflated; + output->length = out_len; + return output; +} + +buffer_t *iron_deflate(buffer_t *bytes, bool raw) { + struct sdefl sdefl; + memset(&sdefl, 0, sizeof(sdefl)); + void *deflated = malloc(sdefl_bound(bytes->length)); + int out_len = raw ? sdeflate(&sdefl, deflated, bytes->buffer, bytes->length, SDEFL_LVL_MIN) + : zsdeflate(&sdefl, deflated, bytes->buffer, bytes->length, SDEFL_LVL_MIN); + buffer_t *output = buffer_create(0); + output->buffer = deflated; + output->length = out_len; + return output; +} + +unsigned char *iron_deflate_raw(unsigned char *data, int data_len, int *out_len, int quality) { + struct sdefl sdefl; + memset(&sdefl, 0, sizeof(sdefl)); + void *deflated = malloc(sdefl_bound(data_len)); + *out_len = zsdeflate(&sdefl, deflated, data, data_len, SDEFL_LVL_MIN); + return (unsigned char *)deflated; +} + +#endif diff --git a/base/sources/iron_compress.h b/base/sources/iron_compress.h new file mode 100644 index 00000000..eed9f557 --- /dev/null +++ b/base/sources/iron_compress.h @@ -0,0 +1,8 @@ +#pragma once + +#include "iron_array.h" +#include + +buffer_t *iron_inflate(buffer_t *bytes, bool raw); +buffer_t *iron_deflate(buffer_t *bytes, bool raw); +unsigned char *iron_deflate_raw(unsigned char *data, int data_len, int *out_len, int quality); diff --git a/base/sources/iron_image.c b/base/sources/iron_image.c new file mode 100644 index 00000000..bbafb14b --- /dev/null +++ b/base/sources/iron_image.c @@ -0,0 +1,255 @@ + +#include "iron_image.h" + +#ifdef WITH_IMAGE_WRITE + +#ifdef WITH_COMPRESS +unsigned char *iron_deflate_raw(unsigned char *data, int data_len, int *out_len, int quality); +#define STBIW_ZLIB_COMPRESS iron_deflate_raw +#endif +#define STBI_WINDOWS_UTF8 +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include + +void _write_image(char *path, buffer_t *bytes, i32 w, i32 h, i32 format, int image_format, int quality) { + int comp = 0; + unsigned char *pixels = NULL; + unsigned char *rgba = (unsigned char *)bytes->buffer; + if (format == 0) { // RGBA + comp = 4; +#ifdef IRON_BGRA + pixels = (unsigned char *)malloc(w * h * comp); + for (int i = 0; i < w * h; ++i) { + pixels[i * 4] = rgba[i * 4 + 2]; + pixels[i * 4 + 1] = rgba[i * 4 + 1]; + pixels[i * 4 + 2] = rgba[i * 4]; + pixels[i * 4 + 3] = rgba[i * 4 + 3]; + } +#else + pixels = rgba; +#endif + } + else if (format == 1) { // R + comp = 1; + pixels = rgba; + } + else if (format == 2) { // RGB1 + comp = 3; + pixels = (unsigned char *)malloc(w * h * comp); + for (int i = 0; i < w * h; ++i) { +#ifdef IRON_BGRA + pixels[i * 3] = rgba[i * 4 + 2]; + pixels[i * 3 + 1] = rgba[i * 4 + 1]; + pixels[i * 3 + 2] = rgba[i * 4]; +#else + pixels[i * 3] = rgba[i * 4]; + pixels[i * 3 + 1] = rgba[i * 4 + 1]; + pixels[i * 3 + 2] = rgba[i * 4 + 2]; +#endif + } + } + else if (format > 2) { // RRR1, GGG1, BBB1, AAA1 + comp = 1; + pixels = (unsigned char *)malloc(w * h * comp); + int off = format - 3; +#ifdef IRON_BGRA + off = 2 - off; +#endif + for (int i = 0; i < w * h; ++i) { + pixels[i] = rgba[i * 4 + off]; + } + } + + image_format == 0 ? stbi_write_jpg(path, w, h, comp, pixels, quality) : stbi_write_png(path, w, h, comp, pixels, w * comp); + + if (pixels != rgba) { + free(pixels); + } +} + +void iron_write_jpg(char *path, buffer_t *bytes, i32 w, i32 h, i32 format, i32 quality) { + // RGBA, R, RGB1, RRR1, GGG1, BBB1, AAA1 + _write_image(path, bytes, w, h, format, 0, quality); +} + +void iron_write_png(char *path, buffer_t *bytes, i32 w, i32 h, i32 format) { + _write_image(path, bytes, w, h, format, 1, 100); +} + +unsigned char *_encode_data; +int _encode_size; +void _encode_image_func(void *context, void *data, int size) { + memcpy(_encode_data + _encode_size, data, size); + _encode_size += size; +} + +buffer_t *_encode_image(buffer_t *bytes, i32 w, i32 h, i32 format, i32 quality) { +#ifdef IRON_BGRA + unsigned char *pixels = bytes->buffer; + for (int i = 0; i < w * h; ++i) { + unsigned char c = pixels[i * 4]; + pixels[i * 4] = pixels[i * 4 + 2]; + pixels[i * 4 + 2] = c; + } +#endif + _encode_data = (unsigned char *)malloc(w * h * 4); + _encode_size = 0; + format == 0 ? stbi_write_jpg_to_func(&_encode_image_func, NULL, w, h, 4, bytes->buffer, quality) + : stbi_write_png_to_func(&_encode_image_func, NULL, w, h, 4, bytes->buffer, w * 4); + buffer_t *buffer = malloc(sizeof(buffer_t)); + buffer->buffer = _encode_data; + buffer->length = _encode_size; + return buffer; +} + +buffer_t *iron_encode_jpg(buffer_t *bytes, i32 w, i32 h, i32 format, i32 quality) { + return _encode_image(bytes, w, h, 0, quality); +} + +buffer_t *iron_encode_png(buffer_t *bytes, i32 w, i32 h, i32 format) { + return _encode_image(bytes, w, h, 1, 100); +} +#endif + +#ifdef WITH_VIDEO_WRITE + +#include +#include + +buffer_t *iron_load_blob(char *file); + +static FILE *iron_mp4_fp; +static int iron_mp4_w; +static int iron_mp4_h; +static int iron_mp4_stride; +static H264E_persist_t *iron_mp4_enc = NULL; +static H264E_scratch_t *iron_mp4_scratch = NULL; +static char iron_mp4_path[512]; +static char iron_mp4_path_264[512]; +static uint8_t *iron_mp4_yuv_buf; + +static size_t iron_mp4_get_nal_size(uint8_t *buf, size_t size) { + size_t pos = 3; + while ((size - pos) > 3) { + if (buf[pos] == 0 && buf[pos + 1] == 0 && buf[pos + 2] == 1) { + return pos; + } + if (buf[pos] == 0 && buf[pos + 1] == 0 && buf[pos + 2] == 0 && buf[pos + 3] == 1) { + return pos; + } + pos++; + } + return size; +} + +static int iron_mp4_write_callback(int64_t offset, const void *buffer, size_t size, void *token) { + FILE *f = (FILE *)token; + fseek(f, offset, SEEK_SET); + return fwrite(buffer, 1, size, f) != size; +} + +void iron_mp4_begin(char *path, i32 w, i32 h) { + strcpy(iron_mp4_path, path); + strcpy(iron_mp4_path_264, path); + int len = strlen(iron_mp4_path_264); + iron_mp4_path_264[len - 1] = '4'; + iron_mp4_path_264[len - 2] = '6'; + iron_mp4_path_264[len - 3] = '2'; + + iron_mp4_stride = w; + iron_mp4_w = w - w % 16; + iron_mp4_h = h - h % 16; + + H264E_create_param_t create_param = {0}; + create_param.width = iron_mp4_w; + create_param.height = iron_mp4_h; + int sizeof_persist = 0; + int sizeof_scratch = 0; + H264E_sizeof(&create_param, &sizeof_persist, &sizeof_scratch); + + iron_mp4_enc = (H264E_persist_t *)malloc(sizeof_persist); + iron_mp4_scratch = (H264E_scratch_t *)malloc(sizeof_scratch); + H264E_init(iron_mp4_enc, &create_param); + + iron_mp4_fp = fopen(iron_mp4_path_264, "wb"); + int frame_size = (int)(iron_mp4_w * iron_mp4_h * 1.5); + iron_mp4_yuv_buf = malloc(frame_size); +} + +void iron_mp4_end() { + if (iron_mp4_fp == NULL) { + return; + } + + buffer_t *blob = iron_load_blob(iron_mp4_path_264); + uint8_t *buf = blob->buffer; + size_t buf_size = blob->length; + FILE *fout = fopen(iron_mp4_path, "wb"); + MP4E_mux_t *mux = MP4E_open(0, 0, fout, iron_mp4_write_callback); + mp4_h26x_writer_t mp4wr; + mp4_h26x_write_init(&mp4wr, mux, iron_mp4_w, iron_mp4_h, false); + + while (buf_size > 0) { + size_t nal_size = iron_mp4_get_nal_size(buf, buf_size); + if (nal_size < 4) { + buf += 1; + buf_size -= 1; + continue; + } + + int fps = 24; + mp4_h26x_write_nal(&mp4wr, buf, nal_size, 90000 / fps); + buf += nal_size; + buf_size -= nal_size; + } + + MP4E_close(mux); + mp4_h26x_write_close(&mp4wr); + free(iron_mp4_enc); + free(iron_mp4_scratch); + free(iron_mp4_yuv_buf); + fclose(fout); + fclose(iron_mp4_fp); + iron_mp4_fp = NULL; +} + +void iron_mp4_encode(buffer_t *pixels) { + // rgba to yuv420p + for (int i = 0; i < iron_mp4_w; ++i) { + for (int j = 0; j < iron_mp4_h; ++j) { + int k = i + j * iron_mp4_stride; + uint8_t r = pixels->buffer[k * 4]; + uint8_t g = pixels->buffer[k * 4 + 1]; + uint8_t b = pixels->buffer[k * 4 + 2]; + uint8_t y = ((66 * r + 129 * g + 25 * b + 128) / 256) + 16; + uint8_t u = ((-38 * r - 74 * g + 112 * b + 128) / 256) + 128; + uint8_t v = ((112 * r - 94 * g - 18 * b + 128) / 256) + 128; + int l = i + j * iron_mp4_w; + int m = i / 2 + j / 2 * (iron_mp4_w / 2); + iron_mp4_yuv_buf[l] = y; + iron_mp4_yuv_buf[iron_mp4_w * iron_mp4_h + m] = u; + iron_mp4_yuv_buf[iron_mp4_w * iron_mp4_h + (iron_mp4_w * iron_mp4_h) / 4 + m] = v; + } + } + + H264E_run_param_t run_param = {0}; + run_param.frame_type = 0; + run_param.encode_speed = H264E_SPEED_SLOWEST; // H264E_SPEED_FASTEST; + run_param.desired_frame_bytes = (2048 * 4) * 1000 / 8 / 30; // 2048 * 4 kbps + run_param.qp_min = 10; + run_param.qp_max = 50; + + H264E_io_yuv_t yuv; + yuv.yuv[0] = iron_mp4_yuv_buf; + yuv.stride[0] = iron_mp4_w; + yuv.yuv[1] = iron_mp4_yuv_buf + iron_mp4_w * iron_mp4_h; + yuv.stride[1] = iron_mp4_w / 2; + yuv.yuv[2] = iron_mp4_yuv_buf + (int)(iron_mp4_w * iron_mp4_h * 1.25); + yuv.stride[2] = iron_mp4_w / 2; + + uint8_t *coded_data; + int sizeof_coded_data; + H264E_encode(iron_mp4_enc, iron_mp4_scratch, &run_param, &yuv, &coded_data, &sizeof_coded_data); + fwrite(coded_data, sizeof_coded_data, 1, iron_mp4_fp); +} +#endif diff --git a/base/sources/iron_image.h b/base/sources/iron_image.h new file mode 100644 index 00000000..104934fd --- /dev/null +++ b/base/sources/iron_image.h @@ -0,0 +1,13 @@ +#pragma once + +#include "iron_global.h" +#include "iron_array.h" + +void iron_write_jpg(char *path, buffer_t *bytes, i32 w, i32 h, i32 format, i32 quality); +void iron_write_png(char *path, buffer_t *bytes, i32 w, i32 h, i32 format); +buffer_t *iron_encode_jpg(buffer_t *bytes, i32 w, i32 h, i32 format, i32 quality); +buffer_t *iron_encode_png(buffer_t *bytes, i32 w, i32 h, i32 format); + +void iron_mp4_begin(char *path, i32 w, i32 h); +void iron_mp4_end(); +void iron_mp4_encode(buffer_t *pixels); diff --git a/base/sources/iron_system.c b/base/sources/iron_system.c index 8fa60459..26c7a361 100644 --- a/base/sources/iron_system.c +++ b/base/sources/iron_system.c @@ -652,3 +652,94 @@ i32 iron_sys_command(char *cmd) { #endif return result; } + +#ifdef WITH_NFD + +#include + +char_ptr_array_t *iron_open_dialog(char *filter_list, char *default_path, bool open_multiple) { + nfdpathset_t out_paths; + nfdchar_t *out_path; + nfdresult_t result = open_multiple ? NFD_OpenDialogMultiple(filter_list, default_path, &out_paths) : NFD_OpenDialog(filter_list, default_path, &out_path); + + if (result == NFD_OKAY) { + int path_count = open_multiple ? (int)NFD_PathSet_GetCount(&out_paths) : 1; + char_ptr_array_t *result = any_array_create(path_count); + + if (open_multiple) { + for (int i = 0; i < path_count; ++i) { + nfdchar_t *out_path = NFD_PathSet_GetPath(&out_paths, i); + result->buffer[i] = out_path; + } + // NFD_PathSet_Free(&out_paths); + } + else { + result->buffer[0] = out_path; + // free(out_path); + } + return result; + } + return NULL; +} + +static char iron_save_dialog_path[512]; + +char *iron_save_dialog(char *filter_list, char *default_path) { + nfdchar_t *out_path = NULL; + nfdresult_t result = NFD_SaveDialog(filter_list, default_path, &out_path); + if (result == NFD_OKAY) { + strcpy(iron_save_dialog_path, out_path); + free(out_path); + return iron_save_dialog_path; + } + return NULL; +} + +#elif defined(IRON_ANDROID) + +#include "backends/android_file_dialog.h" + +char_ptr_array_t *iron_open_dialog(char *filter_list, char *default_path, bool open_multiple) { + AndroidFileDialogOpen(); + return NULL; +} + +char *iron_save_dialog(char *filter_list, char *default_path) { + wchar_t *out_path = AndroidFileDialogSave(); + wcstombs(temp_string, out_path, sizeof(temp_string)); + return temp_string; +} + +#elif defined(IRON_IOS) + +#include "backends/ios_file_dialog.h" +#include + +char_ptr_array_t *iron_open_dialog(char *filter_list, char *default_path, bool open_multiple) { + // Once finished drop_files callback is called + IOSFileDialogOpen(); + return NULL; +} + +char *iron_save_dialog(char *filter_list, char *default_path) { + // Path to app document directory + wchar_t *out_path = IOSFileDialogSave(); + wcstombs(temp_string, out_path, sizeof(temp_string)); + return temp_string; +} + +#elif defined(IRON_WASM) + +__attribute__((import_module("imports"), import_name("js_open_dialog"))) void js_open_dialog(); +__attribute__((import_module("imports"), import_name("js_save_dialog"))) char *js_save_dialog(); + +char_ptr_array_t *iron_open_dialog(char *filter_list, char *default_path, bool open_multiple) { + js_open_dialog(); + return NULL; +} + +char *iron_save_dialog(char *filter_list, char *default_path) { + return js_save_dialog(); +} + +#endif diff --git a/base/sources/iron_system.h b/base/sources/iron_system.h index 31159968..212e132b 100644 --- a/base/sources/iron_system.h +++ b/base/sources/iron_system.h @@ -1,6 +1,7 @@ #pragma once #include "iron_global.h" +#include "iron_array.h" #include #include #include @@ -334,3 +335,5 @@ void iron_internal_gamepad_trigger_button(int gamepad, int button, float #endif i32 iron_sys_command(char *cmd); +char_ptr_array_t *iron_open_dialog(char *filter_list, char *default_path, bool open_multiple); +char *iron_save_dialog(char *filter_list, char *default_path); diff --git a/base/sources/libs/kong/kong.c b/base/sources/libs/kong/kong.c index 41ad1685..fe220b79 100644 --- a/base/sources/libs/kong/kong.c +++ b/base/sources/libs/kong/kong.c @@ -62,3 +62,174 @@ static void read_file(char *filename) { } typedef enum integration_kind { INTEGRATION_KORE3 } integration_kind; + +#include "analyzer.h" +#include "backends/hlsl.h" +#include "backends/metal.h" +#include "backends/spirv.h" +#include "backends/wgsl.h" +#include "compiler.h" +#include "disasm.h" +#include "errors.h" +#include "functions.h" +#include "globals.h" +#include "libs/stb_ds.h" +#include "log.h" +#include "names.h" +#include "parser.h" +#include "tokenizer.h" +#include "transformer.h" +#include "typer.h" +#include "types.h" + +extern uint64_t next_variable_id; +extern size_t allocated_globals_size; +extern function_id next_function_index; +extern global_id globals_size; +extern name_id names_index; +extern size_t sets_count; +extern type_id next_type_index; +extern size_t vertex_inputs_size; +extern size_t fragment_inputs_size; +extern size_t vertex_functions_size; +extern size_t fragment_functions_size; +extern struct { + char *key; + name_id value; +} *hash; +extern int expression_index; +extern int statement_index; +extern bool kong_error; + +uint64_t _next_variable_id; +size_t _allocated_globals_size; +function_id _next_function_index; +global_id _globals_size; +name_id _names_index; +size_t _sets_count; +type_id _next_type_index; +size_t _vertex_inputs_size; +size_t _fragment_inputs_size; +size_t _vertex_functions_size; +size_t _fragment_functions_size; +struct { + char *key; + name_id value; +} *_hash; +int _expression_index; +int _statement_index; +void hlsl_export2(char **vs, char **fs, api_kind d3d, bool debug); +void spirv_export2(char **vs, char **fs, int *vs_size, int *fs_size, bool debug); +void wgsl_export2(char **vs, char **fs); +void console_info(char *s); + +static struct { + char *key; + name_id value; +} *_clone_hash(struct { + char *key; + name_id value; +} * hash) { + struct { + char *key; + name_id value; + } *clone = NULL; + sh_new_arena(clone); + ptrdiff_t len = shlen(hash); + for (ptrdiff_t i = 0; i < len; i++) { + shput(clone, hash[i].key, hash[i].value); + } + return clone; +} + +void gpu_create_shaders_from_kong(char *kong, char **vs, char **fs, int *vs_size, int *fs_size) { + static bool first = true; + if (first) { + first = false; + names_init(); + types_init(); + functions_init(); + globals_init(); + + _next_variable_id = next_variable_id; + _allocated_globals_size = allocated_globals_size; + _next_function_index = next_function_index; + _globals_size = globals_size; + _names_index = names_index; + _sets_count = sets_count; + _next_type_index = next_type_index; + _vertex_inputs_size = vertex_inputs_size; + _fragment_inputs_size = fragment_inputs_size; + _vertex_functions_size = vertex_functions_size; + _fragment_functions_size = fragment_functions_size; + _hash = _clone_hash(hash); + _expression_index = expression_index; + _statement_index = statement_index; + } + else { + next_variable_id = _next_variable_id; + allocated_globals_size = _allocated_globals_size; + next_function_index = _next_function_index; + globals_size = _globals_size; + names_index = _names_index; + sets_count = _sets_count; + next_type_index = _next_type_index; + vertex_inputs_size = _vertex_inputs_size; + fragment_inputs_size = _fragment_inputs_size; + vertex_functions_size = _vertex_functions_size; + fragment_functions_size = _fragment_functions_size; + shfree(hash); + hash = _clone_hash(_hash); + expression_index = _expression_index; + statement_index = _statement_index; + } + + kong_error = false; + char *from = ""; + tokens tokens = tokenize(from, kong); + parse(from, &tokens); + resolve_types(); + + if (kong_error) { + console_info("Warning: Shader compilation failed"); + free(tokens.t); +#if defined(__APPLE__) + *vs = ""; + *fs = ""; +#endif + return; + } + allocate_globals(); + for (function_id i = 0; get_function(i) != NULL; ++i) { + compile_function_block(&get_function(i)->code, get_function(i)->block); + } + analyze(); + +#ifdef _WIN32 + + hlsl_export2(vs, fs, API_DIRECT3D11, false); + +#elif defined(__APPLE__) + + static char vs_temp[1024 * 128]; + strcpy(vs_temp, "//>kong_vert\n"); + char *metal = metal_export(""); + strcat(vs_temp, metal); + *vs = &vs_temp[0]; + *fs = "//>kong_frag\n"; + free(metal); + +#elif defined(IRON_WASM) + + transform(TRANSFORM_FLAG_ONE_COMPONENT_SWIZZLE); + wgsl_export2(vs, fs); + +#else + + transform(TRANSFORM_FLAG_ONE_COMPONENT_SWIZZLE | TRANSFORM_FLAG_BINARY_UNIFY_LENGTH); + spirv_export2(vs, fs, vs_size, fs_size, false); + +#endif + + free(tokens.t); +}