diff --git a/.gitignore b/.gitignore index 73c73d4..a670ada 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -app.* \ No newline at end of file +app.* +.vscode/c_cpp_properties.json \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 03e34c7..a68ad47 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -21,6 +21,7 @@ "includePath": [ "${workspaceFolder}/../sokol", "${workspaceFolder}/../sokol_gp", + "${workspaceFolder}/../cimgui", "${workspaceFolder}/../flecs/distr" ], "defines": [ @@ -29,7 +30,7 @@ "_UNICODE" ], "windowsSdkVersion": "10.0.22621.0", - "compilerPath": "C:\\Users\\c.pons\\Documents\\Perso\\Git\\emsdk\\upstream\\emscripten\\emcc.bat", + "compilerPath": "D:\\UserDefaults\\Desktop\\Dev\\Git\\emsdk\\upstream\\emscripten\\emcc.bat", "cStandard": "c17", "cppStandard": "c++17", "intelliSenseMode": "windows-clang-x64", @@ -46,7 +47,6 @@ "-sUSE_WEBGL2", "-sASSERTIONS", "-sWASM_BIGINT", - "-pthread", "-sFILESYSTEM=0", "-sALLOW_MEMORY_GROWTH=1", "-sSTACK_SIZE=1mb", diff --git a/.vscode/settings.json b/.vscode/settings.json index 12f5689..8b3a62b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -22,6 +22,12 @@ "syslog.h": "c", "base.h": "c", "stdarg.h": "c", - "rand.h": "c" + "rand.h": "c", + "sokol_gfx_imgui.h": "c", + "cimgui.h": "c", + "sokol_imgui.h": "c", + "typeinfo": "c", + "api.h": "c", + "sprite.h": "c" } } \ No newline at end of file diff --git a/build.sh b/build.sh index 0b8082d..288e7fa 100644 --- a/build.sh +++ b/build.sh @@ -1 +1,20 @@ -emcc -O3 src/main.c -o app.html -sUSE_WEBGL2 -sWASM_BIGINT -sALLOW_MEMORY_GROWTH -pthread -I../sokol -I../sokol_gp -I../flecs/distr --shell-file=shell.html -sFILESYSTEM=0 \ No newline at end of file +emcc -O3 src/main.c -o app.html -sUSE_WEBGPU -sWASM_BIGINT -sALLOW_MEMORY_GROWTH -I../sokol -I../sokol_gp -I../cimgui -msimd128 -flto --llvm-lto 1 --shell-file=shell.html -sFILESYSTEM=0 + +emcc -O3 src/main.c \ + ../cimgui/cimgui.cpp \ + ../cimgui/imgui.cpp \ + ../cimgui/imgui_draw.cpp \ + ../cimgui/imgui_tables.cpp \ + ../cimgui/imgui_widgets.cpp \ + -o app.html \ + -sUSE_WEBGPU \ + -sWASM_BIGINT \ + -sALLOW_MEMORY_GROWTH \ + -I../sokol \ + -I../sokol_gp \ + -I../cimgui \ + -I../flecs/distr \ + -msimd128 \ + -flto \ + --shell-file=shell.html \ + -sFILESYSTEM=0 \ No newline at end of file diff --git a/debug.sh b/debug.sh index 6dfc5ce..21341e7 100644 --- a/debug.sh +++ b/debug.sh @@ -1,2 +1,19 @@ xxd -i src/shaders/sprite.wgsl src/generated/sprite.h -emcc src/main.c -o app.html -sUSE_WEBGPU -sASSERTIONS -sWASM_BIGINT -sALLOW_MEMORY_GROWTH -pthread -I../sokol -I../sokol_gp -I../flecs/distr --shell-file=shell.html -sFILESYSTEM=0 -g \ No newline at end of file +emcc src/main.c \ + ../cimgui/cimgui.cpp \ + ../cimgui/imgui.cpp \ + ../cimgui/imgui_draw.cpp \ + ../cimgui/imgui_tables.cpp \ + ../cimgui/imgui_widgets.cpp \ + -o app.html \ + -sUSE_WEBGPU \ + -sASSERTIONS \ + -sWASM_BIGINT \ + -sALLOW_MEMORY_GROWTH \ + -I../sokol \ + -I../sokol_gp \ + -I../cimgui \ + -I../flecs/distr \ + -msimd128 \ + --shell-file=shell.html \ + -sFILESYSTEM=0 \ No newline at end of file diff --git a/src/api.h b/src/api.h new file mode 100644 index 0000000..60fdd5b --- /dev/null +++ b/src/api.h @@ -0,0 +1,27 @@ +#ifndef API_DEFINITION +#define API_DEFINITION + +#define SOKOL_IMPL +#define SOKOL_WGPU + +#include "cimgui.h" +#include "sokol_gfx.h" +#include "sokol_app.h" +#include "sokol_glue.h" +#include "sokol_log.h" +#include "util/sokol_memtrack.h" +#include "util/sokol_imgui.h" + +#include "math.h" +#include "rand.h" +#include "util.h" +#include "sprite.h" + +#include "generated/sprite.h" + +#include +#include +#include +#include + +#endif \ No newline at end of file diff --git a/src/generated/base.h b/src/generated/base.h deleted file mode 100644 index f0f7a5f..0000000 --- a/src/generated/base.h +++ /dev/null @@ -1,427 +0,0 @@ -#pragma once -/* - #version:1# (machine generated, don't edit!) - - Generated by sokol-shdc (https://github.com/floooh/sokol-tools) - - Cmdline: - sokol-shdc --slang=wgsl -i src/shaders/base.glsl -o src/generated/base.h --ifdef - - Overview: - ========= - Shader program: 'base': - Get shader desc: base_shader_desc(sg_query_backend()); - Vertex Shader: vs - Fragment Shader: fs - Attributes: - ATTR_base_in_quad => 0 - Bindings: - Uniform block 'vs_uniform': - C struct: vs_uniform_t - Bind slot: UB_vs_uniform => 0 - Uniform block 'fs_uniform': - C struct: fs_uniform_t - Bind slot: UB_fs_uniform => 1 - Storage buffer 'vs_ssbo': - C struct: cell_t - Bind slot: SBUF_vs_ssbo => 0 - Readonly: true -*/ -#if !defined(SOKOL_GFX_INCLUDED) -#error "Please include sokol_gfx.h before base.h" -#endif -#if !defined(SOKOL_SHDC_ALIGN) -#if defined(_MSC_VER) -#define SOKOL_SHDC_ALIGN(a) __declspec(align(a)) -#else -#define SOKOL_SHDC_ALIGN(a) __attribute__((aligned(a))) -#endif -#endif -#define ATTR_base_in_quad (0) -#define UB_vs_uniform (0) -#define UB_fs_uniform (1) -#define SBUF_vs_ssbo (0) -#pragma pack(push,1) -SOKOL_SHDC_ALIGN(16) typedef struct vs_uniform_t { - float radius; - uint8_t _pad_4[12]; -} vs_uniform_t; -#pragma pack(pop) -#pragma pack(push,1) -SOKOL_SHDC_ALIGN(16) typedef struct fs_uniform_t { - float radius; - uint8_t _pad_4[12]; -} fs_uniform_t; -#pragma pack(pop) -#pragma pack(push,1) -SOKOL_SHDC_ALIGN(8) typedef struct cell_t { - float pos[2]; -} cell_t; -#pragma pack(pop) -/* - diagnostic(off, derivative_uniformity); - - struct cell { - /_ @offset(0) _/ - pos : vec2f, - } - - alias RTArr = array; - - struct vs_ssbo { - /_ @offset(0) _/ - cells : RTArr, - } - - struct vs_uniform { - /_ @offset(0) _/ - radius : f32, - } - - var x_centroid : vec2f; - - @group(1) @binding(32) var x_51 : vs_ssbo; - - var gl_InstanceIndex : i32; - - var x_color : vec3f; - - var x_quad : vec2f; - - @group(0) @binding(0) var x_66 : vs_uniform; - - var in_quad : vec2f; - - var gl_Position : vec4f; - - fn color_i1_(i : ptr) -> vec3f { - var r : f32; - var g : f32; - var b : f32; - let x_16 : i32 = *(i); - r = (f32(((x_16 >> bitcast(0i)) & 255i)) / 255.0f); - let x_25 : i32 = *(i); - g = (f32(((x_25 >> bitcast(8i)) & 255i)) / 255.0f); - let x_32 : i32 = *(i); - b = (f32(((x_32 >> bitcast(16i)) & 255i)) / 255.0f); - let x_38 : f32 = r; - let x_39 : f32 = g; - let x_40 : f32 = b; - return vec3f(x_38, x_39, x_40); - } - - fn main_1() { - var param : i32; - let x_54 : i32 = gl_InstanceIndex; - let x_57 : vec2f = x_51.cells[x_54].pos; - x_centroid = x_57; - let x_61 : i32 = gl_InstanceIndex; - param = x_61; - let x_62 : vec3f = color_i1_(&(param)); - x_color = x_62; - let x_69 : f32 = x_66.radius; - let x_72 : vec2f = in_quad; - let x_74 : vec2f = x_centroid; - x_quad = ((x_72 * x_69) + x_74); - let x_83 : vec2f = x_quad; - gl_Position = vec4f(x_83.x, x_83.y, 0.0f, 1.0f); - return; - } - - struct main_out { - @location(2) - x_centroid_1 : vec2f, - @location(3) @interpolate(flat) - x_color_1 : vec3f, - @location(1) - x_quad_1 : vec2f, - @builtin(position) - gl_Position : vec4f, - } - - @vertex - fn main(@builtin(instance_index) gl_InstanceIndex_param : u32, @location(0) in_quad_param : vec2f) -> main_out { - gl_InstanceIndex = bitcast(gl_InstanceIndex_param); - in_quad = in_quad_param; - main_1(); - return main_out(x_centroid, x_color, x_quad, gl_Position); - } - -*/ -#if defined(SOKOL_WGPU) -static const uint8_t vs_source_wgsl[1944] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20, - 0x63,0x65,0x6c,0x6c,0x20,0x7b,0x0a,0x20,0x20,0x2f,0x2a,0x20,0x40,0x6f,0x66,0x66, - 0x73,0x65,0x74,0x28,0x30,0x29,0x20,0x2a,0x2f,0x0a,0x20,0x20,0x70,0x6f,0x73,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x61,0x6c,0x69,0x61, - 0x73,0x20,0x52,0x54,0x41,0x72,0x72,0x20,0x3d,0x20,0x61,0x72,0x72,0x61,0x79,0x3c, - 0x63,0x65,0x6c,0x6c,0x3e,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x76, - 0x73,0x5f,0x73,0x73,0x62,0x6f,0x20,0x7b,0x0a,0x20,0x20,0x2f,0x2a,0x20,0x40,0x6f, - 0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x20,0x2a,0x2f,0x0a,0x20,0x20,0x63,0x65, - 0x6c,0x6c,0x73,0x20,0x3a,0x20,0x52,0x54,0x41,0x72,0x72,0x2c,0x0a,0x7d,0x0a,0x0a, - 0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x76,0x73,0x5f,0x75,0x6e,0x69,0x66,0x6f,0x72, - 0x6d,0x20,0x7b,0x0a,0x20,0x20,0x2f,0x2a,0x20,0x40,0x6f,0x66,0x66,0x73,0x65,0x74, - 0x28,0x30,0x29,0x20,0x2a,0x2f,0x0a,0x20,0x20,0x72,0x61,0x64,0x69,0x75,0x73,0x20, - 0x3a,0x20,0x66,0x33,0x32,0x2c,0x0a,0x7d,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72, - 0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x78,0x5f,0x63,0x65,0x6e,0x74,0x72,0x6f,0x69, - 0x64,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x40,0x67,0x72,0x6f, - 0x75,0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x33, - 0x32,0x29,0x20,0x76,0x61,0x72,0x3c,0x73,0x74,0x6f,0x72,0x61,0x67,0x65,0x2c,0x20, - 0x72,0x65,0x61,0x64,0x3e,0x20,0x78,0x5f,0x35,0x31,0x20,0x3a,0x20,0x76,0x73,0x5f, - 0x73,0x73,0x62,0x6f,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61, - 0x74,0x65,0x3e,0x20,0x67,0x6c,0x5f,0x49,0x6e,0x73,0x74,0x61,0x6e,0x63,0x65,0x49, - 0x6e,0x64,0x65,0x78,0x20,0x3a,0x20,0x69,0x33,0x32,0x3b,0x0a,0x0a,0x76,0x61,0x72, - 0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x78,0x5f,0x63,0x6f,0x6c,0x6f, - 0x72,0x20,0x3a,0x20,0x76,0x65,0x63,0x33,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c, - 0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x78,0x5f,0x71,0x75,0x61,0x64,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75,0x70, - 0x28,0x30,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x30,0x29,0x20, - 0x76,0x61,0x72,0x3c,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x3e,0x20,0x78,0x5f,0x36, - 0x36,0x20,0x3a,0x20,0x76,0x73,0x5f,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x3b,0x0a, - 0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x69,0x6e, - 0x5f,0x71,0x75,0x61,0x64,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a, - 0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x67,0x6c,0x5f, - 0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, - 0x3b,0x0a,0x0a,0x66,0x6e,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x69,0x31,0x5f,0x28, - 0x69,0x20,0x3a,0x20,0x70,0x74,0x72,0x3c,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e, - 0x2c,0x20,0x69,0x33,0x32,0x3e,0x29,0x20,0x2d,0x3e,0x20,0x76,0x65,0x63,0x33,0x66, - 0x20,0x7b,0x0a,0x20,0x20,0x76,0x61,0x72,0x20,0x72,0x20,0x3a,0x20,0x66,0x33,0x32, - 0x3b,0x0a,0x20,0x20,0x76,0x61,0x72,0x20,0x67,0x20,0x3a,0x20,0x66,0x33,0x32,0x3b, - 0x0a,0x20,0x20,0x76,0x61,0x72,0x20,0x62,0x20,0x3a,0x20,0x66,0x33,0x32,0x3b,0x0a, - 0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x31,0x36,0x20,0x3a,0x20,0x69,0x33,0x32, - 0x20,0x3d,0x20,0x2a,0x28,0x69,0x29,0x3b,0x0a,0x20,0x20,0x72,0x20,0x3d,0x20,0x28, - 0x66,0x33,0x32,0x28,0x28,0x28,0x78,0x5f,0x31,0x36,0x20,0x3e,0x3e,0x20,0x62,0x69, - 0x74,0x63,0x61,0x73,0x74,0x3c,0x75,0x33,0x32,0x3e,0x28,0x30,0x69,0x29,0x29,0x20, - 0x26,0x20,0x32,0x35,0x35,0x69,0x29,0x29,0x20,0x2f,0x20,0x32,0x35,0x35,0x2e,0x30, - 0x66,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x35,0x20,0x3a, - 0x20,0x69,0x33,0x32,0x20,0x3d,0x20,0x2a,0x28,0x69,0x29,0x3b,0x0a,0x20,0x20,0x67, - 0x20,0x3d,0x20,0x28,0x66,0x33,0x32,0x28,0x28,0x28,0x78,0x5f,0x32,0x35,0x20,0x3e, - 0x3e,0x20,0x62,0x69,0x74,0x63,0x61,0x73,0x74,0x3c,0x75,0x33,0x32,0x3e,0x28,0x38, - 0x69,0x29,0x29,0x20,0x26,0x20,0x32,0x35,0x35,0x69,0x29,0x29,0x20,0x2f,0x20,0x32, - 0x35,0x35,0x2e,0x30,0x66,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f, - 0x33,0x32,0x20,0x3a,0x20,0x69,0x33,0x32,0x20,0x3d,0x20,0x2a,0x28,0x69,0x29,0x3b, - 0x0a,0x20,0x20,0x62,0x20,0x3d,0x20,0x28,0x66,0x33,0x32,0x28,0x28,0x28,0x78,0x5f, - 0x33,0x32,0x20,0x3e,0x3e,0x20,0x62,0x69,0x74,0x63,0x61,0x73,0x74,0x3c,0x75,0x33, - 0x32,0x3e,0x28,0x31,0x36,0x69,0x29,0x29,0x20,0x26,0x20,0x32,0x35,0x35,0x69,0x29, - 0x29,0x20,0x2f,0x20,0x32,0x35,0x35,0x2e,0x30,0x66,0x29,0x3b,0x0a,0x20,0x20,0x6c, - 0x65,0x74,0x20,0x78,0x5f,0x33,0x38,0x20,0x3a,0x20,0x66,0x33,0x32,0x20,0x3d,0x20, - 0x72,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x33,0x39,0x20,0x3a,0x20, - 0x66,0x33,0x32,0x20,0x3d,0x20,0x67,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78, - 0x5f,0x34,0x30,0x20,0x3a,0x20,0x66,0x33,0x32,0x20,0x3d,0x20,0x62,0x3b,0x0a,0x20, - 0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x76,0x65,0x63,0x33,0x66,0x28,0x78,0x5f, - 0x33,0x38,0x2c,0x20,0x78,0x5f,0x33,0x39,0x2c,0x20,0x78,0x5f,0x34,0x30,0x29,0x3b, - 0x0a,0x7d,0x0a,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20, - 0x7b,0x0a,0x20,0x20,0x76,0x61,0x72,0x20,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20, - 0x69,0x33,0x32,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x35,0x34,0x20, - 0x3a,0x20,0x69,0x33,0x32,0x20,0x3d,0x20,0x67,0x6c,0x5f,0x49,0x6e,0x73,0x74,0x61, - 0x6e,0x63,0x65,0x49,0x6e,0x64,0x65,0x78,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20, - 0x78,0x5f,0x35,0x37,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x20,0x3d,0x20,0x78, - 0x5f,0x35,0x31,0x2e,0x63,0x65,0x6c,0x6c,0x73,0x5b,0x78,0x5f,0x35,0x34,0x5d,0x2e, - 0x70,0x6f,0x73,0x3b,0x0a,0x20,0x20,0x78,0x5f,0x63,0x65,0x6e,0x74,0x72,0x6f,0x69, - 0x64,0x20,0x3d,0x20,0x78,0x5f,0x35,0x37,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20, - 0x78,0x5f,0x36,0x31,0x20,0x3a,0x20,0x69,0x33,0x32,0x20,0x3d,0x20,0x67,0x6c,0x5f, - 0x49,0x6e,0x73,0x74,0x61,0x6e,0x63,0x65,0x49,0x6e,0x64,0x65,0x78,0x3b,0x0a,0x20, - 0x20,0x70,0x61,0x72,0x61,0x6d,0x20,0x3d,0x20,0x78,0x5f,0x36,0x31,0x3b,0x0a,0x20, - 0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x36,0x32,0x20,0x3a,0x20,0x76,0x65,0x63,0x33, - 0x66,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x69,0x31,0x5f,0x28,0x26,0x28, - 0x70,0x61,0x72,0x61,0x6d,0x29,0x29,0x3b,0x0a,0x20,0x20,0x78,0x5f,0x63,0x6f,0x6c, - 0x6f,0x72,0x20,0x3d,0x20,0x78,0x5f,0x36,0x32,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74, - 0x20,0x78,0x5f,0x36,0x39,0x20,0x3a,0x20,0x66,0x33,0x32,0x20,0x3d,0x20,0x78,0x5f, - 0x36,0x36,0x2e,0x72,0x61,0x64,0x69,0x75,0x73,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74, - 0x20,0x78,0x5f,0x37,0x32,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x20,0x3d,0x20, - 0x69,0x6e,0x5f,0x71,0x75,0x61,0x64,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78, - 0x5f,0x37,0x34,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x20,0x3d,0x20,0x78,0x5f, - 0x63,0x65,0x6e,0x74,0x72,0x6f,0x69,0x64,0x3b,0x0a,0x20,0x20,0x78,0x5f,0x71,0x75, - 0x61,0x64,0x20,0x3d,0x20,0x28,0x28,0x78,0x5f,0x37,0x32,0x20,0x2a,0x20,0x78,0x5f, - 0x36,0x39,0x29,0x20,0x2b,0x20,0x78,0x5f,0x37,0x34,0x29,0x3b,0x0a,0x20,0x20,0x6c, - 0x65,0x74,0x20,0x78,0x5f,0x38,0x33,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x20, - 0x3d,0x20,0x78,0x5f,0x71,0x75,0x61,0x64,0x3b,0x0a,0x20,0x20,0x67,0x6c,0x5f,0x50, - 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x66,0x28, - 0x78,0x5f,0x38,0x33,0x2e,0x78,0x2c,0x20,0x78,0x5f,0x38,0x33,0x2e,0x79,0x2c,0x20, - 0x30,0x2e,0x30,0x66,0x2c,0x20,0x31,0x2e,0x30,0x66,0x29,0x3b,0x0a,0x20,0x20,0x72, - 0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a,0x7d,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74, - 0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x40,0x6c, - 0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x32,0x29,0x0a,0x20,0x20,0x78,0x5f,0x63, - 0x65,0x6e,0x74,0x72,0x6f,0x69,0x64,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x32, - 0x66,0x2c,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x33, - 0x29,0x20,0x40,0x69,0x6e,0x74,0x65,0x72,0x70,0x6f,0x6c,0x61,0x74,0x65,0x28,0x66, - 0x6c,0x61,0x74,0x29,0x0a,0x20,0x20,0x78,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x31, - 0x20,0x3a,0x20,0x76,0x65,0x63,0x33,0x66,0x2c,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63, - 0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x0a,0x20,0x20,0x78,0x5f,0x71,0x75,0x61, - 0x64,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x0a,0x20,0x20,0x40, - 0x62,0x75,0x69,0x6c,0x74,0x69,0x6e,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, - 0x29,0x0a,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40,0x76,0x65,0x72, - 0x74,0x65,0x78,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x28,0x40,0x62,0x75,0x69, - 0x6c,0x74,0x69,0x6e,0x28,0x69,0x6e,0x73,0x74,0x61,0x6e,0x63,0x65,0x5f,0x69,0x6e, - 0x64,0x65,0x78,0x29,0x20,0x67,0x6c,0x5f,0x49,0x6e,0x73,0x74,0x61,0x6e,0x63,0x65, - 0x49,0x6e,0x64,0x65,0x78,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x75,0x33, - 0x32,0x2c,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x20, - 0x69,0x6e,0x5f,0x71,0x75,0x61,0x64,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20, - 0x76,0x65,0x63,0x32,0x66,0x29,0x20,0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f, - 0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x67,0x6c,0x5f,0x49,0x6e,0x73,0x74,0x61,0x6e, - 0x63,0x65,0x49,0x6e,0x64,0x65,0x78,0x20,0x3d,0x20,0x62,0x69,0x74,0x63,0x61,0x73, - 0x74,0x3c,0x69,0x33,0x32,0x3e,0x28,0x67,0x6c,0x5f,0x49,0x6e,0x73,0x74,0x61,0x6e, - 0x63,0x65,0x49,0x6e,0x64,0x65,0x78,0x5f,0x70,0x61,0x72,0x61,0x6d,0x29,0x3b,0x0a, - 0x20,0x20,0x69,0x6e,0x5f,0x71,0x75,0x61,0x64,0x20,0x3d,0x20,0x69,0x6e,0x5f,0x71, - 0x75,0x61,0x64,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x6d,0x61,0x69, - 0x6e,0x5f,0x31,0x28,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20, - 0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x28,0x78,0x5f,0x63,0x65,0x6e,0x74,0x72, - 0x6f,0x69,0x64,0x2c,0x20,0x78,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x2c,0x20,0x78,0x5f, - 0x71,0x75,0x61,0x64,0x2c,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f, - 0x6e,0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#endif -/* - diagnostic(off, derivative_uniformity); - - struct fs_uniform { - /_ @offset(0) _/ - radius : f32, - } - - var gl_FragDepth : f32; - - var x_quad : vec2f; - - var x_centroid : vec2f; - - @group(0) @binding(8) var x_20 : fs_uniform; - - var frag_color : vec4f; - - var x_color : vec3f; - - fn main_1() { - let x_12 : vec2f = x_quad; - let x_14 : vec2f = x_centroid; - gl_FragDepth = length((x_12 - x_14)); - let x_17 : f32 = gl_FragDepth; - let x_25 : f32 = x_20.radius; - if ((x_17 > x_25)) { - discard; - } - let x_37 : vec3f = x_color; - frag_color = vec4f(x_37.x, x_37.y, x_37.z, 1.0f); - return; - } - - struct main_out { - @builtin(frag_depth) - gl_FragDepth_1 : f32, - @location(0) - frag_color_1 : vec4f, - } - - @fragment - fn main(@location(1) x_quad_param : vec2f, @location(2) x_centroid_param : vec2f, @location(3) @interpolate(flat) x_color_param : vec3f) -> main_out { - x_quad = x_quad_param; - x_centroid = x_centroid_param; - x_color = x_color_param; - main_1(); - return main_out(gl_FragDepth, frag_color); - } - -*/ -#if defined(SOKOL_WGPU) -static const uint8_t fs_source_wgsl[1047] = { - 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, - 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, - 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20, - 0x66,0x73,0x5f,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x7b,0x0a,0x20,0x20,0x2f, - 0x2a,0x20,0x40,0x6f,0x66,0x66,0x73,0x65,0x74,0x28,0x30,0x29,0x20,0x2a,0x2f,0x0a, - 0x20,0x20,0x72,0x61,0x64,0x69,0x75,0x73,0x20,0x3a,0x20,0x66,0x33,0x32,0x2c,0x0a, - 0x7d,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20, - 0x67,0x6c,0x5f,0x46,0x72,0x61,0x67,0x44,0x65,0x70,0x74,0x68,0x20,0x3a,0x20,0x66, - 0x33,0x32,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65, - 0x3e,0x20,0x78,0x5f,0x71,0x75,0x61,0x64,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66, - 0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20, - 0x78,0x5f,0x63,0x65,0x6e,0x74,0x72,0x6f,0x69,0x64,0x20,0x3a,0x20,0x76,0x65,0x63, - 0x32,0x66,0x3b,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75,0x70,0x28,0x30,0x29,0x20,0x40, - 0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x38,0x29,0x20,0x76,0x61,0x72,0x3c,0x75, - 0x6e,0x69,0x66,0x6f,0x72,0x6d,0x3e,0x20,0x78,0x5f,0x32,0x30,0x20,0x3a,0x20,0x66, - 0x73,0x5f,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c, - 0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f, - 0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x76,0x61, - 0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x78,0x5f,0x63,0x6f,0x6c, - 0x6f,0x72,0x20,0x3a,0x20,0x76,0x65,0x63,0x33,0x66,0x3b,0x0a,0x0a,0x66,0x6e,0x20, - 0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20,0x7b,0x0a,0x20,0x20,0x6c,0x65,0x74, - 0x20,0x78,0x5f,0x31,0x32,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x20,0x3d,0x20, - 0x78,0x5f,0x71,0x75,0x61,0x64,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f, - 0x31,0x34,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x20,0x3d,0x20,0x78,0x5f,0x63, - 0x65,0x6e,0x74,0x72,0x6f,0x69,0x64,0x3b,0x0a,0x20,0x20,0x67,0x6c,0x5f,0x46,0x72, - 0x61,0x67,0x44,0x65,0x70,0x74,0x68,0x20,0x3d,0x20,0x6c,0x65,0x6e,0x67,0x74,0x68, - 0x28,0x28,0x78,0x5f,0x31,0x32,0x20,0x2d,0x20,0x78,0x5f,0x31,0x34,0x29,0x29,0x3b, - 0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x31,0x37,0x20,0x3a,0x20,0x66,0x33, - 0x32,0x20,0x3d,0x20,0x67,0x6c,0x5f,0x46,0x72,0x61,0x67,0x44,0x65,0x70,0x74,0x68, - 0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x35,0x20,0x3a,0x20,0x66, - 0x33,0x32,0x20,0x3d,0x20,0x78,0x5f,0x32,0x30,0x2e,0x72,0x61,0x64,0x69,0x75,0x73, - 0x3b,0x0a,0x20,0x20,0x69,0x66,0x20,0x28,0x28,0x78,0x5f,0x31,0x37,0x20,0x3e,0x20, - 0x78,0x5f,0x32,0x35,0x29,0x29,0x20,0x7b,0x0a,0x20,0x20,0x20,0x20,0x64,0x69,0x73, - 0x63,0x61,0x72,0x64,0x3b,0x0a,0x20,0x20,0x7d,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20, - 0x78,0x5f,0x33,0x37,0x20,0x3a,0x20,0x76,0x65,0x63,0x33,0x66,0x20,0x3d,0x20,0x78, - 0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63, - 0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x66,0x28,0x78,0x5f,0x33, - 0x37,0x2e,0x78,0x2c,0x20,0x78,0x5f,0x33,0x37,0x2e,0x79,0x2c,0x20,0x78,0x5f,0x33, - 0x37,0x2e,0x7a,0x2c,0x20,0x31,0x2e,0x30,0x66,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65, - 0x74,0x75,0x72,0x6e,0x3b,0x0a,0x7d,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20, - 0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x40,0x62,0x75, - 0x69,0x6c,0x74,0x69,0x6e,0x28,0x66,0x72,0x61,0x67,0x5f,0x64,0x65,0x70,0x74,0x68, - 0x29,0x0a,0x20,0x20,0x67,0x6c,0x5f,0x46,0x72,0x61,0x67,0x44,0x65,0x70,0x74,0x68, - 0x5f,0x31,0x20,0x3a,0x20,0x66,0x33,0x32,0x2c,0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63, - 0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x5f, - 0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c, - 0x0a,0x7d,0x0a,0x0a,0x40,0x66,0x72,0x61,0x67,0x6d,0x65,0x6e,0x74,0x0a,0x66,0x6e, - 0x20,0x6d,0x61,0x69,0x6e,0x28,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28, - 0x31,0x29,0x20,0x78,0x5f,0x71,0x75,0x61,0x64,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20, - 0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69, - 0x6f,0x6e,0x28,0x32,0x29,0x20,0x78,0x5f,0x63,0x65,0x6e,0x74,0x72,0x6f,0x69,0x64, - 0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x20, - 0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x33,0x29,0x20,0x40,0x69,0x6e, - 0x74,0x65,0x72,0x70,0x6f,0x6c,0x61,0x74,0x65,0x28,0x66,0x6c,0x61,0x74,0x29,0x20, - 0x78,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20,0x3a,0x20, - 0x76,0x65,0x63,0x33,0x66,0x29,0x20,0x2d,0x3e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f, - 0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x78,0x5f,0x71,0x75,0x61,0x64,0x20,0x3d,0x20, - 0x78,0x5f,0x71,0x75,0x61,0x64,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20, - 0x78,0x5f,0x63,0x65,0x6e,0x74,0x72,0x6f,0x69,0x64,0x20,0x3d,0x20,0x78,0x5f,0x63, - 0x65,0x6e,0x74,0x72,0x6f,0x69,0x64,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20, - 0x20,0x78,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x78,0x5f,0x63,0x6f,0x6c, - 0x6f,0x72,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x6d,0x61,0x69,0x6e, - 0x5f,0x31,0x28,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6d, - 0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x28,0x67,0x6c,0x5f,0x46,0x72,0x61,0x67,0x44, - 0x65,0x70,0x74,0x68,0x2c,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, - 0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, -}; -#endif -static inline const sg_shader_desc* base_shader_desc(sg_backend backend) { - #if defined(SOKOL_WGPU) - if (backend == SG_BACKEND_WGPU) { - static sg_shader_desc desc; - static bool valid; - if (!valid) { - valid = true; - desc.vertex_func.source = (const char*)vs_source_wgsl; - desc.vertex_func.entry = "main"; - desc.fragment_func.source = (const char*)fs_source_wgsl; - desc.fragment_func.entry = "main"; - desc.attrs[0].base_type = SG_SHADERATTRBASETYPE_FLOAT; - desc.uniform_blocks[0].stage = SG_SHADERSTAGE_VERTEX; - desc.uniform_blocks[0].layout = SG_UNIFORMLAYOUT_STD140; - desc.uniform_blocks[0].size = 16; - desc.uniform_blocks[0].wgsl_group0_binding_n = 0; - desc.uniform_blocks[1].stage = SG_SHADERSTAGE_FRAGMENT; - desc.uniform_blocks[1].layout = SG_UNIFORMLAYOUT_STD140; - desc.uniform_blocks[1].size = 16; - desc.uniform_blocks[1].wgsl_group0_binding_n = 8; - desc.storage_buffers[0].stage = SG_SHADERSTAGE_VERTEX; - desc.storage_buffers[0].readonly = true; - desc.storage_buffers[0].wgsl_group1_binding_n = 32; - desc.label = "base_shader"; - } - return &desc; - } - #endif /* SOKOL_WGPU */ - return 0; -} diff --git a/src/generated/sprite.h b/src/generated/sprite.h index 2008f98..fa48e93 100644 --- a/src/generated/sprite.h +++ b/src/generated/sprite.h @@ -1,102 +1,144 @@ unsigned char src_shaders_sprite_wgsl[] = { - 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x43, 0x65, 0x6c, 0x6c, 0x20, - 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, - 0x0a, 0x7d, 0x3b, 0x0d, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, - 0x56, 0x73, 0x49, 0x20, 0x7b, 0x20, 0x2f, 0x2f, 0x56, 0x65, 0x72, 0x74, - 0x65, 0x78, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, - 0x70, 0x75, 0x74, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x40, 0x62, 0x75, - 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x28, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, - 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x29, 0x20, 0x69, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, - 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x28, 0x30, 0x29, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, - 0x0a, 0x7d, 0x3b, 0x0d, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, - 0x56, 0x73, 0x32, 0x46, 0x73, 0x20, 0x7b, 0x20, 0x2f, 0x2f, 0x56, 0x65, - 0x72, 0x74, 0x65, 0x78, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, - 0x74, 0x6f, 0x20, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x20, - 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x40, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x28, 0x70, 0x6f, 0x73, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x29, 0x20, 0x70, 0x6f, 0x73, 0x3a, 0x20, - 0x76, 0x65, 0x63, 0x34, 0x66, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x30, 0x29, - 0x20, 0x40, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x6f, 0x6c, 0x61, 0x74, - 0x65, 0x28, 0x66, 0x6c, 0x61, 0x74, 0x29, 0x20, 0x69, 0x6e, 0x73, 0x74, - 0x61, 0x6e, 0x63, 0x65, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, 0x0d, 0x0a, + 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x53, 0x70, 0x72, 0x69, 0x74, + 0x65, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x74, + 0x72, 0x69, 0x78, 0x3a, 0x20, 0x6d, 0x61, 0x74, 0x34, 0x78, 0x34, 0x66, + 0x2c, 0x0d, 0x0a, 0x7d, 0x3b, 0x0d, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, + 0x74, 0x20, 0x56, 0x73, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, + 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x76, 0x70, 0x3a, 0x20, + 0x6d, 0x61, 0x74, 0x34, 0x78, 0x34, 0x66, 0x2c, 0x0d, 0x0a, 0x7d, 0x3b, + 0x0d, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x56, 0x73, 0x49, + 0x20, 0x7b, 0x20, 0x2f, 0x2f, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x20, + 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, + 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x40, 0x62, 0x75, 0x69, 0x6c, 0x74, + 0x69, 0x6e, 0x28, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x29, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, 0x0d, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x30, 0x29, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x31, 0x29, 0x20, 0x75, 0x76, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, + 0x2c, 0x0d, 0x0a, 0x7d, 0x3b, 0x0d, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, + 0x74, 0x20, 0x56, 0x73, 0x32, 0x46, 0x73, 0x20, 0x7b, 0x20, 0x2f, 0x2f, + 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, + 0x72, 0x20, 0x74, 0x6f, 0x20, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, + 0x74, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x0d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x40, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x28, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x29, 0x20, 0x70, 0x6f, 0x73, + 0x3a, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x2c, 0x0d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x30, 0x29, 0x20, 0x40, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x6f, 0x6c, + 0x61, 0x74, 0x65, 0x28, 0x6c, 0x69, 0x6e, 0x65, 0x61, 0x72, 0x29, 0x20, + 0x75, 0x76, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x0d, 0x0a, 0x7d, 0x3b, 0x0d, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x46, 0x73, 0x4f, 0x20, 0x7b, 0x20, 0x2f, 0x2f, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x40, - 0x62, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x28, 0x66, 0x72, 0x61, 0x67, - 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x29, 0x20, 0x64, 0x65, 0x70, 0x74, - 0x68, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x30, - 0x29, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x76, 0x65, 0x63, - 0x34, 0x66, 0x2c, 0x0d, 0x0a, 0x7d, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x66, - 0x6e, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x69, 0x3a, 0x20, 0x75, - 0x33, 0x32, 0x29, 0x20, 0x2d, 0x3e, 0x20, 0x76, 0x65, 0x63, 0x33, 0x66, - 0x0d, 0x0a, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, - 0x20, 0x72, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x20, 0x3d, 0x20, 0x66, 0x33, - 0x32, 0x28, 0x28, 0x28, 0x69, 0x20, 0x3e, 0x3e, 0x20, 0x20, 0x30, 0x29, - 0x20, 0x26, 0x20, 0x30, 0x78, 0x66, 0x66, 0x29, 0x29, 0x3b, 0x0d, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x67, 0x3a, 0x20, 0x66, - 0x33, 0x32, 0x20, 0x3d, 0x20, 0x66, 0x33, 0x32, 0x28, 0x28, 0x28, 0x69, + 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x30, 0x29, 0x20, + 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, + 0x2c, 0x0d, 0x0a, 0x7d, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x40, 0x62, 0x69, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x30, 0x29, 0x20, 0x40, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x28, 0x30, 0x29, 0x20, 0x76, 0x61, 0x72, 0x3c, 0x75, + 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x3e, 0x20, 0x76, 0x73, 0x5f, 0x75, + 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x3a, 0x20, 0x56, 0x73, 0x55, + 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x3b, 0x0d, 0x0a, 0x40, 0x62, 0x69, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x30, 0x29, 0x20, 0x40, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x28, 0x31, 0x29, 0x20, 0x76, 0x61, 0x72, 0x20, 0x74, + 0x65, 0x78, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5f, + 0x32, 0x64, 0x3c, 0x66, 0x33, 0x32, 0x3e, 0x3b, 0x0d, 0x0a, 0x40, 0x62, + 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x31, 0x29, 0x20, 0x40, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x28, 0x31, 0x29, 0x20, 0x76, 0x61, 0x72, 0x20, + 0x73, 0x61, 0x6d, 0x70, 0x3a, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x72, 0x3b, 0x0d, 0x0a, 0x40, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x28, 0x32, 0x29, 0x20, 0x40, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x28, 0x31, + 0x29, 0x20, 0x76, 0x61, 0x72, 0x3c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x3e, 0x20, 0x73, 0x70, 0x72, 0x69, 0x74, 0x65, 0x73, 0x3a, 0x20, + 0x61, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x53, 0x70, 0x72, 0x69, 0x74, 0x65, + 0x3e, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x40, 0x76, 0x65, 0x72, 0x74, 0x65, + 0x78, 0x20, 0x66, 0x6e, 0x20, 0x76, 0x73, 0x5f, 0x6d, 0x61, 0x69, 0x6e, + 0x28, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x3a, 0x20, 0x56, 0x73, 0x49, 0x29, + 0x20, 0x2d, 0x3e, 0x20, 0x56, 0x73, 0x32, 0x46, 0x73, 0x20, 0x7b, 0x0d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x3a, 0x20, 0x56, 0x73, 0x32, 0x46, 0x73, 0x3b, 0x0d, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, 0x70, 0x6f, 0x73, 0x20, 0x3d, 0x20, + 0x76, 0x65, 0x63, 0x34, 0x66, 0x28, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x2e, + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x78, 0x2c, 0x20, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x2e, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x79, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x30, 0x29, 0x20, + 0x2a, 0x20, 0x73, 0x70, 0x72, 0x69, 0x74, 0x65, 0x73, 0x5b, 0x69, 0x6e, + 0x70, 0x75, 0x74, 0x2e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x5d, 0x2e, 0x6d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x20, 0x2a, 0x20, 0x76, + 0x73, 0x5f, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x2e, 0x6d, + 0x76, 0x70, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x2e, 0x75, 0x76, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x70, + 0x75, 0x74, 0x2e, 0x75, 0x76, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x3b, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x2f, + 0x2f, 0x20, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x20, 0x61, 0x20, + 0x33, 0x32, 0x62, 0x69, 0x74, 0x20, 0x75, 0x69, 0x6e, 0x74, 0x20, 0x63, + 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x28, 0x68, 0x65, 0x78, 0x20, 0x72, 0x65, + 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x29, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x6e, 0x6f, 0x72, + 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x76, 0x65, 0x63, 0x34, + 0x66, 0x0d, 0x0a, 0x2f, 0x2a, 0x66, 0x6e, 0x20, 0x63, 0x6f, 0x6e, 0x76, + 0x65, 0x72, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x69, 0x6e, 0x70, + 0x75, 0x74, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x29, 0x20, 0x2d, 0x3e, 0x20, + 0x76, 0x65, 0x63, 0x34, 0x66, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x6c, 0x65, 0x74, 0x20, 0x72, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x20, + 0x3d, 0x20, 0x66, 0x33, 0x32, 0x28, 0x28, 0x28, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x20, 0x3e, 0x3e, 0x20, 0x20, 0x30, 0x29, 0x20, 0x26, 0x20, 0x30, + 0x78, 0x66, 0x66, 0x29, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x6c, 0x65, 0x74, 0x20, 0x67, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x20, 0x3d, + 0x20, 0x66, 0x33, 0x32, 0x28, 0x28, 0x28, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x3e, 0x3e, 0x20, 0x20, 0x38, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x66, 0x66, 0x29, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, 0x20, 0x62, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x20, 0x3d, 0x20, - 0x66, 0x33, 0x32, 0x28, 0x28, 0x28, 0x69, 0x20, 0x3e, 0x3e, 0x20, 0x31, - 0x36, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x66, 0x66, 0x29, 0x29, 0x3b, - 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, - 0x20, 0x76, 0x65, 0x63, 0x33, 0x66, 0x28, 0x72, 0x20, 0x2f, 0x20, 0x32, - 0x35, 0x35, 0x2c, 0x20, 0x67, 0x20, 0x2f, 0x20, 0x32, 0x35, 0x35, 0x2c, - 0x20, 0x62, 0x20, 0x2f, 0x20, 0x32, 0x35, 0x35, 0x29, 0x3b, 0x0d, 0x0a, - 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x2f, 0x2f, 0x40, 0x62, 0x69, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x28, 0x30, 0x29, 0x20, 0x40, 0x67, 0x72, 0x6f, 0x75, - 0x70, 0x28, 0x30, 0x29, 0x20, 0x76, 0x61, 0x72, 0x3c, 0x75, 0x6e, 0x69, - 0x66, 0x6f, 0x72, 0x6d, 0x3e, 0x20, 0x6d, 0x76, 0x70, 0x3a, 0x20, 0x6d, - 0x61, 0x74, 0x34, 0x78, 0x34, 0x66, 0x3b, 0x0d, 0x0a, 0x40, 0x62, 0x69, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x28, 0x30, 0x29, 0x20, 0x40, 0x67, 0x72, - 0x6f, 0x75, 0x70, 0x28, 0x31, 0x29, 0x20, 0x76, 0x61, 0x72, 0x3c, 0x73, - 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x3e, 0x20, 0x63, 0x65, 0x6c, 0x6c, - 0x73, 0x3a, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x3c, 0x43, 0x65, 0x6c, - 0x6c, 0x3e, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x40, 0x76, 0x65, 0x72, 0x74, - 0x65, 0x78, 0x0d, 0x0a, 0x66, 0x6e, 0x20, 0x76, 0x73, 0x5f, 0x6d, 0x61, - 0x69, 0x6e, 0x28, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x3a, 0x20, 0x56, 0x73, - 0x49, 0x29, 0x20, 0x2d, 0x3e, 0x20, 0x56, 0x73, 0x32, 0x46, 0x73, 0x20, - 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6f, - 0x75, 0x74, 0x70, 0x75, 0x74, 0x3a, 0x20, 0x56, 0x73, 0x32, 0x46, 0x73, - 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x2e, 0x70, 0x6f, 0x73, 0x20, 0x3d, 0x20, 0x76, 0x65, - 0x63, 0x34, 0x66, 0x28, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x5b, 0x69, 0x6e, - 0x70, 0x75, 0x74, 0x2e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x5d, 0x2e, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x78, - 0x79, 0x2c, 0x20, 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x30, 0x2e, 0x30, 0x29, - 0x2f, 0x2a, 0x20, 0x2a, 0x20, 0x6d, 0x76, 0x70, 0x2a, 0x2f, 0x3b, 0x0d, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, - 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x69, - 0x6e, 0x70, 0x75, 0x74, 0x2e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, - 0x65, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, - 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x3b, - 0x0d, 0x0a, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x40, 0x66, 0x72, 0x61, 0x67, - 0x6d, 0x65, 0x6e, 0x74, 0x0d, 0x0a, 0x66, 0x6e, 0x20, 0x66, 0x73, 0x5f, - 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x3a, 0x20, - 0x56, 0x73, 0x32, 0x46, 0x73, 0x29, 0x20, 0x2d, 0x3e, 0x20, 0x46, 0x73, - 0x4f, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, - 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x3a, 0x20, 0x46, 0x73, 0x4f, - 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x2e, 0x64, 0x65, 0x70, 0x74, 0x68, 0x20, 0x3d, 0x20, - 0x31, 0x2e, 0x30, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, - 0x74, 0x70, 0x75, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, - 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x28, 0x31, 0x2e, 0x30, 0x2c, 0x20, - 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x2c, 0x20, 0x31, 0x2e, - 0x30, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x6f, - 0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, - 0x3d, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x28, 0x63, 0x6f, 0x6c, 0x6f, - 0x72, 0x28, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x2e, 0x69, 0x6e, 0x73, 0x74, - 0x61, 0x6e, 0x63, 0x65, 0x29, 0x2c, 0x20, 0x31, 0x2e, 0x30, 0x29, 0x3b, - 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, - 0x72, 0x6e, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x3b, 0x0d, 0x0a, - 0x7d, 0x0d, 0x0a + 0x66, 0x33, 0x32, 0x28, 0x28, 0x28, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, + 0x3e, 0x3e, 0x20, 0x31, 0x36, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x66, + 0x66, 0x29, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, + 0x74, 0x20, 0x61, 0x3a, 0x20, 0x66, 0x33, 0x32, 0x20, 0x3d, 0x20, 0x66, + 0x33, 0x32, 0x28, 0x28, 0x28, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x3e, + 0x3e, 0x20, 0x32, 0x34, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x66, 0x66, + 0x29, 0x29, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x76, 0x65, 0x63, 0x34, 0x66, 0x28, + 0x72, 0x20, 0x2f, 0x20, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x67, 0x20, 0x2f, + 0x20, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x62, 0x20, 0x2f, 0x20, 0x32, 0x35, + 0x35, 0x2c, 0x20, 0x61, 0x20, 0x2f, 0x20, 0x32, 0x35, 0x35, 0x29, 0x3b, + 0x0d, 0x0a, 0x7d, 0x2a, 0x2f, 0x0d, 0x0a, 0x2f, 0x2f, 0x20, 0x47, 0x65, + 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, + 0x65, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x55, + 0x56, 0x0d, 0x0a, 0x2f, 0x2a, 0x66, 0x6e, 0x20, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x46, 0x72, 0x6f, 0x6d, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x28, 0x75, + 0x76, 0x3a, 0x20, 0x76, 0x65, 0x63, 0x32, 0x66, 0x2c, 0x20, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x2c, 0x20, 0x68, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x29, 0x20, 0x2d, + 0x3e, 0x20, 0x75, 0x33, 0x32, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x6c, 0x65, 0x74, 0x20, 0x78, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x20, + 0x3d, 0x20, 0x63, 0x6c, 0x61, 0x6d, 0x70, 0x28, 0x66, 0x6c, 0x6f, 0x6f, + 0x72, 0x28, 0x75, 0x76, 0x2e, 0x78, 0x20, 0x2a, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x29, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x74, + 0x20, 0x79, 0x3a, 0x20, 0x75, 0x33, 0x32, 0x20, 0x3d, 0x20, 0x63, 0x6c, + 0x61, 0x6d, 0x70, 0x28, 0x66, 0x6c, 0x6f, 0x6f, 0x72, 0x28, 0x75, 0x76, + 0x2e, 0x79, 0x20, 0x2a, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x29, + 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x29, + 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x79, 0x20, 0x2a, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, + 0x2b, 0x20, 0x78, 0x3b, 0x0d, 0x0a, 0x7d, 0x2a, 0x2f, 0x0d, 0x0a, 0x0d, + 0x0a, 0x40, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x66, + 0x6e, 0x20, 0x66, 0x73, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x69, 0x6e, + 0x70, 0x75, 0x74, 0x3a, 0x20, 0x56, 0x73, 0x32, 0x46, 0x73, 0x29, 0x20, + 0x2d, 0x3e, 0x20, 0x46, 0x73, 0x4f, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x3a, 0x20, 0x46, 0x73, 0x4f, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, 0x63, 0x6f, 0x6c, + 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, + 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x28, 0x74, 0x65, 0x78, 0x2c, 0x20, + 0x73, 0x61, 0x6d, 0x70, 0x2c, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x2e, + 0x75, 0x76, 0x29, 0x3b, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, + 0x74, 0x3b, 0x0d, 0x0a, 0x7d, 0x0d, 0x0a }; -unsigned int src_shaders_sprite_wgsl_len = 1179; +unsigned int src_shaders_sprite_wgsl_len = 1687; diff --git a/src/main.c b/src/main.c index 5b927a4..f2e5c60 100644 --- a/src/main.c +++ b/src/main.c @@ -1,29 +1,38 @@ -// This is an example on how to set up and use Sokol GP to draw a filled rectangle. - -// Includes Sokol GFX, Sokol GP and Sokol APP, doing all implementations. -#define SOKOL_IMPL -#define SOKOL_WGPU - -#include "sokol_gfx.h" -#include "sokol_gp.h" -#include "sokol_app.h" -#include "sokol_glue.h" -#include "sokol_log.h" -#include "util/sokol_memtrack.h" -#include "math.h" -#include "rand.h" - -#include "generated/sprite.h" - -#include -#include -#include -#include +#include "api.h" #define ALLOC(arg) smemtrack_alloc(arg, NULL) #define FREE(arg) smemtrack_free(arg, NULL) -#define SAMPLE_COUNT 100000 +#define GRID_X 1000 +#define GRID_Y 1000 + +typedef struct vs_uniform_t { + mat4x4f mvp; +} uniform_t; + +typedef struct renderer_t { + sg_pipeline pipeline; //Configured sprite pipeline + sg_pass_action clear_pass; //Render pass - Clear screen + uniform_t uniform; //Uniform data +} renderer_t; + +typedef struct manager_t { + vector_t textures; +} manager_t; + +typedef struct dragger_t { + bool dragging; + float origin_x, origin_y; +} dragger_t; + +typedef struct userdata_t { + int width, height; + vec2f pan; + float zoom; + dragger_t dragger; + renderer_t renderer; + manager_t manager; +} userdata_t; void js_log(int severity, const char* format, ...) { @@ -37,72 +46,74 @@ void js_log(int severity, const char* format, ...) va_end(va); slog_js_log(severity, buffer); } -void compute_mvp(Mat4 *ptr, Vec2 pan, float zoom) +void compute_mvp(userdata_t *userdata) { - const int width = sapp_width(), height = sapp_height(); - - ptr->Elements[0][0] = (2.0f * zoom)/width; - ptr->Elements[0][1] = 0.0f; - ptr->Elements[0][2] = 0.0f; - ptr->Elements[0][3] = 0.0f; - ptr->Elements[1][0] = 0.0f; - ptr->Elements[1][1] = (2.0f * zoom)/height; - ptr->Elements[1][2] = 0.0f; - ptr->Elements[1][3] = 0.0f; - ptr->Elements[2][0] = 0.0f; - ptr->Elements[2][1] = 0.0f; - ptr->Elements[2][2] = 1.0f; - ptr->Elements[2][3] = 0.0f; - ptr->Elements[3][0] = (-2.0f * pan.X * zoom)/width - 1.0f; - ptr->Elements[3][1] = (-2.0f * pan.Y * zoom)/height - 1.0f; - ptr->Elements[3][2] = 0.0f; - ptr->Elements[3][3] = 0.0f; + userdata->renderer.uniform.mvp.e[0][0] = (2.0f / userdata->width) * userdata->zoom; + userdata->renderer.uniform.mvp.e[1][1] = (2.0f / userdata->height) * userdata->zoom; + userdata->renderer.uniform.mvp.e[0][3] = (2.0f / userdata->width) * userdata->pan.x; + userdata->renderer.uniform.mvp.e[1][3] = (2.0f / userdata->height) * userdata->pan.y; } -typedef struct renderer_t { - sg_pipeline pipeline; - sg_pipeline compute; - sg_bindings binding; - sg_range uniform; - sg_pass_action pass; - sg_shader sprite_shader; -} renderer_t; - -typedef struct userdata_t { - Vec2 pan; - float zoom; - renderer_t renderer; - Mat4 *mvp; -} userdata_t; - -// Called on every frame of the application. static void frame(void* _userdata) { userdata_t* userdata = (userdata_t*) _userdata; + + simgui_new_frame(&(simgui_frame_desc_t){ + .width = userdata->width, + .height = userdata->height, + .delta_time = sapp_frame_duration(), + .dpi_scale = 1.0f, + }); + + igSetNextWindowPos((ImVec2){20,20}, ImGuiCond_Once); + igSetNextWindowSize((ImVec2){600,200}, ImGuiCond_Once); + if (igBegin("Menu", 0, ImGuiWindowFlags_NoResize)) { + igText("Frame duration: %.4fms", sapp_frame_duration() * 1000.0); + igText("Zoom: %.3f", userdata->zoom); + igText("Pan: %.3f/%.3f", userdata->pan.x, userdata->pan.y); + } + igEnd(); sg_begin_pass(&(sg_pass){ - .action = userdata->renderer.pass, + .action = userdata->renderer.clear_pass, .swapchain = sglue_swapchain(), }); - sg_apply_pipeline(userdata->renderer.pipeline); - sg_apply_bindings(&userdata->renderer.binding); - //sg_apply_uniforms(0, &userdata->renderer.uniform); + const uint32_t length = vector_length(&userdata->manager.textures); + if(length > 0) + { + sg_apply_pipeline(userdata->renderer.pipeline); - sg_draw(0, 4, SAMPLE_COUNT); + for(uint32_t i = 0; i < length; i++) + { + texture_t* texture = (texture_t*) vector_get(&userdata->manager.textures, i); + + if(texture->dirty) + { + const sg_range range = vector_range(&texture->sprites); + sg_update_buffer(texture->binding.storage_buffers[0], &range); + texture->dirty = false; + } + + sg_apply_bindings(&texture->binding); + sg_apply_uniforms(0, &SG_RANGE(userdata->renderer.uniform)); + + sg_draw(0, 6, vector_length(&texture->sprites)); + } + } + + simgui_render(); sg_end_pass(); sg_commit(); } -// Called when the application is initializing. static void init(void* _userdata) { rand_seed(1); userdata_t* userdata = (userdata_t*) _userdata; - // Initialize Sokol GFX. sg_desc sgdesc = { .environment = sglue_environment(), .logger.func = slog_func, @@ -113,46 +124,81 @@ static void init(void* _userdata) exit(-1); } - const Vec2 quad[4] = { - {0.0f, 1.0f}, // bottom left - {1.0f, 1.0f}, // bottom right - {1.0f, 0.0f}, // top right - {0.0f, 0.0f}, // top left + const vec2f quad[4] = { + {-2.0f, 2.0f}, // bottom left + {2.0f, 2.0f}, // bottom right + {2.0f, -2.0f}, // top right + {-2.0f, -2.0f}, // top left }; const uint16_t indices[] = { 0, 1, 2, 0, 2, 3, }; + + userdata->width = sapp_width(); + userdata->height = sapp_height(); + userdata->pan = (vec2f) { 0.0f, 0.0f }; + userdata->zoom = 2; - Mat4 mvp = M4(); - compute_mvp(&mvp, V2(0, 0), 1); + vec2f* tmp_buffer = malloc(sizeof(vec2f) * GRID_X * GRID_Y); - Vec2* tmp_buffer = malloc(sizeof(Vec2) * SAMPLE_COUNT); - - for(uint32_t i = 0; i < SAMPLE_COUNT; i++) + uint32_t i = 0; + for(uint32_t x = 0; x < GRID_X; x++) { - tmp_buffer[i].X = next_float(); - tmp_buffer[i].Y = next_float(); + for(uint32_t y = 0; y < GRID_Y; y++) + { + const float angle = next_float_max(PI), radius = next_float_max(0.5f); + tmp_buffer[i].x = x + sin(angle) * radius - GRID_X / 2.0f; + tmp_buffer[i].y = y + cos(angle) * radius - GRID_Y / 2.0f; + + i++; + } } sg_shader sprite_shader = sg_make_shader(&(sg_shader_desc) { .vertex_func = { - .source = src_shaders_sprite_wgsl, + .source = (const char*) src_shaders_sprite_wgsl, .entry = "vs_main", }, .fragment_func = { - .source = src_shaders_sprite_wgsl, + .source = (const char*) src_shaders_sprite_wgsl, .entry = "fs_main", }, - .storage_buffers[0] = { - .wgsl_group1_binding_n = 0, - .stage = SG_SHADERSTAGE_VERTEX, - .readonly = true, + .images = { + [0] = { + .stage = SG_SHADERSTAGE_FRAGMENT, + .image_type = SG_IMAGETYPE_2D, + .wgsl_group1_binding_n = 0, + .sample_type = SG_IMAGESAMPLETYPE_FLOAT, + }, + }, + .samplers = { + [0] = { + .stage = SG_SHADERSTAGE_FRAGMENT, + .sampler_type = SG_SAMPLERTYPE_FILTERING, + .wgsl_group1_binding_n = 1, + } + }, + .image_sampler_pairs = { + [0] = { + .stage = SG_SHADERSTAGE_FRAGMENT, + .image_slot = 0, + .sampler_slot = 0, + } + }, + .storage_buffers = { + [0] = { + .wgsl_group1_binding_n = 2, + .stage = SG_SHADERSTAGE_VERTEX, + .readonly = true, + }, + }, + .uniform_blocks = { + [0] = { + .size = sizeof(uniform_t), + .stage = SG_SHADERSTAGE_VERTEX, + .wgsl_group0_binding_n = 0, + }, }, - /*.uniform_blocks[0] = { - .size = sizeof(float) * 16, //mat4x4f - .stage = SG_SHADERSTAGE_VERTEX, - .wgsl_group0_binding_n = 0, - },*/ .attrs[0] = { .base_type = SG_SHADERATTRBASETYPE_FLOAT, }, @@ -160,97 +206,103 @@ static void init(void* _userdata) }); userdata->renderer = (renderer_t) { - .pass = (sg_pass_action) { - .colors[0] = { .clear_value = { 0.0f, 0.0f, 0.0f, 1.0f }, .load_action = SG_LOADACTION_CLEAR } + .clear_pass = (sg_pass_action) { + .colors[0] = { .clear_value = { 1.0f, 1.0f, 1.0f, 1.0f }, .load_action = SG_LOADACTION_CLEAR } }, .pipeline = sg_make_pipeline(&(sg_pipeline_desc) { .shader = sprite_shader, - .depth.write_enabled = true, .index_type = SG_INDEXTYPE_UINT16, .layout.attrs = { [0].format = SG_VERTEXFORMAT_FLOAT2, }, .label = "Sprite pipeline", }), - /*.compute = sg_make_pipeline(&(sg_pipeline_desc) { - .compute = true, - .shader = sg_make_shader(compute_shader_desc(sg_query_backend())), - }),*/ - .binding = (sg_bindings) { - .vertex_buffers = { - [0] = sg_make_buffer(&(sg_buffer_desc) { - .type = SG_BUFFERTYPE_VERTEXBUFFER, - .data = SG_RANGE(quad), - .label = "Vertices" - }), + .uniform = (uniform_t) { + .mvp = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f }, - .index_buffer = sg_make_buffer(&(sg_buffer_desc) { - .type = SG_BUFFERTYPE_INDEXBUFFER, - .data = SG_RANGE(indices), - .label = "Indices" - }), - .storage_buffers = { - [0] = sg_make_buffer(&(sg_buffer_desc) { - .type = SG_BUFFERTYPE_STORAGEBUFFER, - .data = { - .ptr = tmp_buffer, - .size = sizeof(Vec2) * SAMPLE_COUNT, - }, - .label = "SSBO" - }), - }, - }, - .uniform = SG_RANGE(mvp), + } }; - - userdata->pan = (Vec2) { .X = 0, .Y = 0 }; - userdata->zoom = 1; - userdata->mvp = &mvp; + + userdata->manager = (manager_t) { + .textures = vector_create(sizeof(texture_t)), + }; + + compute_mvp(userdata); FREE(tmp_buffer); + + simgui_setup(&(simgui_desc_t) { + .logger.func = slog_func, + .allocator = { + .alloc_fn = smemtrack_alloc, + .free_fn = smemtrack_free, + }, + }); } -// Called when the application is shutting down. static void cleanup(void* _userdata) { userdata_t* userdata = (userdata_t*) _userdata; + vector_free(&userdata->manager.textures); + FREE(userdata); - smemtrack_info_t info = smemtrack_info(); - js_log(3, "Leaks: %d. Amount: %db", info.num_allocs, info.num_bytes); - + simgui_shutdown(); sg_shutdown(); } static void event(const sapp_event* event, void* _userdata) { userdata_t* userdata = (userdata_t*) _userdata; + + if(simgui_handle_event(event)) + return; + switch(event->type) { + case SAPP_EVENTTYPE_RESIZED: + userdata->width = sapp_width(); + userdata->height = sapp_height(); + + compute_mvp(userdata); + + break; case SAPP_EVENTTYPE_MOUSE_DOWN: + if(event->modifiers & SAPP_MODIFIER_RMB) + { + userdata->dragger.dragging = true; + userdata->dragger.origin_x = event->mouse_x; + userdata->dragger.origin_y = event->mouse_y; + } break; case SAPP_EVENTTYPE_MOUSE_UP: + userdata->dragger.dragging = false; break; case SAPP_EVENTTYPE_MOUSE_MOVE: + if(userdata->dragger.dragging) + { + userdata->pan.x += event->mouse_dx; + userdata->pan.y -= event->mouse_dy; + + compute_mvp(userdata); + } break; case SAPP_EVENTTYPE_MOUSE_SCROLL: - if((userdata->zoom >= 3.0f && event->scroll_y > 0.0f) || (userdata->zoom <= 0.1f && event->scroll_y < 0.0f)) + if((userdata->zoom >= 6.0f && event->scroll_y > 0.0f) || (userdata->zoom <= 0.1f && event->scroll_y < 0.0f)) return; const float diff = expf(event->scroll_y * 0.01f); - const float width = sapp_widthf(), height = sapp_heightf(); + userdata->zoom = _sg_clamp(userdata->zoom * diff, 0.1f, 6.0f); - userdata->pan.X = userdata->pan.X - (event->mouse_x / (diff * userdata->zoom) - event->mouse_x / userdata->zoom); - userdata->pan.Y = userdata->pan.Y - (event->mouse_y / (diff * userdata->zoom) - event->mouse_y / userdata->zoom); - userdata->zoom = _sg_clamp(userdata->zoom * diff, 0.1f, 3.0f); - - compute_mvp(userdata->mvp, userdata->pan, userdata->zoom); - - js_log(3, "Zoom: %f. Pan: %f/%f", userdata->zoom, userdata->pan.X, userdata->pan.Y); + compute_mvp(userdata); break; default: @@ -258,7 +310,6 @@ static void event(const sapp_event* event, void* _userdata) } } -// Implement application main through Sokol APP. sapp_desc sokol_main(int argc, char* argv[]) { userdata_t* userdata = (userdata_t*) ALLOC(sizeof(userdata_t)); diff --git a/src/math.h b/src/math.h index a1ee542..d3a03d5 100644 --- a/src/math.h +++ b/src/math.h @@ -1,3939 +1,49 @@ -/* - HandmadeMath.h v2.0.0 +#ifndef MATH_IMPL_H +#define MATH_IMPL_H - This is a single header file with a bunch of useful types and functions for - games and graphics. Consider it a lightweight alternative to GLM that works - both C and C++. - - ============================================================================= - CONFIG - ============================================================================= - - By default, all angles in Handmade Math are specified in radians. However, it - can be configured to use degrees or turns instead. Use one of the following - defines to specify the default unit for angles: - - #define HANDMADE_MATH_USE_RADIANS - #define HANDMADE_MATH_USE_DEGREES - #define HANDMADE_MATH_USE_TURNS - - Regardless of the default angle, you can use the following functions to - specify an angle in a particular unit: - - AngleRad(radians) - AngleDeg(degrees) - AngleTurn(turns) - - The definitions of these functions change depending on the default unit. - - ----------------------------------------------------------------------------- - - Handmade Math ships with SSE (SIMD) implementations of several common - operations. To disable the use of SSE intrinsics, you must define - HANDMADE_MATH_NO_SSE before including this file: - - #define HANDMADE_MATH_NO_SSE - #include "HandmadeMath.h" - - ----------------------------------------------------------------------------- - - To use Handmade Math without the C runtime library, you must provide your own - implementations of basic math functions. Otherwise, HandmadeMath.h will use - the runtime library implementation of these functions. - - Define HANDMADE_MATH_PROVIDE_MATH_FUNCTIONS and provide your own - implementations of SINF, COSF, TANF, ACOSF, and SQRTF - before including HandmadeMath.h, like so: - - #define HANDMADE_MATH_PROVIDE_MATH_FUNCTIONS - #define SINF MySinF - #define COSF MyCosF - #define TANF MyTanF - #define ACOSF MyACosF - #define SQRTF MySqrtF - #include "HandmadeMath.h" - - By default, it is assumed that your math functions take radians. To use - different units, you must define ANGLE_USER_TO_INTERNAL and - ANGLE_INTERNAL_TO_USER. For example, if you want to use degrees in your - code but your math functions use turns: - - #define ANGLE_USER_TO_INTERNAL(a) ((a)*DegToTurn) - #define ANGLE_INTERNAL_TO_USER(a) ((a)*TurnToDeg) - - ============================================================================= - - LICENSE - - This software is in the public domain. Where that dedication is not - recognized, you are granted a perpetual, irrevocable license to copy, - distribute, and modify this file as you see fit. - - ============================================================================= - - CREDITS - - Originally written by Zakary Strange. - - Functionality: - Zakary Strange (strangezak@protonmail.com && @strangezak) - Matt Mascarenhas (@miblo_) - Aleph - FieryDrake (@fierydrake) - Gingerbill (@TheGingerBill) - Ben Visness (@bvisness) - Trinton Bullard (@Peliex_Dev) - @AntonDan - Logan Forman (@dev_dwarf) - - Fixes: - Jeroen van Rijn (@J_vanRijn) - Kiljacken (@Kiljacken) - Insofaras (@insofaras) - Daniel Gibson (@DanielGibson) -*/ - -#ifndef HANDMADE_MATH_H -#define HANDMADE_MATH_H - -// Dummy macros for when test framework is not present. -#ifndef COVERAGE -# define COVERAGE(a, b) -#endif - -#ifndef ASSERT_COVERED -# define ASSERT_COVERED(a) -#endif - -#ifdef HANDMADE_MATH_NO_SSE -# warning "HANDMADE_MATH_NO_SSE is deprecated, use HANDMADE_MATH_NO_SIMD instead" -# define HANDMADE_MATH_NO_SIMD -#endif - -/* let's figure out if SSE is really available (unless disabled anyway) - (it isn't on non-x86/x86_64 platforms or even x86 without explicit SSE support) - => only use "#ifdef HANDMADE_MATH__USE_SSE" to check for SSE support below this block! */ -#ifndef HANDMADE_MATH_NO_SIMD -# ifdef _MSC_VER /* MSVC supports SSE in amd64 mode or _M_IX86_FP >= 1 (2 means SSE2) */ -# if defined(_M_AMD64) || ( defined(_M_IX86_FP) && _M_IX86_FP >= 1 ) -# define HANDMADE_MATH__USE_SSE 1 -# endif -# else /* not MSVC, probably GCC, clang, icc or something that doesn't support SSE anyway */ -# ifdef __SSE__ /* they #define __SSE__ if it's supported */ -# define HANDMADE_MATH__USE_SSE 1 -# endif /* __SSE__ */ -# endif /* not _MSC_VER */ -# ifdef __ARM_NEON -# define HANDMADE_MATH__USE_NEON 1 -# endif /* NEON Supported */ -#endif /* #ifndef HANDMADE_MATH_NO_SIMD */ - -#if (!defined(__cplusplus) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) -# define HANDMADE_MATH__USE_C11_GENERICS 1 -#endif - -#ifdef HANDMADE_MATH__USE_SSE -# include -#endif - -#ifdef HANDMADE_MATH__USE_NEON -# include -#endif - -#ifdef _MSC_VER -#pragma warning(disable:4201) -#endif - -#if defined(__GNUC__) || defined(__clang__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wfloat-equal" -# pragma GCC diagnostic ignored "-Wmissing-braces" -# ifdef __clang__ -# pragma GCC diagnostic ignored "-Wgnu-anonymous-struct" -# pragma GCC diagnostic ignored "-Wmissing-field-initializers" -# endif -#endif - -#if defined(__GNUC__) || defined(__clang__) -# define DEPRECATED(msg) __attribute__((deprecated(msg))) -#elif defined(_MSC_VER) -# define DEPRECATED(msg) __declspec(deprecated(msg)) -#else -# define DEPRECATED(msg) -#endif - -#ifdef __cplusplus -extern "C" -{ -#endif - -#if !defined(HANDMADE_MATH_USE_DEGREES) \ - && !defined(HANDMADE_MATH_USE_TURNS) \ - && !defined(HANDMADE_MATH_USE_RADIANS) -# define HANDMADE_MATH_USE_RADIANS -#endif +#include "api.h" #define PI 3.14159265358979323846 #define PI32 3.14159265359f -#define DEG180 180.0 -#define DEG18032 180.0f -#define TURNHALF 0.5 -#define TURNHALF32 0.5f -#define RadToDeg ((float)(DEG180/PI)) -#define RadToTurn ((float)(TURNHALF/PI)) -#define DegToRad ((float)(PI/DEG180)) -#define DegToTurn ((float)(TURNHALF/DEG180)) -#define TurnToRad ((float)(PI/TURNHALF)) -#define TurnToDeg ((float)(DEG180/TURNHALF)) -#if defined(HANDMADE_MATH_USE_RADIANS) -# define AngleRad(a) (a) -# define AngleDeg(a) ((a)*DegToRad) -# define AngleTurn(a) ((a)*TurnToRad) -#elif defined(HANDMADE_MATH_USE_DEGREES) -# define AngleRad(a) ((a)*RadToDeg) -# define AngleDeg(a) (a) -# define AngleTurn(a) ((a)*TurnToDeg) -#elif defined(HANDMADE_MATH_USE_TURNS) -# define AngleRad(a) ((a)*RadToTurn) -# define AngleDeg(a) ((a)*DegToTurn) -# define AngleTurn(a) (a) -#endif - -#if !defined(HANDMADE_MATH_PROVIDE_MATH_FUNCTIONS) -# include -# define SINF sinf -# define COSF cosf -# define TANF tanf -# define SQRTF sqrtf -# define ACOSF acosf -#endif - -#if !defined(ANGLE_USER_TO_INTERNAL) -# define ANGLE_USER_TO_INTERNAL(a) (ToRad(a)) -#endif - -#if !defined(ANGLE_INTERNAL_TO_USER) -# if defined(HANDMADE_MATH_USE_RADIANS) -# define ANGLE_INTERNAL_TO_USER(a) (a) -# elif defined(HANDMADE_MATH_USE_DEGREES) -# define ANGLE_INTERNAL_TO_USER(a) ((a)*RadToDeg) -# elif defined(HANDMADE_MATH_USE_TURNS) -# define ANGLE_INTERNAL_TO_USER(a) ((a)*RadToTurn) -# endif -#endif - -#define MIN(a, b) ((a) > (b) ? (b) : (a)) -#define MAX(a, b) ((a) < (b) ? (b) : (a)) -#define ABS(a) ((a) > 0 ? (a) : -(a)) -#define MOD(a, m) (((a) % (m)) >= 0 ? ((a) % (m)) : (((a) % (m)) + (m))) -#define SQUARE(x) ((x) * (x)) - -typedef union Vec2 -{ - struct - { - float X, Y; - }; - - struct - { - float U, V; - }; - - struct - { - float Left, Right; - }; - - struct - { - float Width, Height; - }; - - float Elements[2]; - -#ifdef __cplusplus - inline float &operator[](int Index) { return Elements[Index]; } - inline const float& operator[](int Index) const { return Elements[Index]; } -#endif -} Vec2; - -typedef union Vec3 -{ - struct - { - float X, Y, Z; - }; - - struct - { - float U, V, W; - }; - - struct - { - float R, G, B; - }; - - struct - { - Vec2 XY; - float _Ignored0; - }; - - struct - { - float _Ignored1; - Vec2 YZ; - }; - - struct - { - Vec2 UV; - float _Ignored2; - }; - - struct - { - float _Ignored3; - Vec2 VW; - }; - - float Elements[3]; - -#ifdef __cplusplus - inline float &operator[](int Index) { return Elements[Index]; } - inline const float &operator[](int Index) const { return Elements[Index]; } -#endif -} Vec3; - -typedef union Vec4 -{ - struct - { - union - { - Vec3 XYZ; - struct - { - float X, Y, Z; - }; - }; - - float W; - }; - struct - { - union - { - Vec3 RGB; - struct - { - float R, G, B; - }; - }; - - float A; - }; - - struct - { - Vec2 XY; - float _Ignored0; - float _Ignored1; - }; - - struct - { - float _Ignored2; - Vec2 YZ; - float _Ignored3; - }; - - struct - { - float _Ignored4; - float _Ignored5; - Vec2 ZW; - }; - - float Elements[4]; - -#ifdef HANDMADE_MATH__USE_SSE - __m128 SSE; -#endif - -#ifdef HANDMADE_MATH__USE_NEON - float32x4_t NEON; -#endif - -#ifdef __cplusplus - inline float &operator[](int Index) { return Elements[Index]; } - inline const float &operator[](int Index) const { return Elements[Index]; } -#endif -} Vec4; - -typedef union Mat2 -{ - float Elements[2][2]; - Vec2 Columns[2]; - -#ifdef __cplusplus - inline Vec2 &operator[](int Index) { return Columns[Index]; } - inline const Vec2 &operator[](int Index) const { return Columns[Index]; } -#endif -} Mat2; - -typedef union Mat3 -{ - float Elements[3][3]; - Vec3 Columns[3]; - -#ifdef __cplusplus - inline Vec3 &operator[](int Index) { return Columns[Index]; } - inline const Vec3 &operator[](int Index) const { return Columns[Index]; } -#endif -} Mat3; - -typedef union Mat4 -{ - float Elements[4][4]; - Vec4 Columns[4]; - -#ifdef __cplusplus - inline Vec4 &operator[](int Index) { return Columns[Index]; } - inline const Vec4 &operator[](int Index) const { return Columns[Index]; } -#endif -} Mat4; - -typedef union Quat -{ - struct - { - union - { - Vec3 XYZ; - struct - { - float X, Y, Z; - }; - }; - - float W; - }; - - float Elements[4]; - -#ifdef HANDMADE_MATH__USE_SSE - __m128 SSE; -#endif -#ifdef HANDMADE_MATH__USE_NEON - float32x4_t NEON; -#endif -} Quat; - -typedef signed int Bool; - -/* - * Angle unit conversion functions - */ -static inline float ToRad(float Angle) -{ -#if defined(HANDMADE_MATH_USE_RADIANS) - float Result = Angle; -#elif defined(HANDMADE_MATH_USE_DEGREES) - float Result = Angle * DegToRad; -#elif defined(HANDMADE_MATH_USE_TURNS) - float Result = Angle * TurnToRad; -#endif - - return Result; -} - -static inline float ToDeg(float Angle) -{ -#if defined(HANDMADE_MATH_USE_RADIANS) - float Result = Angle * RadToDeg; -#elif defined(HANDMADE_MATH_USE_DEGREES) - float Result = Angle; -#elif defined(HANDMADE_MATH_USE_TURNS) - float Result = Angle * TurnToDeg; -#endif - - return Result; -} - -static inline float ToTurn(float Angle) -{ -#if defined(HANDMADE_MATH_USE_RADIANS) - float Result = Angle * RadToTurn; -#elif defined(HANDMADE_MATH_USE_DEGREES) - float Result = Angle * DegToTurn; -#elif defined(HANDMADE_MATH_USE_TURNS) - float Result = Angle; -#endif - - return Result; -} - -/* - * Floating-point math functions - */ - -COVERAGE(SinF, 1) -static inline float SinF(float Angle) -{ - ASSERT_COVERED(SinF); - return SINF(ANGLE_USER_TO_INTERNAL(Angle)); -} - -COVERAGE(CosF, 1) -static inline float CosF(float Angle) -{ - ASSERT_COVERED(CosF); - return COSF(ANGLE_USER_TO_INTERNAL(Angle)); -} - -COVERAGE(TanF, 1) -static inline float TanF(float Angle) -{ - ASSERT_COVERED(TanF); - return TANF(ANGLE_USER_TO_INTERNAL(Angle)); -} - -COVERAGE(ACosF, 1) -static inline float ACosF(float Arg) -{ - ASSERT_COVERED(ACosF); - return ANGLE_INTERNAL_TO_USER(ACOSF(Arg)); -} - -COVERAGE(SqrtF, 1) -static inline float SqrtF(float Float) -{ - ASSERT_COVERED(SqrtF); - - float Result; - -#ifdef HANDMADE_MATH__USE_SSE - __m128 In = _mm_set_ss(Float); - __m128 Out = _mm_sqrt_ss(In); - Result = _mm_cvtss_f32(Out); -#elif defined(HANDMADE_MATH__USE_NEON) - float32x4_t In = vdupq_n_f32(Float); - float32x4_t Out = vsqrtq_f32(In); - Result = vgetq_lane_f32(Out, 0); -#else - Result = SQRTF(Float); -#endif - - return Result; -} - -COVERAGE(InvSqrtF, 1) -static inline float InvSqrtF(float Float) -{ - ASSERT_COVERED(InvSqrtF); - - float Result; - - Result = 1.0f/SqrtF(Float); - - return Result; -} - - -/* - * Utility functions - */ - -COVERAGE(Lerp, 1) -static inline float Lerp(float A, float Time, float B) -{ - ASSERT_COVERED(Lerp); - return (1.0f - Time) * A + Time * B; -} - -COVERAGE(Clamp, 1) -static inline float Clamp(float Min, float Value, float Max) -{ - ASSERT_COVERED(Clamp); - - float Result = Value; - - if (Result < Min) - { - Result = Min; - } - - if (Result > Max) - { - Result = Max; - } - - return Result; -} - - -/* - * Vector initialization - */ - -COVERAGE(V2, 1) -static inline Vec2 V2(float X, float Y) -{ - ASSERT_COVERED(V2); - - Vec2 Result; - Result.X = X; - Result.Y = Y; - - return Result; -} - -COVERAGE(V3, 1) -static inline Vec3 V3(float X, float Y, float Z) -{ - ASSERT_COVERED(V3); - - Vec3 Result; - Result.X = X; - Result.Y = Y; - Result.Z = Z; - - return Result; -} - -COVERAGE(V4, 1) -static inline Vec4 V4(float X, float Y, float Z, float W) -{ - ASSERT_COVERED(V4); - - Vec4 Result; - -#ifdef HANDMADE_MATH__USE_SSE - Result.SSE = _mm_setr_ps(X, Y, Z, W); -#elif defined(HANDMADE_MATH__USE_NEON) - float32x4_t v = {X, Y, Z, W}; - Result.NEON = v; -#else - Result.X = X; - Result.Y = Y; - Result.Z = Z; - Result.W = W; -#endif - - return Result; -} - -COVERAGE(V4V, 1) -static inline Vec4 V4V(Vec3 Vector, float W) -{ - ASSERT_COVERED(V4V); - - Vec4 Result; - -#ifdef HANDMADE_MATH__USE_SSE - Result.SSE = _mm_setr_ps(Vector.X, Vector.Y, Vector.Z, W); -#elif defined(HANDMADE_MATH__USE_NEON) - float32x4_t v = {Vector.X, Vector.Y, Vector.Z, W}; - Result.NEON = v; -#else - Result.XYZ = Vector; - Result.W = W; -#endif - - return Result; -} - - -/* - * Binary vector operations - */ - -COVERAGE(AddV2, 1) -static inline Vec2 AddV2(Vec2 Left, Vec2 Right) -{ - ASSERT_COVERED(AddV2); - - Vec2 Result; - Result.X = Left.X + Right.X; - Result.Y = Left.Y + Right.Y; - - return Result; -} - -COVERAGE(AddV3, 1) -static inline Vec3 AddV3(Vec3 Left, Vec3 Right) -{ - ASSERT_COVERED(AddV3); - - Vec3 Result; - Result.X = Left.X + Right.X; - Result.Y = Left.Y + Right.Y; - Result.Z = Left.Z + Right.Z; - - return Result; -} - -COVERAGE(AddV4, 1) -static inline Vec4 AddV4(Vec4 Left, Vec4 Right) -{ - ASSERT_COVERED(AddV4); - - Vec4 Result; - -#ifdef HANDMADE_MATH__USE_SSE - Result.SSE = _mm_add_ps(Left.SSE, Right.SSE); -#elif defined(HANDMADE_MATH__USE_NEON) - Result.NEON = vaddq_f32(Left.NEON, Right.NEON); -#else - Result.X = Left.X + Right.X; - Result.Y = Left.Y + Right.Y; - Result.Z = Left.Z + Right.Z; - Result.W = Left.W + Right.W; -#endif - - return Result; -} - -COVERAGE(SubV2, 1) -static inline Vec2 SubV2(Vec2 Left, Vec2 Right) -{ - ASSERT_COVERED(SubV2); - - Vec2 Result; - Result.X = Left.X - Right.X; - Result.Y = Left.Y - Right.Y; - - return Result; -} - -COVERAGE(SubV3, 1) -static inline Vec3 SubV3(Vec3 Left, Vec3 Right) -{ - ASSERT_COVERED(SubV3); - - Vec3 Result; - Result.X = Left.X - Right.X; - Result.Y = Left.Y - Right.Y; - Result.Z = Left.Z - Right.Z; - - return Result; -} - -COVERAGE(SubV4, 1) -static inline Vec4 SubV4(Vec4 Left, Vec4 Right) -{ - ASSERT_COVERED(SubV4); - - Vec4 Result; - -#ifdef HANDMADE_MATH__USE_SSE - Result.SSE = _mm_sub_ps(Left.SSE, Right.SSE); -#elif defined(HANDMADE_MATH__USE_NEON) - Result.NEON = vsubq_f32(Left.NEON, Right.NEON); -#else - Result.X = Left.X - Right.X; - Result.Y = Left.Y - Right.Y; - Result.Z = Left.Z - Right.Z; - Result.W = Left.W - Right.W; -#endif - - return Result; -} - -COVERAGE(MulV2, 1) -static inline Vec2 MulV2(Vec2 Left, Vec2 Right) -{ - ASSERT_COVERED(MulV2); - - Vec2 Result; - Result.X = Left.X * Right.X; - Result.Y = Left.Y * Right.Y; - - return Result; -} - -COVERAGE(MulV2F, 1) -static inline Vec2 MulV2F(Vec2 Left, float Right) -{ - ASSERT_COVERED(MulV2F); - - Vec2 Result; - Result.X = Left.X * Right; - Result.Y = Left.Y * Right; - - return Result; -} - -COVERAGE(MulV3, 1) -static inline Vec3 MulV3(Vec3 Left, Vec3 Right) -{ - ASSERT_COVERED(MulV3); - - Vec3 Result; - Result.X = Left.X * Right.X; - Result.Y = Left.Y * Right.Y; - Result.Z = Left.Z * Right.Z; - - return Result; -} - -COVERAGE(MulV3F, 1) -static inline Vec3 MulV3F(Vec3 Left, float Right) -{ - ASSERT_COVERED(MulV3F); - - Vec3 Result; - Result.X = Left.X * Right; - Result.Y = Left.Y * Right; - Result.Z = Left.Z * Right; - - return Result; -} - -COVERAGE(MulV4, 1) -static inline Vec4 MulV4(Vec4 Left, Vec4 Right) -{ - ASSERT_COVERED(MulV4); - - Vec4 Result; - -#ifdef HANDMADE_MATH__USE_SSE - Result.SSE = _mm_mul_ps(Left.SSE, Right.SSE); -#elif defined(HANDMADE_MATH__USE_NEON) - Result.NEON = vmulq_f32(Left.NEON, Right.NEON); -#else - Result.X = Left.X * Right.X; - Result.Y = Left.Y * Right.Y; - Result.Z = Left.Z * Right.Z; - Result.W = Left.W * Right.W; -#endif - - return Result; -} - -COVERAGE(MulV4F, 1) -static inline Vec4 MulV4F(Vec4 Left, float Right) -{ - ASSERT_COVERED(MulV4F); - - Vec4 Result; - -#ifdef HANDMADE_MATH__USE_SSE - __m128 Scalar = _mm_set1_ps(Right); - Result.SSE = _mm_mul_ps(Left.SSE, Scalar); -#elif defined(HANDMADE_MATH__USE_NEON) - Result.NEON = vmulq_n_f32(Left.NEON, Right); -#else - Result.X = Left.X * Right; - Result.Y = Left.Y * Right; - Result.Z = Left.Z * Right; - Result.W = Left.W * Right; -#endif - - return Result; -} - -COVERAGE(DivV2, 1) -static inline Vec2 DivV2(Vec2 Left, Vec2 Right) -{ - ASSERT_COVERED(DivV2); - - Vec2 Result; - Result.X = Left.X / Right.X; - Result.Y = Left.Y / Right.Y; - - return Result; -} - -COVERAGE(DivV2F, 1) -static inline Vec2 DivV2F(Vec2 Left, float Right) -{ - ASSERT_COVERED(DivV2F); - - Vec2 Result; - Result.X = Left.X / Right; - Result.Y = Left.Y / Right; - - return Result; -} - -COVERAGE(DivV3, 1) -static inline Vec3 DivV3(Vec3 Left, Vec3 Right) -{ - ASSERT_COVERED(DivV3); - - Vec3 Result; - Result.X = Left.X / Right.X; - Result.Y = Left.Y / Right.Y; - Result.Z = Left.Z / Right.Z; - - return Result; -} - -COVERAGE(DivV3F, 1) -static inline Vec3 DivV3F(Vec3 Left, float Right) -{ - ASSERT_COVERED(DivV3F); - - Vec3 Result; - Result.X = Left.X / Right; - Result.Y = Left.Y / Right; - Result.Z = Left.Z / Right; - - return Result; -} - -COVERAGE(DivV4, 1) -static inline Vec4 DivV4(Vec4 Left, Vec4 Right) -{ - ASSERT_COVERED(DivV4); - - Vec4 Result; - -#ifdef HANDMADE_MATH__USE_SSE - Result.SSE = _mm_div_ps(Left.SSE, Right.SSE); -#elif defined(HANDMADE_MATH__USE_NEON) - Result.NEON = vdivq_f32(Left.NEON, Right.NEON); -#else - Result.X = Left.X / Right.X; - Result.Y = Left.Y / Right.Y; - Result.Z = Left.Z / Right.Z; - Result.W = Left.W / Right.W; -#endif - - return Result; -} - -COVERAGE(DivV4F, 1) -static inline Vec4 DivV4F(Vec4 Left, float Right) -{ - ASSERT_COVERED(DivV4F); - - Vec4 Result; - -#ifdef HANDMADE_MATH__USE_SSE - __m128 Scalar = _mm_set1_ps(Right); - Result.SSE = _mm_div_ps(Left.SSE, Scalar); -#elif defined(HANDMADE_MATH__USE_NEON) - float32x4_t Scalar = vdupq_n_f32(Right); - Result.NEON = vdivq_f32(Left.NEON, Scalar); -#else - Result.X = Left.X / Right; - Result.Y = Left.Y / Right; - Result.Z = Left.Z / Right; - Result.W = Left.W / Right; -#endif - - return Result; -} - -COVERAGE(EqV2, 1) -static inline Bool EqV2(Vec2 Left, Vec2 Right) -{ - ASSERT_COVERED(EqV2); - return Left.X == Right.X && Left.Y == Right.Y; -} - -COVERAGE(EqV3, 1) -static inline Bool EqV3(Vec3 Left, Vec3 Right) -{ - ASSERT_COVERED(EqV3); - return Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z; -} - -COVERAGE(EqV4, 1) -static inline Bool EqV4(Vec4 Left, Vec4 Right) -{ - ASSERT_COVERED(EqV4); - return Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z && Left.W == Right.W; -} - -COVERAGE(DotV2, 1) -static inline float DotV2(Vec2 Left, Vec2 Right) -{ - ASSERT_COVERED(DotV2); - return (Left.X * Right.X) + (Left.Y * Right.Y); -} - -COVERAGE(DotV3, 1) -static inline float DotV3(Vec3 Left, Vec3 Right) -{ - ASSERT_COVERED(DotV3); - return (Left.X * Right.X) + (Left.Y * Right.Y) + (Left.Z * Right.Z); -} - -COVERAGE(DotV4, 1) -static inline float DotV4(Vec4 Left, Vec4 Right) -{ - ASSERT_COVERED(DotV4); - - float Result; - - // NOTE(zak): IN the future if we wanna check what version SSE is support - // we can use _mm_dp_ps (4.3) but for now we will use the old way. - // Or a r = _mm_mul_ps(v1, v2), r = _mm_hadd_ps(r, r), r = _mm_hadd_ps(r, r) for SSE3 -#ifdef HANDMADE_MATH__USE_SSE - __m128 SSEResultOne = _mm_mul_ps(Left.SSE, Right.SSE); - __m128 SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(2, 3, 0, 1)); - SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo); - SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(0, 1, 2, 3)); - SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo); - _mm_store_ss(&Result, SSEResultOne); -#elif defined(HANDMADE_MATH__USE_NEON) - float32x4_t NEONMultiplyResult = vmulq_f32(Left.NEON, Right.NEON); - float32x4_t NEONHalfAdd = vpaddq_f32(NEONMultiplyResult, NEONMultiplyResult); - float32x4_t NEONFullAdd = vpaddq_f32(NEONHalfAdd, NEONHalfAdd); - Result = vgetq_lane_f32(NEONFullAdd, 0); -#else - Result = ((Left.X * Right.X) + (Left.Z * Right.Z)) + ((Left.Y * Right.Y) + (Left.W * Right.W)); -#endif - - return Result; -} - -COVERAGE(Cross, 1) -static inline Vec3 Cross(Vec3 Left, Vec3 Right) -{ - ASSERT_COVERED(Cross); - - Vec3 Result; - Result.X = (Left.Y * Right.Z) - (Left.Z * Right.Y); - Result.Y = (Left.Z * Right.X) - (Left.X * Right.Z); - Result.Z = (Left.X * Right.Y) - (Left.Y * Right.X); - - return Result; -} - - -/* - * Unary vector operations - */ - -COVERAGE(LenSqrV2, 1) -static inline float LenSqrV2(Vec2 A) -{ - ASSERT_COVERED(LenSqrV2); - return DotV2(A, A); -} - -COVERAGE(LenSqrV3, 1) -static inline float LenSqrV3(Vec3 A) -{ - ASSERT_COVERED(LenSqrV3); - return DotV3(A, A); -} - -COVERAGE(LenSqrV4, 1) -static inline float LenSqrV4(Vec4 A) -{ - ASSERT_COVERED(LenSqrV4); - return DotV4(A, A); -} - -COVERAGE(LenV2, 1) -static inline float LenV2(Vec2 A) -{ - ASSERT_COVERED(LenV2); - return SqrtF(LenSqrV2(A)); -} - -COVERAGE(LenV3, 1) -static inline float LenV3(Vec3 A) -{ - ASSERT_COVERED(LenV3); - return SqrtF(LenSqrV3(A)); -} - -COVERAGE(LenV4, 1) -static inline float LenV4(Vec4 A) -{ - ASSERT_COVERED(LenV4); - return SqrtF(LenSqrV4(A)); -} - -COVERAGE(NormV2, 1) -static inline Vec2 NormV2(Vec2 A) -{ - ASSERT_COVERED(NormV2); - return MulV2F(A, InvSqrtF(DotV2(A, A))); -} - -COVERAGE(NormV3, 1) -static inline Vec3 NormV3(Vec3 A) -{ - ASSERT_COVERED(NormV3); - return MulV3F(A, InvSqrtF(DotV3(A, A))); -} - -COVERAGE(NormV4, 1) -static inline Vec4 NormV4(Vec4 A) -{ - ASSERT_COVERED(NormV4); - return MulV4F(A, InvSqrtF(DotV4(A, A))); -} - -/* - * Utility vector functions - */ - -COVERAGE(LerpV2, 1) -static inline Vec2 LerpV2(Vec2 A, float Time, Vec2 B) -{ - ASSERT_COVERED(LerpV2); - return AddV2(MulV2F(A, 1.0f - Time), MulV2F(B, Time)); -} - -COVERAGE(LerpV3, 1) -static inline Vec3 LerpV3(Vec3 A, float Time, Vec3 B) -{ - ASSERT_COVERED(LerpV3); - return AddV3(MulV3F(A, 1.0f - Time), MulV3F(B, Time)); -} - -COVERAGE(LerpV4, 1) -static inline Vec4 LerpV4(Vec4 A, float Time, Vec4 B) -{ - ASSERT_COVERED(LerpV4); - return AddV4(MulV4F(A, 1.0f - Time), MulV4F(B, Time)); -} - -/* - * SSE stuff - */ - -COVERAGE(LinearCombineV4M4, 1) -static inline Vec4 LinearCombineV4M4(Vec4 Left, Mat4 Right) -{ - ASSERT_COVERED(LinearCombineV4M4); - - Vec4 Result; -#ifdef HANDMADE_MATH__USE_SSE - Result.SSE = _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0x00), Right.Columns[0].SSE); - Result.SSE = _mm_add_ps(Result.SSE, _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0x55), Right.Columns[1].SSE)); - Result.SSE = _mm_add_ps(Result.SSE, _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0xaa), Right.Columns[2].SSE)); - Result.SSE = _mm_add_ps(Result.SSE, _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0xff), Right.Columns[3].SSE)); -#elif defined(HANDMADE_MATH__USE_NEON) - Result.NEON = vmulq_laneq_f32(Right.Columns[0].NEON, Left.NEON, 0); - Result.NEON = vfmaq_laneq_f32(Result.NEON, Right.Columns[1].NEON, Left.NEON, 1); - Result.NEON = vfmaq_laneq_f32(Result.NEON, Right.Columns[2].NEON, Left.NEON, 2); - Result.NEON = vfmaq_laneq_f32(Result.NEON, Right.Columns[3].NEON, Left.NEON, 3); -#else - Result.X = Left.Elements[0] * Right.Columns[0].X; - Result.Y = Left.Elements[0] * Right.Columns[0].Y; - Result.Z = Left.Elements[0] * Right.Columns[0].Z; - Result.W = Left.Elements[0] * Right.Columns[0].W; - - Result.X += Left.Elements[1] * Right.Columns[1].X; - Result.Y += Left.Elements[1] * Right.Columns[1].Y; - Result.Z += Left.Elements[1] * Right.Columns[1].Z; - Result.W += Left.Elements[1] * Right.Columns[1].W; - - Result.X += Left.Elements[2] * Right.Columns[2].X; - Result.Y += Left.Elements[2] * Right.Columns[2].Y; - Result.Z += Left.Elements[2] * Right.Columns[2].Z; - Result.W += Left.Elements[2] * Right.Columns[2].W; - - Result.X += Left.Elements[3] * Right.Columns[3].X; - Result.Y += Left.Elements[3] * Right.Columns[3].Y; - Result.Z += Left.Elements[3] * Right.Columns[3].Z; - Result.W += Left.Elements[3] * Right.Columns[3].W; -#endif - - return Result; -} - -/* - * 2x2 Matrices - */ - -COVERAGE(M2, 1) -static inline Mat2 M2(void) -{ - ASSERT_COVERED(M2); - Mat2 Result = {0}; - return Result; -} - -COVERAGE(M2D, 1) -static inline Mat2 M2D(float Diagonal) -{ - ASSERT_COVERED(M2D); - - Mat2 Result = {0}; - Result.Elements[0][0] = Diagonal; - Result.Elements[1][1] = Diagonal; - - return Result; -} - -COVERAGE(TransposeM2, 1) -static inline Mat2 TransposeM2(Mat2 Matrix) -{ - ASSERT_COVERED(TransposeM2); - - Mat2 Result = Matrix; - - Result.Elements[0][1] = Matrix.Elements[1][0]; - Result.Elements[1][0] = Matrix.Elements[0][1]; - - return Result; -} - -COVERAGE(AddM2, 1) -static inline Mat2 AddM2(Mat2 Left, Mat2 Right) -{ - ASSERT_COVERED(AddM2); - - Mat2 Result; - - Result.Elements[0][0] = Left.Elements[0][0] + Right.Elements[0][0]; - Result.Elements[0][1] = Left.Elements[0][1] + Right.Elements[0][1]; - Result.Elements[1][0] = Left.Elements[1][0] + Right.Elements[1][0]; - Result.Elements[1][1] = Left.Elements[1][1] + Right.Elements[1][1]; - - return Result; -} - -COVERAGE(SubM2, 1) -static inline Mat2 SubM2(Mat2 Left, Mat2 Right) -{ - ASSERT_COVERED(SubM2); - - Mat2 Result; - - Result.Elements[0][0] = Left.Elements[0][0] - Right.Elements[0][0]; - Result.Elements[0][1] = Left.Elements[0][1] - Right.Elements[0][1]; - Result.Elements[1][0] = Left.Elements[1][0] - Right.Elements[1][0]; - Result.Elements[1][1] = Left.Elements[1][1] - Right.Elements[1][1]; - - return Result; -} - -COVERAGE(MulM2V2, 1) -static inline Vec2 MulM2V2(Mat2 Matrix, Vec2 Vector) -{ - ASSERT_COVERED(MulM2V2); - - Vec2 Result; - - Result.X = Vector.Elements[0] * Matrix.Columns[0].X; - Result.Y = Vector.Elements[0] * Matrix.Columns[0].Y; - - Result.X += Vector.Elements[1] * Matrix.Columns[1].X; - Result.Y += Vector.Elements[1] * Matrix.Columns[1].Y; - - return Result; -} - -COVERAGE(MulM2, 1) -static inline Mat2 MulM2(Mat2 Left, Mat2 Right) -{ - ASSERT_COVERED(MulM2); - - Mat2 Result; - Result.Columns[0] = MulM2V2(Left, Right.Columns[0]); - Result.Columns[1] = MulM2V2(Left, Right.Columns[1]); - - return Result; -} - -COVERAGE(MulM2F, 1) -static inline Mat2 MulM2F(Mat2 Matrix, float Scalar) -{ - ASSERT_COVERED(MulM2F); - - Mat2 Result; - - Result.Elements[0][0] = Matrix.Elements[0][0] * Scalar; - Result.Elements[0][1] = Matrix.Elements[0][1] * Scalar; - Result.Elements[1][0] = Matrix.Elements[1][0] * Scalar; - Result.Elements[1][1] = Matrix.Elements[1][1] * Scalar; - - return Result; -} - -COVERAGE(DivM2F, 1) -static inline Mat2 DivM2F(Mat2 Matrix, float Scalar) -{ - ASSERT_COVERED(DivM2F); - - Mat2 Result; - - Result.Elements[0][0] = Matrix.Elements[0][0] / Scalar; - Result.Elements[0][1] = Matrix.Elements[0][1] / Scalar; - Result.Elements[1][0] = Matrix.Elements[1][0] / Scalar; - Result.Elements[1][1] = Matrix.Elements[1][1] / Scalar; - - return Result; -} - -COVERAGE(DeterminantM2, 1) -static inline float DeterminantM2(Mat2 Matrix) -{ - ASSERT_COVERED(DeterminantM2); - return Matrix.Elements[0][0]*Matrix.Elements[1][1] - Matrix.Elements[0][1]*Matrix.Elements[1][0]; -} - - -COVERAGE(InvGeneralM2, 1) -static inline Mat2 InvGeneralM2(Mat2 Matrix) -{ - ASSERT_COVERED(InvGeneralM2); - - Mat2 Result; - float InvDeterminant = 1.0f / DeterminantM2(Matrix); - Result.Elements[0][0] = InvDeterminant * +Matrix.Elements[1][1]; - Result.Elements[1][1] = InvDeterminant * +Matrix.Elements[0][0]; - Result.Elements[0][1] = InvDeterminant * -Matrix.Elements[0][1]; - Result.Elements[1][0] = InvDeterminant * -Matrix.Elements[1][0]; - - return Result; -} - -/* - * 3x3 Matrices - */ - -COVERAGE(M3, 1) -static inline Mat3 M3(void) -{ - ASSERT_COVERED(M3); - Mat3 Result = {0}; - return Result; -} - -COVERAGE(M3D, 1) -static inline Mat3 M3D(float Diagonal) -{ - ASSERT_COVERED(M3D); - - Mat3 Result = {0}; - Result.Elements[0][0] = Diagonal; - Result.Elements[1][1] = Diagonal; - Result.Elements[2][2] = Diagonal; - - return Result; -} - -COVERAGE(TransposeM3, 1) -static inline Mat3 TransposeM3(Mat3 Matrix) -{ - ASSERT_COVERED(TransposeM3); - - Mat3 Result = Matrix; - - Result.Elements[0][1] = Matrix.Elements[1][0]; - Result.Elements[0][2] = Matrix.Elements[2][0]; - Result.Elements[1][0] = Matrix.Elements[0][1]; - Result.Elements[1][2] = Matrix.Elements[2][1]; - Result.Elements[2][1] = Matrix.Elements[1][2]; - Result.Elements[2][0] = Matrix.Elements[0][2]; - - return Result; -} - -COVERAGE(AddM3, 1) -static inline Mat3 AddM3(Mat3 Left, Mat3 Right) -{ - ASSERT_COVERED(AddM3); - - Mat3 Result; - - Result.Elements[0][0] = Left.Elements[0][0] + Right.Elements[0][0]; - Result.Elements[0][1] = Left.Elements[0][1] + Right.Elements[0][1]; - Result.Elements[0][2] = Left.Elements[0][2] + Right.Elements[0][2]; - Result.Elements[1][0] = Left.Elements[1][0] + Right.Elements[1][0]; - Result.Elements[1][1] = Left.Elements[1][1] + Right.Elements[1][1]; - Result.Elements[1][2] = Left.Elements[1][2] + Right.Elements[1][2]; - Result.Elements[2][0] = Left.Elements[2][0] + Right.Elements[2][0]; - Result.Elements[2][1] = Left.Elements[2][1] + Right.Elements[2][1]; - Result.Elements[2][2] = Left.Elements[2][2] + Right.Elements[2][2]; - - return Result; -} - -COVERAGE(SubM3, 1) -static inline Mat3 SubM3(Mat3 Left, Mat3 Right) -{ - ASSERT_COVERED(SubM3); - - Mat3 Result; - - Result.Elements[0][0] = Left.Elements[0][0] - Right.Elements[0][0]; - Result.Elements[0][1] = Left.Elements[0][1] - Right.Elements[0][1]; - Result.Elements[0][2] = Left.Elements[0][2] - Right.Elements[0][2]; - Result.Elements[1][0] = Left.Elements[1][0] - Right.Elements[1][0]; - Result.Elements[1][1] = Left.Elements[1][1] - Right.Elements[1][1]; - Result.Elements[1][2] = Left.Elements[1][2] - Right.Elements[1][2]; - Result.Elements[2][0] = Left.Elements[2][0] - Right.Elements[2][0]; - Result.Elements[2][1] = Left.Elements[2][1] - Right.Elements[2][1]; - Result.Elements[2][2] = Left.Elements[2][2] - Right.Elements[2][2]; - - return Result; -} - -COVERAGE(MulM3V3, 1) -static inline Vec3 MulM3V3(Mat3 Matrix, Vec3 Vector) -{ - ASSERT_COVERED(MulM3V3); - - Vec3 Result; - - Result.X = Vector.Elements[0] * Matrix.Columns[0].X; - Result.Y = Vector.Elements[0] * Matrix.Columns[0].Y; - Result.Z = Vector.Elements[0] * Matrix.Columns[0].Z; - - Result.X += Vector.Elements[1] * Matrix.Columns[1].X; - Result.Y += Vector.Elements[1] * Matrix.Columns[1].Y; - Result.Z += Vector.Elements[1] * Matrix.Columns[1].Z; - - Result.X += Vector.Elements[2] * Matrix.Columns[2].X; - Result.Y += Vector.Elements[2] * Matrix.Columns[2].Y; - Result.Z += Vector.Elements[2] * Matrix.Columns[2].Z; - - return Result; -} - -COVERAGE(MulM3, 1) -static inline Mat3 MulM3(Mat3 Left, Mat3 Right) -{ - ASSERT_COVERED(MulM3); - - Mat3 Result; - Result.Columns[0] = MulM3V3(Left, Right.Columns[0]); - Result.Columns[1] = MulM3V3(Left, Right.Columns[1]); - Result.Columns[2] = MulM3V3(Left, Right.Columns[2]); - - return Result; -} - -COVERAGE(MulM3F, 1) -static inline Mat3 MulM3F(Mat3 Matrix, float Scalar) -{ - ASSERT_COVERED(MulM3F); - - Mat3 Result; - - Result.Elements[0][0] = Matrix.Elements[0][0] * Scalar; - Result.Elements[0][1] = Matrix.Elements[0][1] * Scalar; - Result.Elements[0][2] = Matrix.Elements[0][2] * Scalar; - Result.Elements[1][0] = Matrix.Elements[1][0] * Scalar; - Result.Elements[1][1] = Matrix.Elements[1][1] * Scalar; - Result.Elements[1][2] = Matrix.Elements[1][2] * Scalar; - Result.Elements[2][0] = Matrix.Elements[2][0] * Scalar; - Result.Elements[2][1] = Matrix.Elements[2][1] * Scalar; - Result.Elements[2][2] = Matrix.Elements[2][2] * Scalar; - - return Result; -} - -COVERAGE(DivM3F, 1) -static inline Mat3 DivM3F(Mat3 Matrix, float Scalar) -{ - ASSERT_COVERED(DivM3F); - - Mat3 Result; - - Result.Elements[0][0] = Matrix.Elements[0][0] / Scalar; - Result.Elements[0][1] = Matrix.Elements[0][1] / Scalar; - Result.Elements[0][2] = Matrix.Elements[0][2] / Scalar; - Result.Elements[1][0] = Matrix.Elements[1][0] / Scalar; - Result.Elements[1][1] = Matrix.Elements[1][1] / Scalar; - Result.Elements[1][2] = Matrix.Elements[1][2] / Scalar; - Result.Elements[2][0] = Matrix.Elements[2][0] / Scalar; - Result.Elements[2][1] = Matrix.Elements[2][1] / Scalar; - Result.Elements[2][2] = Matrix.Elements[2][2] / Scalar; - - return Result; -} - -COVERAGE(DeterminantM3, 1) -static inline float DeterminantM3(Mat3 Matrix) -{ - ASSERT_COVERED(DeterminantM3); - - Mat3 _Cross; - _Cross.Columns[0] = Cross(Matrix.Columns[1], Matrix.Columns[2]); - _Cross.Columns[1] = Cross(Matrix.Columns[2], Matrix.Columns[0]); - _Cross.Columns[2] = Cross(Matrix.Columns[0], Matrix.Columns[1]); - - return DotV3(_Cross.Columns[2], Matrix.Columns[2]); -} - -COVERAGE(InvGeneralM3, 1) -static inline Mat3 InvGeneralM3(Mat3 Matrix) -{ - ASSERT_COVERED(InvGeneralM3); - - Mat3 _Cross; - _Cross.Columns[0] = Cross(Matrix.Columns[1], Matrix.Columns[2]); - _Cross.Columns[1] = Cross(Matrix.Columns[2], Matrix.Columns[0]); - _Cross.Columns[2] = Cross(Matrix.Columns[0], Matrix.Columns[1]); - - float InvDeterminant = 1.0f / DotV3(_Cross.Columns[2], Matrix.Columns[2]); - - Mat3 Result; - Result.Columns[0] = MulV3F(_Cross.Columns[0], InvDeterminant); - Result.Columns[1] = MulV3F(_Cross.Columns[1], InvDeterminant); - Result.Columns[2] = MulV3F(_Cross.Columns[2], InvDeterminant); - - return TransposeM3(Result); -} - -/* - * 4x4 Matrices - */ - -COVERAGE(M4, 1) -static inline Mat4 M4(void) -{ - ASSERT_COVERED(M4); - Mat4 Result = {0}; - return Result; -} - -COVERAGE(M4D, 1) -static inline Mat4 M4D(float Diagonal) -{ - ASSERT_COVERED(M4D); - - Mat4 Result = {0}; - Result.Elements[0][0] = Diagonal; - Result.Elements[1][1] = Diagonal; - Result.Elements[2][2] = Diagonal; - Result.Elements[3][3] = Diagonal; - - return Result; -} - -COVERAGE(TransposeM4, 1) -static inline Mat4 TransposeM4(Mat4 Matrix) -{ - ASSERT_COVERED(TransposeM4); - - Mat4 Result; -#ifdef HANDMADE_MATH__USE_SSE - Result = Matrix; - _MM_TRANSPOSE4_PS(Result.Columns[0].SSE, Result.Columns[1].SSE, Result.Columns[2].SSE, Result.Columns[3].SSE); -#elif defined(HANDMADE_MATH__USE_NEON) - float32x4x4_t Transposed = vld4q_f32((float*)Matrix.Columns); - Result.Columns[0].NEON = Transposed.val[0]; - Result.Columns[1].NEON = Transposed.val[1]; - Result.Columns[2].NEON = Transposed.val[2]; - Result.Columns[3].NEON = Transposed.val[3]; -#else - Result.Elements[0][0] = Matrix.Elements[0][0]; - Result.Elements[0][1] = Matrix.Elements[1][0]; - Result.Elements[0][2] = Matrix.Elements[2][0]; - Result.Elements[0][3] = Matrix.Elements[3][0]; - Result.Elements[1][0] = Matrix.Elements[0][1]; - Result.Elements[1][1] = Matrix.Elements[1][1]; - Result.Elements[1][2] = Matrix.Elements[2][1]; - Result.Elements[1][3] = Matrix.Elements[3][1]; - Result.Elements[2][0] = Matrix.Elements[0][2]; - Result.Elements[2][1] = Matrix.Elements[1][2]; - Result.Elements[2][2] = Matrix.Elements[2][2]; - Result.Elements[2][3] = Matrix.Elements[3][2]; - Result.Elements[3][0] = Matrix.Elements[0][3]; - Result.Elements[3][1] = Matrix.Elements[1][3]; - Result.Elements[3][2] = Matrix.Elements[2][3]; - Result.Elements[3][3] = Matrix.Elements[3][3]; -#endif - - return Result; -} - -COVERAGE(AddM4, 1) -static inline Mat4 AddM4(Mat4 Left, Mat4 Right) -{ - ASSERT_COVERED(AddM4); - - Mat4 Result; - - Result.Columns[0] = AddV4(Left.Columns[0], Right.Columns[0]); - Result.Columns[1] = AddV4(Left.Columns[1], Right.Columns[1]); - Result.Columns[2] = AddV4(Left.Columns[2], Right.Columns[2]); - Result.Columns[3] = AddV4(Left.Columns[3], Right.Columns[3]); - - return Result; -} - -COVERAGE(SubM4, 1) -static inline Mat4 SubM4(Mat4 Left, Mat4 Right) -{ - ASSERT_COVERED(SubM4); - - Mat4 Result; - - Result.Columns[0] = SubV4(Left.Columns[0], Right.Columns[0]); - Result.Columns[1] = SubV4(Left.Columns[1], Right.Columns[1]); - Result.Columns[2] = SubV4(Left.Columns[2], Right.Columns[2]); - Result.Columns[3] = SubV4(Left.Columns[3], Right.Columns[3]); - - return Result; -} - -COVERAGE(MulM4, 1) -static inline Mat4 MulM4(Mat4 Left, Mat4 Right) -{ - ASSERT_COVERED(MulM4); - - Mat4 Result; - Result.Columns[0] = LinearCombineV4M4(Right.Columns[0], Left); - Result.Columns[1] = LinearCombineV4M4(Right.Columns[1], Left); - Result.Columns[2] = LinearCombineV4M4(Right.Columns[2], Left); - Result.Columns[3] = LinearCombineV4M4(Right.Columns[3], Left); - - return Result; -} - -COVERAGE(MulM4F, 1) -static inline Mat4 MulM4F(Mat4 Matrix, float Scalar) -{ - ASSERT_COVERED(MulM4F); - - Mat4 Result; - - -#ifdef HANDMADE_MATH__USE_SSE - __m128 SSEScalar = _mm_set1_ps(Scalar); - Result.Columns[0].SSE = _mm_mul_ps(Matrix.Columns[0].SSE, SSEScalar); - Result.Columns[1].SSE = _mm_mul_ps(Matrix.Columns[1].SSE, SSEScalar); - Result.Columns[2].SSE = _mm_mul_ps(Matrix.Columns[2].SSE, SSEScalar); - Result.Columns[3].SSE = _mm_mul_ps(Matrix.Columns[3].SSE, SSEScalar); -#elif defined(HANDMADE_MATH__USE_NEON) - Result.Columns[0].NEON = vmulq_n_f32(Matrix.Columns[0].NEON, Scalar); - Result.Columns[1].NEON = vmulq_n_f32(Matrix.Columns[1].NEON, Scalar); - Result.Columns[2].NEON = vmulq_n_f32(Matrix.Columns[2].NEON, Scalar); - Result.Columns[3].NEON = vmulq_n_f32(Matrix.Columns[3].NEON, Scalar); -#else - Result.Elements[0][0] = Matrix.Elements[0][0] * Scalar; - Result.Elements[0][1] = Matrix.Elements[0][1] * Scalar; - Result.Elements[0][2] = Matrix.Elements[0][2] * Scalar; - Result.Elements[0][3] = Matrix.Elements[0][3] * Scalar; - Result.Elements[1][0] = Matrix.Elements[1][0] * Scalar; - Result.Elements[1][1] = Matrix.Elements[1][1] * Scalar; - Result.Elements[1][2] = Matrix.Elements[1][2] * Scalar; - Result.Elements[1][3] = Matrix.Elements[1][3] * Scalar; - Result.Elements[2][0] = Matrix.Elements[2][0] * Scalar; - Result.Elements[2][1] = Matrix.Elements[2][1] * Scalar; - Result.Elements[2][2] = Matrix.Elements[2][2] * Scalar; - Result.Elements[2][3] = Matrix.Elements[2][3] * Scalar; - Result.Elements[3][0] = Matrix.Elements[3][0] * Scalar; - Result.Elements[3][1] = Matrix.Elements[3][1] * Scalar; - Result.Elements[3][2] = Matrix.Elements[3][2] * Scalar; - Result.Elements[3][3] = Matrix.Elements[3][3] * Scalar; -#endif - - return Result; -} - -COVERAGE(MulM4V4, 1) -static inline Vec4 MulM4V4(Mat4 Matrix, Vec4 Vector) -{ - ASSERT_COVERED(MulM4V4); - return LinearCombineV4M4(Vector, Matrix); -} - -COVERAGE(DivM4F, 1) -static inline Mat4 DivM4F(Mat4 Matrix, float Scalar) -{ - ASSERT_COVERED(DivM4F); - - Mat4 Result; - -#ifdef HANDMADE_MATH__USE_SSE - __m128 SSEScalar = _mm_set1_ps(Scalar); - Result.Columns[0].SSE = _mm_div_ps(Matrix.Columns[0].SSE, SSEScalar); - Result.Columns[1].SSE = _mm_div_ps(Matrix.Columns[1].SSE, SSEScalar); - Result.Columns[2].SSE = _mm_div_ps(Matrix.Columns[2].SSE, SSEScalar); - Result.Columns[3].SSE = _mm_div_ps(Matrix.Columns[3].SSE, SSEScalar); -#elif defined(HANDMADE_MATH__USE_NEON) - float32x4_t NEONScalar = vdupq_n_f32(Scalar); - Result.Columns[0].NEON = vdivq_f32(Matrix.Columns[0].NEON, NEONScalar); - Result.Columns[1].NEON = vdivq_f32(Matrix.Columns[1].NEON, NEONScalar); - Result.Columns[2].NEON = vdivq_f32(Matrix.Columns[2].NEON, NEONScalar); - Result.Columns[3].NEON = vdivq_f32(Matrix.Columns[3].NEON, NEONScalar); -#else - Result.Elements[0][0] = Matrix.Elements[0][0] / Scalar; - Result.Elements[0][1] = Matrix.Elements[0][1] / Scalar; - Result.Elements[0][2] = Matrix.Elements[0][2] / Scalar; - Result.Elements[0][3] = Matrix.Elements[0][3] / Scalar; - Result.Elements[1][0] = Matrix.Elements[1][0] / Scalar; - Result.Elements[1][1] = Matrix.Elements[1][1] / Scalar; - Result.Elements[1][2] = Matrix.Elements[1][2] / Scalar; - Result.Elements[1][3] = Matrix.Elements[1][3] / Scalar; - Result.Elements[2][0] = Matrix.Elements[2][0] / Scalar; - Result.Elements[2][1] = Matrix.Elements[2][1] / Scalar; - Result.Elements[2][2] = Matrix.Elements[2][2] / Scalar; - Result.Elements[2][3] = Matrix.Elements[2][3] / Scalar; - Result.Elements[3][0] = Matrix.Elements[3][0] / Scalar; - Result.Elements[3][1] = Matrix.Elements[3][1] / Scalar; - Result.Elements[3][2] = Matrix.Elements[3][2] / Scalar; - Result.Elements[3][3] = Matrix.Elements[3][3] / Scalar; -#endif - - return Result; -} - -COVERAGE(DeterminantM4, 1) -static inline float DeterminantM4(Mat4 Matrix) -{ - ASSERT_COVERED(DeterminantM4); - - Vec3 C01 = Cross(Matrix.Columns[0].XYZ, Matrix.Columns[1].XYZ); - Vec3 C23 = Cross(Matrix.Columns[2].XYZ, Matrix.Columns[3].XYZ); - Vec3 B10 = SubV3(MulV3F(Matrix.Columns[0].XYZ, Matrix.Columns[1].W), MulV3F(Matrix.Columns[1].XYZ, Matrix.Columns[0].W)); - Vec3 B32 = SubV3(MulV3F(Matrix.Columns[2].XYZ, Matrix.Columns[3].W), MulV3F(Matrix.Columns[3].XYZ, Matrix.Columns[2].W)); - - return DotV3(C01, B32) + DotV3(C23, B10); -} - -COVERAGE(InvGeneralM4, 1) -// Returns a general-purpose inverse of an Mat4. Note that special-purpose inverses of many transformations -// are available and will be more efficient. -static inline Mat4 InvGeneralM4(Mat4 Matrix) -{ - ASSERT_COVERED(InvGeneralM4); - - Vec3 C01 = Cross(Matrix.Columns[0].XYZ, Matrix.Columns[1].XYZ); - Vec3 C23 = Cross(Matrix.Columns[2].XYZ, Matrix.Columns[3].XYZ); - Vec3 B10 = SubV3(MulV3F(Matrix.Columns[0].XYZ, Matrix.Columns[1].W), MulV3F(Matrix.Columns[1].XYZ, Matrix.Columns[0].W)); - Vec3 B32 = SubV3(MulV3F(Matrix.Columns[2].XYZ, Matrix.Columns[3].W), MulV3F(Matrix.Columns[3].XYZ, Matrix.Columns[2].W)); - - float InvDeterminant = 1.0f / (DotV3(C01, B32) + DotV3(C23, B10)); - C01 = MulV3F(C01, InvDeterminant); - C23 = MulV3F(C23, InvDeterminant); - B10 = MulV3F(B10, InvDeterminant); - B32 = MulV3F(B32, InvDeterminant); - - Mat4 Result; - Result.Columns[0] = V4V(AddV3(Cross(Matrix.Columns[1].XYZ, B32), MulV3F(C23, Matrix.Columns[1].W)), -DotV3(Matrix.Columns[1].XYZ, C23)); - Result.Columns[1] = V4V(SubV3(Cross(B32, Matrix.Columns[0].XYZ), MulV3F(C23, Matrix.Columns[0].W)), +DotV3(Matrix.Columns[0].XYZ, C23)); - Result.Columns[2] = V4V(AddV3(Cross(Matrix.Columns[3].XYZ, B10), MulV3F(C01, Matrix.Columns[3].W)), -DotV3(Matrix.Columns[3].XYZ, C01)); - Result.Columns[3] = V4V(SubV3(Cross(B10, Matrix.Columns[2].XYZ), MulV3F(C01, Matrix.Columns[2].W)), +DotV3(Matrix.Columns[2].XYZ, C01)); - - return TransposeM4(Result); -} - -/* - * Common graphics transformations - */ - -COVERAGE(Orthographic_RH_NO, 1) -// Produces a right-handed orthographic projection matrix with Z ranging from -1 to 1 (the GL convention). -// Left, Right, Bottom, and Top specify the coordinates of their respective clipping planes. -// Near and Far specify the distances to the near and far clipping planes. -static inline Mat4 Orthographic_RH_NO(float Left, float Right, float Bottom, float Top, float Near, float Far) -{ - ASSERT_COVERED(Orthographic_RH_NO); - - Mat4 Result = {0}; - - Result.Elements[0][0] = 2.0f / (Right - Left); - Result.Elements[1][1] = 2.0f / (Top - Bottom); - Result.Elements[2][2] = 2.0f / (Near - Far); - Result.Elements[3][3] = 1.0f; - - Result.Elements[3][0] = (Left + Right) / (Left - Right); - Result.Elements[3][1] = (Bottom + Top) / (Bottom - Top); - Result.Elements[3][2] = (Near + Far) / (Near - Far); - - return Result; -} - -COVERAGE(Orthographic_RH_ZO, 1) -// Produces a right-handed orthographic projection matrix with Z ranging from 0 to 1 (the DirectX convention). -// Left, Right, Bottom, and Top specify the coordinates of their respective clipping planes. -// Near and Far specify the distances to the near and far clipping planes. -static inline Mat4 Orthographic_RH_ZO(float Left, float Right, float Bottom, float Top, float Near, float Far) -{ - ASSERT_COVERED(Orthographic_RH_ZO); - - Mat4 Result = {0}; - - Result.Elements[0][0] = 2.0f / (Right - Left); - Result.Elements[1][1] = 2.0f / (Top - Bottom); - Result.Elements[2][2] = 1.0f / (Near - Far); - Result.Elements[3][3] = 1.0f; - - Result.Elements[3][0] = (Left + Right) / (Left - Right); - Result.Elements[3][1] = (Bottom + Top) / (Bottom - Top); - Result.Elements[3][2] = (Near) / (Near - Far); - - return Result; -} - -COVERAGE(Orthographic_LH_NO, 1) -// Produces a left-handed orthographic projection matrix with Z ranging from -1 to 1 (the GL convention). -// Left, Right, Bottom, and Top specify the coordinates of their respective clipping planes. -// Near and Far specify the distances to the near and far clipping planes. -static inline Mat4 Orthographic_LH_NO(float Left, float Right, float Bottom, float Top, float Near, float Far) -{ - ASSERT_COVERED(Orthographic_LH_NO); - - Mat4 Result = Orthographic_RH_NO(Left, Right, Bottom, Top, Near, Far); - Result.Elements[2][2] = -Result.Elements[2][2]; - - return Result; -} - -COVERAGE(Orthographic_LH_ZO, 1) -// Produces a left-handed orthographic projection matrix with Z ranging from 0 to 1 (the DirectX convention). -// Left, Right, Bottom, and Top specify the coordinates of their respective clipping planes. -// Near and Far specify the distances to the near and far clipping planes. -static inline Mat4 Orthographic_LH_ZO(float Left, float Right, float Bottom, float Top, float Near, float Far) -{ - ASSERT_COVERED(Orthographic_LH_ZO); - - Mat4 Result = Orthographic_RH_ZO(Left, Right, Bottom, Top, Near, Far); - Result.Elements[2][2] = -Result.Elements[2][2]; - - return Result; -} - -COVERAGE(InvOrthographic, 1) -// Returns an inverse for the given orthographic projection matrix. Works for all orthographic -// projection matrices, regardless of handedness or NDC convention. -static inline Mat4 InvOrthographic(Mat4 OrthoMatrix) -{ - ASSERT_COVERED(InvOrthographic); - - Mat4 Result = {0}; - Result.Elements[0][0] = 1.0f / OrthoMatrix.Elements[0][0]; - Result.Elements[1][1] = 1.0f / OrthoMatrix.Elements[1][1]; - Result.Elements[2][2] = 1.0f / OrthoMatrix.Elements[2][2]; - Result.Elements[3][3] = 1.0f; - - Result.Elements[3][0] = -OrthoMatrix.Elements[3][0] * Result.Elements[0][0]; - Result.Elements[3][1] = -OrthoMatrix.Elements[3][1] * Result.Elements[1][1]; - Result.Elements[3][2] = -OrthoMatrix.Elements[3][2] * Result.Elements[2][2]; - - return Result; -} - -COVERAGE(Perspective_RH_NO, 1) -static inline Mat4 Perspective_RH_NO(float FOV, float AspectRatio, float Near, float Far) -{ - ASSERT_COVERED(Perspective_RH_NO); - - Mat4 Result = {0}; - - // See https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml - - float Cotangent = 1.0f / TanF(FOV / 2.0f); - Result.Elements[0][0] = Cotangent / AspectRatio; - Result.Elements[1][1] = Cotangent; - Result.Elements[2][3] = -1.0f; - - Result.Elements[2][2] = (Near + Far) / (Near - Far); - Result.Elements[3][2] = (2.0f * Near * Far) / (Near - Far); - - return Result; -} - -COVERAGE(Perspective_RH_ZO, 1) -static inline Mat4 Perspective_RH_ZO(float FOV, float AspectRatio, float Near, float Far) -{ - ASSERT_COVERED(Perspective_RH_ZO); - - Mat4 Result = {0}; - - // See https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml - - float Cotangent = 1.0f / TanF(FOV / 2.0f); - Result.Elements[0][0] = Cotangent / AspectRatio; - Result.Elements[1][1] = Cotangent; - Result.Elements[2][3] = -1.0f; - - Result.Elements[2][2] = (Far) / (Near - Far); - Result.Elements[3][2] = (Near * Far) / (Near - Far); - - return Result; -} - -COVERAGE(Perspective_LH_NO, 1) -static inline Mat4 Perspective_LH_NO(float FOV, float AspectRatio, float Near, float Far) -{ - ASSERT_COVERED(Perspective_LH_NO); - - Mat4 Result = Perspective_RH_NO(FOV, AspectRatio, Near, Far); - Result.Elements[2][2] = -Result.Elements[2][2]; - Result.Elements[2][3] = -Result.Elements[2][3]; - - return Result; -} - -COVERAGE(Perspective_LH_ZO, 1) -static inline Mat4 Perspective_LH_ZO(float FOV, float AspectRatio, float Near, float Far) -{ - ASSERT_COVERED(Perspective_LH_ZO); - - Mat4 Result = Perspective_RH_ZO(FOV, AspectRatio, Near, Far); - Result.Elements[2][2] = -Result.Elements[2][2]; - Result.Elements[2][3] = -Result.Elements[2][3]; - - return Result; -} - -COVERAGE(InvPerspective_RH, 1) -static inline Mat4 InvPerspective_RH(Mat4 PerspectiveMatrix) -{ - ASSERT_COVERED(InvPerspective_RH); - - Mat4 Result = {0}; - Result.Elements[0][0] = 1.0f / PerspectiveMatrix.Elements[0][0]; - Result.Elements[1][1] = 1.0f / PerspectiveMatrix.Elements[1][1]; - Result.Elements[2][2] = 0.0f; - - Result.Elements[2][3] = 1.0f / PerspectiveMatrix.Elements[3][2]; - Result.Elements[3][3] = PerspectiveMatrix.Elements[2][2] * Result.Elements[2][3]; - Result.Elements[3][2] = PerspectiveMatrix.Elements[2][3]; - - return Result; -} - -COVERAGE(InvPerspective_LH, 1) -static inline Mat4 InvPerspective_LH(Mat4 PerspectiveMatrix) -{ - ASSERT_COVERED(InvPerspective_LH); - - Mat4 Result = {0}; - Result.Elements[0][0] = 1.0f / PerspectiveMatrix.Elements[0][0]; - Result.Elements[1][1] = 1.0f / PerspectiveMatrix.Elements[1][1]; - Result.Elements[2][2] = 0.0f; - - Result.Elements[2][3] = 1.0f / PerspectiveMatrix.Elements[3][2]; - Result.Elements[3][3] = PerspectiveMatrix.Elements[2][2] * -Result.Elements[2][3]; - Result.Elements[3][2] = PerspectiveMatrix.Elements[2][3]; - - return Result; -} - -COVERAGE(Translate, 1) -static inline Mat4 Translate(Vec3 Translation) -{ - ASSERT_COVERED(Translate); - - Mat4 Result = M4D(1.0f); - Result.Elements[3][0] = Translation.X; - Result.Elements[3][1] = Translation.Y; - Result.Elements[3][2] = Translation.Z; - - return Result; -} - -COVERAGE(InvTranslate, 1) -static inline Mat4 InvTranslate(Mat4 TranslationMatrix) -{ - ASSERT_COVERED(InvTranslate); - - Mat4 Result = TranslationMatrix; - Result.Elements[3][0] = -Result.Elements[3][0]; - Result.Elements[3][1] = -Result.Elements[3][1]; - Result.Elements[3][2] = -Result.Elements[3][2]; - - return Result; -} - -COVERAGE(Rotate_RH, 1) -static inline Mat4 Rotate_RH(float Angle, Vec3 Axis) -{ - ASSERT_COVERED(Rotate_RH); - - Mat4 Result = M4D(1.0f); - - Axis = NormV3(Axis); - - float SinTheta = SinF(Angle); - float CosTheta = CosF(Angle); - float CosValue = 1.0f - CosTheta; - - Result.Elements[0][0] = (Axis.X * Axis.X * CosValue) + CosTheta; - Result.Elements[0][1] = (Axis.X * Axis.Y * CosValue) + (Axis.Z * SinTheta); - Result.Elements[0][2] = (Axis.X * Axis.Z * CosValue) - (Axis.Y * SinTheta); - - Result.Elements[1][0] = (Axis.Y * Axis.X * CosValue) - (Axis.Z * SinTheta); - Result.Elements[1][1] = (Axis.Y * Axis.Y * CosValue) + CosTheta; - Result.Elements[1][2] = (Axis.Y * Axis.Z * CosValue) + (Axis.X * SinTheta); - - Result.Elements[2][0] = (Axis.Z * Axis.X * CosValue) + (Axis.Y * SinTheta); - Result.Elements[2][1] = (Axis.Z * Axis.Y * CosValue) - (Axis.X * SinTheta); - Result.Elements[2][2] = (Axis.Z * Axis.Z * CosValue) + CosTheta; - - return Result; -} - -COVERAGE(Rotate_LH, 1) -static inline Mat4 Rotate_LH(float Angle, Vec3 Axis) -{ - ASSERT_COVERED(Rotate_LH); - /* NOTE(lcf): Matrix will be inverse/transpose of RH. */ - return Rotate_RH(-Angle, Axis); -} - -COVERAGE(InvRotate, 1) -static inline Mat4 InvRotate(Mat4 RotationMatrix) -{ - ASSERT_COVERED(InvRotate); - return TransposeM4(RotationMatrix); -} - -COVERAGE(Scale, 1) -static inline Mat4 Scale(Vec3 Scale) -{ - ASSERT_COVERED(Scale); - - Mat4 Result = M4D(1.0f); - Result.Elements[0][0] = Scale.X; - Result.Elements[1][1] = Scale.Y; - Result.Elements[2][2] = Scale.Z; - - return Result; -} - -COVERAGE(InvScale, 1) -static inline Mat4 InvScale(Mat4 ScaleMatrix) -{ - ASSERT_COVERED(InvScale); - - Mat4 Result = ScaleMatrix; - Result.Elements[0][0] = 1.0f / Result.Elements[0][0]; - Result.Elements[1][1] = 1.0f / Result.Elements[1][1]; - Result.Elements[2][2] = 1.0f / Result.Elements[2][2]; - - return Result; -} - -static inline Mat4 _LookAt(Vec3 F, Vec3 S, Vec3 U, Vec3 Eye) -{ - Mat4 Result; - - Result.Elements[0][0] = S.X; - Result.Elements[0][1] = U.X; - Result.Elements[0][2] = -F.X; - Result.Elements[0][3] = 0.0f; - - Result.Elements[1][0] = S.Y; - Result.Elements[1][1] = U.Y; - Result.Elements[1][2] = -F.Y; - Result.Elements[1][3] = 0.0f; - - Result.Elements[2][0] = S.Z; - Result.Elements[2][1] = U.Z; - Result.Elements[2][2] = -F.Z; - Result.Elements[2][3] = 0.0f; - - Result.Elements[3][0] = -DotV3(S, Eye); - Result.Elements[3][1] = -DotV3(U, Eye); - Result.Elements[3][2] = DotV3(F, Eye); - Result.Elements[3][3] = 1.0f; - - return Result; -} - -COVERAGE(LookAt_RH, 1) -static inline Mat4 LookAt_RH(Vec3 Eye, Vec3 Center, Vec3 Up) -{ - ASSERT_COVERED(LookAt_RH); - - Vec3 F = NormV3(SubV3(Center, Eye)); - Vec3 S = NormV3(Cross(F, Up)); - Vec3 U = Cross(S, F); - - return _LookAt(F, S, U, Eye); -} - -COVERAGE(LookAt_LH, 1) -static inline Mat4 LookAt_LH(Vec3 Eye, Vec3 Center, Vec3 Up) -{ - ASSERT_COVERED(LookAt_LH); - - Vec3 F = NormV3(SubV3(Eye, Center)); - Vec3 S = NormV3(Cross(F, Up)); - Vec3 U = Cross(S, F); - - return _LookAt(F, S, U, Eye); -} - -COVERAGE(InvLookAt, 1) -static inline Mat4 InvLookAt(Mat4 Matrix) -{ - ASSERT_COVERED(InvLookAt); - Mat4 Result; - - Mat3 Rotation = {0}; - Rotation.Columns[0] = Matrix.Columns[0].XYZ; - Rotation.Columns[1] = Matrix.Columns[1].XYZ; - Rotation.Columns[2] = Matrix.Columns[2].XYZ; - Rotation = TransposeM3(Rotation); - - Result.Columns[0] = V4V(Rotation.Columns[0], 0.0f); - Result.Columns[1] = V4V(Rotation.Columns[1], 0.0f); - Result.Columns[2] = V4V(Rotation.Columns[2], 0.0f); - Result.Columns[3] = MulV4F(Matrix.Columns[3], -1.0f); - Result.Elements[3][0] = -1.0f * Matrix.Elements[3][0] / - (Rotation.Elements[0][0] + Rotation.Elements[0][1] + Rotation.Elements[0][2]); - Result.Elements[3][1] = -1.0f * Matrix.Elements[3][1] / - (Rotation.Elements[1][0] + Rotation.Elements[1][1] + Rotation.Elements[1][2]); - Result.Elements[3][2] = -1.0f * Matrix.Elements[3][2] / - (Rotation.Elements[2][0] + Rotation.Elements[2][1] + Rotation.Elements[2][2]); - Result.Elements[3][3] = 1.0f; - - return Result; -} - -/* - * Quaternion operations - */ - -COVERAGE(Q, 1) -static inline Quat Q(float X, float Y, float Z, float W) -{ - ASSERT_COVERED(Q); - - Quat Result; - -#ifdef HANDMADE_MATH__USE_SSE - Result.SSE = _mm_setr_ps(X, Y, Z, W); -#elif defined(HANDMADE_MATH__USE_NEON) - float32x4_t v = { X, Y, Z, W }; - Result.NEON = v; -#else - Result.X = X; - Result.Y = Y; - Result.Z = Z; - Result.W = W; -#endif - - return Result; -} - -COVERAGE(QV4, 1) -static inline Quat QV4(Vec4 Vector) -{ - ASSERT_COVERED(QV4); - - Quat Result; - -#ifdef HANDMADE_MATH__USE_SSE - Result.SSE = Vector.SSE; -#elif defined(HANDMADE_MATH__USE_NEON) - Result.NEON = Vector.NEON; -#else - Result.X = Vector.X; - Result.Y = Vector.Y; - Result.Z = Vector.Z; - Result.W = Vector.W; -#endif - - return Result; -} - -COVERAGE(AddQ, 1) -static inline Quat AddQ(Quat Left, Quat Right) -{ - ASSERT_COVERED(AddQ); - - Quat Result; - -#ifdef HANDMADE_MATH__USE_SSE - Result.SSE = _mm_add_ps(Left.SSE, Right.SSE); -#elif defined(HANDMADE_MATH__USE_NEON) - Result.NEON = vaddq_f32(Left.NEON, Right.NEON); -#else - - Result.X = Left.X + Right.X; - Result.Y = Left.Y + Right.Y; - Result.Z = Left.Z + Right.Z; - Result.W = Left.W + Right.W; -#endif - - return Result; -} - -COVERAGE(SubQ, 1) -static inline Quat SubQ(Quat Left, Quat Right) -{ - ASSERT_COVERED(SubQ); - - Quat Result; - -#ifdef HANDMADE_MATH__USE_SSE - Result.SSE = _mm_sub_ps(Left.SSE, Right.SSE); -#elif defined(HANDMADE_MATH__USE_NEON) - Result.NEON = vsubq_f32(Left.NEON, Right.NEON); -#else - Result.X = Left.X - Right.X; - Result.Y = Left.Y - Right.Y; - Result.Z = Left.Z - Right.Z; - Result.W = Left.W - Right.W; -#endif - - return Result; -} - -COVERAGE(MulQ, 1) -static inline Quat MulQ(Quat Left, Quat Right) -{ - ASSERT_COVERED(MulQ); - - Quat Result; - -#ifdef HANDMADE_MATH__USE_SSE - __m128 SSEResultOne = _mm_xor_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, _MM_SHUFFLE(0, 0, 0, 0)), _mm_setr_ps(0.f, -0.f, 0.f, -0.f)); - __m128 SSEResultTwo = _mm_shuffle_ps(Right.SSE, Right.SSE, _MM_SHUFFLE(0, 1, 2, 3)); - __m128 SSEResultThree = _mm_mul_ps(SSEResultTwo, SSEResultOne); - - SSEResultOne = _mm_xor_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, _MM_SHUFFLE(1, 1, 1, 1)) , _mm_setr_ps(0.f, 0.f, -0.f, -0.f)); - SSEResultTwo = _mm_shuffle_ps(Right.SSE, Right.SSE, _MM_SHUFFLE(1, 0, 3, 2)); - SSEResultThree = _mm_add_ps(SSEResultThree, _mm_mul_ps(SSEResultTwo, SSEResultOne)); - - SSEResultOne = _mm_xor_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, _MM_SHUFFLE(2, 2, 2, 2)), _mm_setr_ps(-0.f, 0.f, 0.f, -0.f)); - SSEResultTwo = _mm_shuffle_ps(Right.SSE, Right.SSE, _MM_SHUFFLE(2, 3, 0, 1)); - SSEResultThree = _mm_add_ps(SSEResultThree, _mm_mul_ps(SSEResultTwo, SSEResultOne)); - - SSEResultOne = _mm_shuffle_ps(Left.SSE, Left.SSE, _MM_SHUFFLE(3, 3, 3, 3)); - SSEResultTwo = _mm_shuffle_ps(Right.SSE, Right.SSE, _MM_SHUFFLE(3, 2, 1, 0)); - Result.SSE = _mm_add_ps(SSEResultThree, _mm_mul_ps(SSEResultTwo, SSEResultOne)); -#elif defined(HANDMADE_MATH__USE_NEON) - float32x4_t Right1032 = vrev64q_f32(Right.NEON); - float32x4_t Right3210 = vcombine_f32(vget_high_f32(Right1032), vget_low_f32(Right1032)); - float32x4_t Right2301 = vrev64q_f32(Right3210); - - float32x4_t FirstSign = {1.0f, -1.0f, 1.0f, -1.0f}; - Result.NEON = vmulq_f32(Right3210, vmulq_f32(vdupq_laneq_f32(Left.NEON, 0), FirstSign)); - float32x4_t SecondSign = {1.0f, 1.0f, -1.0f, -1.0f}; - Result.NEON = vfmaq_f32(Result.NEON, Right2301, vmulq_f32(vdupq_laneq_f32(Left.NEON, 1), SecondSign)); - float32x4_t ThirdSign = {-1.0f, 1.0f, 1.0f, -1.0f}; - Result.NEON = vfmaq_f32(Result.NEON, Right1032, vmulq_f32(vdupq_laneq_f32(Left.NEON, 2), ThirdSign)); - Result.NEON = vfmaq_laneq_f32(Result.NEON, Right.NEON, Left.NEON, 3); - -#else - Result.X = Right.Elements[3] * +Left.Elements[0]; - Result.Y = Right.Elements[2] * -Left.Elements[0]; - Result.Z = Right.Elements[1] * +Left.Elements[0]; - Result.W = Right.Elements[0] * -Left.Elements[0]; - - Result.X += Right.Elements[2] * +Left.Elements[1]; - Result.Y += Right.Elements[3] * +Left.Elements[1]; - Result.Z += Right.Elements[0] * -Left.Elements[1]; - Result.W += Right.Elements[1] * -Left.Elements[1]; - - Result.X += Right.Elements[1] * -Left.Elements[2]; - Result.Y += Right.Elements[0] * +Left.Elements[2]; - Result.Z += Right.Elements[3] * +Left.Elements[2]; - Result.W += Right.Elements[2] * -Left.Elements[2]; - - Result.X += Right.Elements[0] * +Left.Elements[3]; - Result.Y += Right.Elements[1] * +Left.Elements[3]; - Result.Z += Right.Elements[2] * +Left.Elements[3]; - Result.W += Right.Elements[3] * +Left.Elements[3]; -#endif - - return Result; -} - -COVERAGE(MulQF, 1) -static inline Quat MulQF(Quat Left, float Multiplicative) -{ - ASSERT_COVERED(MulQF); - - Quat Result; - -#ifdef HANDMADE_MATH__USE_SSE - __m128 Scalar = _mm_set1_ps(Multiplicative); - Result.SSE = _mm_mul_ps(Left.SSE, Scalar); -#elif defined(HANDMADE_MATH__USE_NEON) - Result.NEON = vmulq_n_f32(Left.NEON, Multiplicative); -#else - Result.X = Left.X * Multiplicative; - Result.Y = Left.Y * Multiplicative; - Result.Z = Left.Z * Multiplicative; - Result.W = Left.W * Multiplicative; -#endif - - return Result; -} - -COVERAGE(DivQF, 1) -static inline Quat DivQF(Quat Left, float Divnd) -{ - ASSERT_COVERED(DivQF); - - Quat Result; - -#ifdef HANDMADE_MATH__USE_SSE - __m128 Scalar = _mm_set1_ps(Divnd); - Result.SSE = _mm_div_ps(Left.SSE, Scalar); -#elif defined(HANDMADE_MATH__USE_NEON) - float32x4_t Scalar = vdupq_n_f32(Divnd); - Result.NEON = vdivq_f32(Left.NEON, Scalar); -#else - Result.X = Left.X / Divnd; - Result.Y = Left.Y / Divnd; - Result.Z = Left.Z / Divnd; - Result.W = Left.W / Divnd; -#endif - - return Result; -} - -COVERAGE(DotQ, 1) -static inline float DotQ(Quat Left, Quat Right) -{ - ASSERT_COVERED(DotQ); - - float Result; - -#ifdef HANDMADE_MATH__USE_SSE - __m128 SSEResultOne = _mm_mul_ps(Left.SSE, Right.SSE); - __m128 SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(2, 3, 0, 1)); - SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo); - SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(0, 1, 2, 3)); - SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo); - _mm_store_ss(&Result, SSEResultOne); -#elif defined(HANDMADE_MATH__USE_NEON) - float32x4_t NEONMultiplyResult = vmulq_f32(Left.NEON, Right.NEON); - float32x4_t NEONHalfAdd = vpaddq_f32(NEONMultiplyResult, NEONMultiplyResult); - float32x4_t NEONFullAdd = vpaddq_f32(NEONHalfAdd, NEONHalfAdd); - Result = vgetq_lane_f32(NEONFullAdd, 0); -#else - Result = ((Left.X * Right.X) + (Left.Z * Right.Z)) + ((Left.Y * Right.Y) + (Left.W * Right.W)); -#endif - - return Result; -} - -COVERAGE(InvQ, 1) -static inline Quat InvQ(Quat Left) -{ - ASSERT_COVERED(InvQ); - - Quat Result; - Result.X = -Left.X; - Result.Y = -Left.Y; - Result.Z = -Left.Z; - Result.W = Left.W; - - return DivQF(Result, (DotQ(Left, Left))); -} - -COVERAGE(NormQ, 1) -static inline Quat NormQ(Quat _Quat) -{ - ASSERT_COVERED(NormQ); - - /* NOTE(lcf): Take advantage of SSE implementation in NormV4 */ - Vec4 Vec = {_Quat.X, _Quat.Y, _Quat.Z, _Quat.W}; - Vec = NormV4(Vec); - Quat Result = {Vec.X, Vec.Y, Vec.Z, Vec.W}; - - return Result; -} - -static inline Quat _MixQ(Quat Left, float MixLeft, Quat Right, float MixRight) { - Quat Result; - -#ifdef HANDMADE_MATH__USE_SSE - __m128 ScalarLeft = _mm_set1_ps(MixLeft); - __m128 ScalarRight = _mm_set1_ps(MixRight); - __m128 SSEResultOne = _mm_mul_ps(Left.SSE, ScalarLeft); - __m128 SSEResultTwo = _mm_mul_ps(Right.SSE, ScalarRight); - Result.SSE = _mm_add_ps(SSEResultOne, SSEResultTwo); -#elif defined(HANDMADE_MATH__USE_NEON) - float32x4_t ScaledLeft = vmulq_n_f32(Left.NEON, MixLeft); - float32x4_t ScaledRight = vmulq_n_f32(Right.NEON, MixRight); - Result.NEON = vaddq_f32(ScaledLeft, ScaledRight); -#else - Result.X = Left.X*MixLeft + Right.X*MixRight; - Result.Y = Left.Y*MixLeft + Right.Y*MixRight; - Result.Z = Left.Z*MixLeft + Right.Z*MixRight; - Result.W = Left.W*MixLeft + Right.W*MixRight; -#endif - - return Result; -} - -COVERAGE(NLerp, 1) -static inline Quat NLerp(Quat Left, float Time, Quat Right) -{ - ASSERT_COVERED(NLerp); - - Quat Result = _MixQ(Left, 1.0f-Time, Right, Time); - Result = NormQ(Result); - - return Result; -} - -COVERAGE(SLerp, 1) -static inline Quat SLerp(Quat Left, float Time, Quat Right) -{ - ASSERT_COVERED(SLerp); - - Quat Result; - - float Cos_Theta = DotQ(Left, Right); - - if (Cos_Theta < 0.0f) { /* NOTE(lcf): Take shortest path on Hyper-sphere */ - Cos_Theta = -Cos_Theta; - Right = Q(-Right.X, -Right.Y, -Right.Z, -Right.W); - } - - /* NOTE(lcf): Use Normalized Linear interpolation when vectors are roughly not L.I. */ - if (Cos_Theta > 0.9995f) { - Result = NLerp(Left, Time, Right); - } else { - float Angle = ACosF(Cos_Theta); - float MixLeft = SinF((1.0f - Time) * Angle); - float MixRight = SinF(Time * Angle); - - Result = _MixQ(Left, MixLeft, Right, MixRight); - Result = NormQ(Result); - } - - return Result; -} - -COVERAGE(QToM4, 1) -static inline Mat4 QToM4(Quat Left) -{ - ASSERT_COVERED(QToM4); - - Mat4 Result; - - Quat NormalizedQ = NormQ(Left); - - float XX, YY, ZZ, - XY, XZ, YZ, - WX, WY, WZ; - - XX = NormalizedQ.X * NormalizedQ.X; - YY = NormalizedQ.Y * NormalizedQ.Y; - ZZ = NormalizedQ.Z * NormalizedQ.Z; - XY = NormalizedQ.X * NormalizedQ.Y; - XZ = NormalizedQ.X * NormalizedQ.Z; - YZ = NormalizedQ.Y * NormalizedQ.Z; - WX = NormalizedQ.W * NormalizedQ.X; - WY = NormalizedQ.W * NormalizedQ.Y; - WZ = NormalizedQ.W * NormalizedQ.Z; - - Result.Elements[0][0] = 1.0f - 2.0f * (YY + ZZ); - Result.Elements[0][1] = 2.0f * (XY + WZ); - Result.Elements[0][2] = 2.0f * (XZ - WY); - Result.Elements[0][3] = 0.0f; - - Result.Elements[1][0] = 2.0f * (XY - WZ); - Result.Elements[1][1] = 1.0f - 2.0f * (XX + ZZ); - Result.Elements[1][2] = 2.0f * (YZ + WX); - Result.Elements[1][3] = 0.0f; - - Result.Elements[2][0] = 2.0f * (XZ + WY); - Result.Elements[2][1] = 2.0f * (YZ - WX); - Result.Elements[2][2] = 1.0f - 2.0f * (XX + YY); - Result.Elements[2][3] = 0.0f; - - Result.Elements[3][0] = 0.0f; - Result.Elements[3][1] = 0.0f; - Result.Elements[3][2] = 0.0f; - Result.Elements[3][3] = 1.0f; - - return Result; -} - -// This method taken from Mike Day at Insomniac Games. -// https://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2015/01/matrix-to-quat.pdf -// -// Note that as mentioned at the top of the paper, the paper assumes the matrix -// would be *post*-multiplied to a vector to rotate it, meaning the matrix is -// the transpose of what we're dealing with. But, because our matrices are -// stored in column-major order, the indices *appear* to match the paper. -// -// For example, m12 in the paper is row 1, column 2. We need to transpose it to -// row 2, column 1. But, because the column comes first when referencing -// elements, it looks like M.Elements[1][2]. -// -// Don't be confused! Or if you must be confused, at least trust this -// comment. :) -COVERAGE(M4ToQ_RH, 4) -static inline Quat M4ToQ_RH(Mat4 M) -{ - float T; - Quat _Q; - - if (M.Elements[2][2] < 0.0f) { - if (M.Elements[0][0] > M.Elements[1][1]) { - ASSERT_COVERED(M4ToQ_RH); - - T = 1 + M.Elements[0][0] - M.Elements[1][1] - M.Elements[2][2]; - _Q = Q( - T, - M.Elements[0][1] + M.Elements[1][0], - M.Elements[2][0] + M.Elements[0][2], - M.Elements[1][2] - M.Elements[2][1] - ); - } else { - ASSERT_COVERED(M4ToQ_RH); - - T = 1 - M.Elements[0][0] + M.Elements[1][1] - M.Elements[2][2]; - _Q = Q( - M.Elements[0][1] + M.Elements[1][0], - T, - M.Elements[1][2] + M.Elements[2][1], - M.Elements[2][0] - M.Elements[0][2] - ); - } - } else { - if (M.Elements[0][0] < -M.Elements[1][1]) { - ASSERT_COVERED(M4ToQ_RH); - - T = 1 - M.Elements[0][0] - M.Elements[1][1] + M.Elements[2][2]; - _Q = Q( - M.Elements[2][0] + M.Elements[0][2], - M.Elements[1][2] + M.Elements[2][1], - T, - M.Elements[0][1] - M.Elements[1][0] - ); - } else { - ASSERT_COVERED(M4ToQ_RH); - - T = 1 + M.Elements[0][0] + M.Elements[1][1] + M.Elements[2][2]; - _Q = Q( - M.Elements[1][2] - M.Elements[2][1], - M.Elements[2][0] - M.Elements[0][2], - M.Elements[0][1] - M.Elements[1][0], - T - ); - } - } - - _Q = MulQF(_Q, 0.5f / SqrtF(T)); - - return _Q; -} - -COVERAGE(M4ToQ_LH, 4) -static inline Quat M4ToQ_LH(Mat4 M) -{ - float T; - Quat _Q; - - if (M.Elements[2][2] < 0.0f) { - if (M.Elements[0][0] > M.Elements[1][1]) { - ASSERT_COVERED(M4ToQ_LH); - - T = 1 + M.Elements[0][0] - M.Elements[1][1] - M.Elements[2][2]; - _Q = Q( - T, - M.Elements[0][1] + M.Elements[1][0], - M.Elements[2][0] + M.Elements[0][2], - M.Elements[2][1] - M.Elements[1][2] - ); - } else { - ASSERT_COVERED(M4ToQ_LH); - - T = 1 - M.Elements[0][0] + M.Elements[1][1] - M.Elements[2][2]; - _Q = Q( - M.Elements[0][1] + M.Elements[1][0], - T, - M.Elements[1][2] + M.Elements[2][1], - M.Elements[0][2] - M.Elements[2][0] - ); - } - } else { - if (M.Elements[0][0] < -M.Elements[1][1]) { - ASSERT_COVERED(M4ToQ_LH); - - T = 1 - M.Elements[0][0] - M.Elements[1][1] + M.Elements[2][2]; - _Q = Q( - M.Elements[2][0] + M.Elements[0][2], - M.Elements[1][2] + M.Elements[2][1], - T, - M.Elements[1][0] - M.Elements[0][1] - ); - } else { - ASSERT_COVERED(M4ToQ_LH); - - T = 1 + M.Elements[0][0] + M.Elements[1][1] + M.Elements[2][2]; - _Q = Q( - M.Elements[2][1] - M.Elements[1][2], - M.Elements[0][2] - M.Elements[2][0], - M.Elements[1][0] - M.Elements[0][2], - T - ); - } - } - - _Q = MulQF(_Q, 0.5f / SqrtF(T)); - - return _Q; -} - - -COVERAGE(QFromAxisAngle_RH, 1) -static inline Quat QFromAxisAngle_RH(Vec3 Axis, float Angle) -{ - ASSERT_COVERED(QFromAxisAngle_RH); - - Quat Result; - - Vec3 AxisNormalized = NormV3(Axis); - float SineOfRotation = SinF(Angle / 2.0f); - - Result.XYZ = MulV3F(AxisNormalized, SineOfRotation); - Result.W = CosF(Angle / 2.0f); - - return Result; -} - -COVERAGE(QFromAxisAngle_LH, 1) -static inline Quat QFromAxisAngle_LH(Vec3 Axis, float Angle) -{ - ASSERT_COVERED(QFromAxisAngle_LH); - - return QFromAxisAngle_RH(Axis, -Angle); -} - -COVERAGE(QFromNormPair, 1) -static inline Quat QFromNormPair(Vec3 Left, Vec3 Right) -{ - ASSERT_COVERED(QFromNormPair); - - Quat Result; - - Result.XYZ = Cross(Left, Right); - Result.W = 1.0f + DotV3(Left, Right); - - return NormQ(Result); -} - -COVERAGE(QFromVecPair, 1) -static inline Quat QFromVecPair(Vec3 Left, Vec3 Right) -{ - ASSERT_COVERED(QFromVecPair); - - return QFromNormPair(NormV3(Left), NormV3(Right)); -} - -COVERAGE(RotateV2, 1) -static inline Vec2 RotateV2(Vec2 V, float Angle) -{ - ASSERT_COVERED(RotateV2) - - float sinA = SinF(Angle); - float cosA = CosF(Angle); - - return V2(V.X * cosA - V.Y * sinA, V.X * sinA + V.Y * cosA); -} - -// implementation from -// https://blog.molecular-matters.com/2013/05/24/a-faster-quaternion-vector-multiplication/ -COVERAGE(RotateV3Q, 1) -static inline Vec3 RotateV3Q(Vec3 V, Quat Q) -{ - ASSERT_COVERED(RotateV3Q); - - Vec3 t = MulV3F(Cross(Q.XYZ, V), 2); - return AddV3(V, AddV3(MulV3F(t, Q.W), Cross(Q.XYZ, t))); -} - -COVERAGE(RotateV3AxisAngle_LH, 1) -static inline Vec3 RotateV3AxisAngle_LH(Vec3 V, Vec3 Axis, float Angle) { - ASSERT_COVERED(RotateV3AxisAngle_LH); - - return RotateV3Q(V, QFromAxisAngle_LH(Axis, Angle)); -} - -COVERAGE(RotateV3AxisAngle_RH, 1) -static inline Vec3 RotateV3AxisAngle_RH(Vec3 V, Vec3 Axis, float Angle) { - ASSERT_COVERED(RotateV3AxisAngle_RH); - - return RotateV3Q(V, QFromAxisAngle_RH(Axis, Angle)); -} - - -#ifdef __cplusplus -} -#endif - -#ifdef __cplusplus - -COVERAGE(LenV2CPP, 1) -static inline float Len(Vec2 A) -{ - ASSERT_COVERED(LenV2CPP); - return LenV2(A); -} - -COVERAGE(LenV3CPP, 1) -static inline float Len(Vec3 A) -{ - ASSERT_COVERED(LenV3CPP); - return LenV3(A); -} - -COVERAGE(LenV4CPP, 1) -static inline float Len(Vec4 A) -{ - ASSERT_COVERED(LenV4CPP); - return LenV4(A); -} - -COVERAGE(LenSqrV2CPP, 1) -static inline float LenSqr(Vec2 A) -{ - ASSERT_COVERED(LenSqrV2CPP); - return LenSqrV2(A); -} - -COVERAGE(LenSqrV3CPP, 1) -static inline float LenSqr(Vec3 A) -{ - ASSERT_COVERED(LenSqrV3CPP); - return LenSqrV3(A); -} - -COVERAGE(LenSqrV4CPP, 1) -static inline float LenSqr(Vec4 A) -{ - ASSERT_COVERED(LenSqrV4CPP); - return LenSqrV4(A); -} - -COVERAGE(NormV2CPP, 1) -static inline Vec2 Norm(Vec2 A) -{ - ASSERT_COVERED(NormV2CPP); - return NormV2(A); -} - -COVERAGE(NormV3CPP, 1) -static inline Vec3 Norm(Vec3 A) -{ - ASSERT_COVERED(NormV3CPP); - return NormV3(A); -} - -COVERAGE(NormV4CPP, 1) -static inline Vec4 Norm(Vec4 A) -{ - ASSERT_COVERED(NormV4CPP); - return NormV4(A); -} - -COVERAGE(NormQCPP, 1) -static inline Quat Norm(Quat A) -{ - ASSERT_COVERED(NormQCPP); - return NormQ(A); -} - -COVERAGE(DotV2CPP, 1) -static inline float Dot(Vec2 Left, Vec2 VecTwo) -{ - ASSERT_COVERED(DotV2CPP); - return DotV2(Left, VecTwo); -} - -COVERAGE(DotV3CPP, 1) -static inline float Dot(Vec3 Left, Vec3 VecTwo) -{ - ASSERT_COVERED(DotV3CPP); - return DotV3(Left, VecTwo); -} - -COVERAGE(DotV4CPP, 1) -static inline float Dot(Vec4 Left, Vec4 VecTwo) -{ - ASSERT_COVERED(DotV4CPP); - return DotV4(Left, VecTwo); -} - -COVERAGE(LerpV2CPP, 1) -static inline Vec2 Lerp(Vec2 Left, float Time, Vec2 Right) -{ - ASSERT_COVERED(LerpV2CPP); - return LerpV2(Left, Time, Right); -} - -COVERAGE(LerpV3CPP, 1) -static inline Vec3 Lerp(Vec3 Left, float Time, Vec3 Right) -{ - ASSERT_COVERED(LerpV3CPP); - return LerpV3(Left, Time, Right); -} - -COVERAGE(LerpV4CPP, 1) -static inline Vec4 Lerp(Vec4 Left, float Time, Vec4 Right) -{ - ASSERT_COVERED(LerpV4CPP); - return LerpV4(Left, Time, Right); -} - -COVERAGE(TransposeM2CPP, 1) -static inline Mat2 Transpose(Mat2 Matrix) -{ - ASSERT_COVERED(TransposeM2CPP); - return TransposeM2(Matrix); -} - -COVERAGE(TransposeM3CPP, 1) -static inline Mat3 Transpose(Mat3 Matrix) -{ - ASSERT_COVERED(TransposeM3CPP); - return TransposeM3(Matrix); -} - -COVERAGE(TransposeM4CPP, 1) -static inline Mat4 Transpose(Mat4 Matrix) -{ - ASSERT_COVERED(TransposeM4CPP); - return TransposeM4(Matrix); -} - -COVERAGE(DeterminantM2CPP, 1) -static inline float Determinant(Mat2 Matrix) -{ - ASSERT_COVERED(DeterminantM2CPP); - return DeterminantM2(Matrix); -} - -COVERAGE(DeterminantM3CPP, 1) -static inline float Determinant(Mat3 Matrix) -{ - ASSERT_COVERED(DeterminantM3CPP); - return DeterminantM3(Matrix); -} - -COVERAGE(DeterminantM4CPP, 1) -static inline float Determinant(Mat4 Matrix) -{ - ASSERT_COVERED(DeterminantM4CPP); - return DeterminantM4(Matrix); -} - -COVERAGE(InvGeneralM2CPP, 1) -static inline Mat2 InvGeneral(Mat2 Matrix) -{ - ASSERT_COVERED(InvGeneralM2CPP); - return InvGeneralM2(Matrix); -} - -COVERAGE(InvGeneralM3CPP, 1) -static inline Mat3 InvGeneral(Mat3 Matrix) -{ - ASSERT_COVERED(InvGeneralM3CPP); - return InvGeneralM3(Matrix); -} - -COVERAGE(InvGeneralM4CPP, 1) -static inline Mat4 InvGeneral(Mat4 Matrix) -{ - ASSERT_COVERED(InvGeneralM4CPP); - return InvGeneralM4(Matrix); -} - -COVERAGE(DotQCPP, 1) -static inline float Dot(Quat QuatOne, Quat QuatTwo) -{ - ASSERT_COVERED(DotQCPP); - return DotQ(QuatOne, QuatTwo); -} - -COVERAGE(AddV2CPP, 1) -static inline Vec2 Add(Vec2 Left, Vec2 Right) -{ - ASSERT_COVERED(AddV2CPP); - return AddV2(Left, Right); -} - -COVERAGE(AddV3CPP, 1) -static inline Vec3 Add(Vec3 Left, Vec3 Right) -{ - ASSERT_COVERED(AddV3CPP); - return AddV3(Left, Right); -} - -COVERAGE(AddV4CPP, 1) -static inline Vec4 Add(Vec4 Left, Vec4 Right) -{ - ASSERT_COVERED(AddV4CPP); - return AddV4(Left, Right); -} - -COVERAGE(AddM2CPP, 1) -static inline Mat2 Add(Mat2 Left, Mat2 Right) -{ - ASSERT_COVERED(AddM2CPP); - return AddM2(Left, Right); -} - -COVERAGE(AddM3CPP, 1) -static inline Mat3 Add(Mat3 Left, Mat3 Right) -{ - ASSERT_COVERED(AddM3CPP); - return AddM3(Left, Right); -} - -COVERAGE(AddM4CPP, 1) -static inline Mat4 Add(Mat4 Left, Mat4 Right) -{ - ASSERT_COVERED(AddM4CPP); - return AddM4(Left, Right); -} - -COVERAGE(AddQCPP, 1) -static inline Quat Add(Quat Left, Quat Right) -{ - ASSERT_COVERED(AddQCPP); - return AddQ(Left, Right); -} - -COVERAGE(SubV2CPP, 1) -static inline Vec2 Sub(Vec2 Left, Vec2 Right) -{ - ASSERT_COVERED(SubV2CPP); - return SubV2(Left, Right); -} - -COVERAGE(SubV3CPP, 1) -static inline Vec3 Sub(Vec3 Left, Vec3 Right) -{ - ASSERT_COVERED(SubV3CPP); - return SubV3(Left, Right); -} - -COVERAGE(SubV4CPP, 1) -static inline Vec4 Sub(Vec4 Left, Vec4 Right) -{ - ASSERT_COVERED(SubV4CPP); - return SubV4(Left, Right); -} - -COVERAGE(SubM2CPP, 1) -static inline Mat2 Sub(Mat2 Left, Mat2 Right) -{ - ASSERT_COVERED(SubM2CPP); - return SubM2(Left, Right); -} - -COVERAGE(SubM3CPP, 1) -static inline Mat3 Sub(Mat3 Left, Mat3 Right) -{ - ASSERT_COVERED(SubM3CPP); - return SubM3(Left, Right); -} - -COVERAGE(SubM4CPP, 1) -static inline Mat4 Sub(Mat4 Left, Mat4 Right) -{ - ASSERT_COVERED(SubM4CPP); - return SubM4(Left, Right); -} - -COVERAGE(SubQCPP, 1) -static inline Quat Sub(Quat Left, Quat Right) -{ - ASSERT_COVERED(SubQCPP); - return SubQ(Left, Right); -} - -COVERAGE(MulV2CPP, 1) -static inline Vec2 Mul(Vec2 Left, Vec2 Right) -{ - ASSERT_COVERED(MulV2CPP); - return MulV2(Left, Right); -} - -COVERAGE(MulV2FCPP, 1) -static inline Vec2 Mul(Vec2 Left, float Right) -{ - ASSERT_COVERED(MulV2FCPP); - return MulV2F(Left, Right); -} - -COVERAGE(MulV3CPP, 1) -static inline Vec3 Mul(Vec3 Left, Vec3 Right) -{ - ASSERT_COVERED(MulV3CPP); - return MulV3(Left, Right); -} - -COVERAGE(MulV3FCPP, 1) -static inline Vec3 Mul(Vec3 Left, float Right) -{ - ASSERT_COVERED(MulV3FCPP); - return MulV3F(Left, Right); -} - -COVERAGE(MulV4CPP, 1) -static inline Vec4 Mul(Vec4 Left, Vec4 Right) -{ - ASSERT_COVERED(MulV4CPP); - return MulV4(Left, Right); -} - -COVERAGE(MulV4FCPP, 1) -static inline Vec4 Mul(Vec4 Left, float Right) -{ - ASSERT_COVERED(MulV4FCPP); - return MulV4F(Left, Right); -} - -COVERAGE(MulM2CPP, 1) -static inline Mat2 Mul(Mat2 Left, Mat2 Right) -{ - ASSERT_COVERED(MulM2CPP); - return MulM2(Left, Right); -} - -COVERAGE(MulM3CPP, 1) -static inline Mat3 Mul(Mat3 Left, Mat3 Right) -{ - ASSERT_COVERED(MulM3CPP); - return MulM3(Left, Right); -} - -COVERAGE(MulM4CPP, 1) -static inline Mat4 Mul(Mat4 Left, Mat4 Right) -{ - ASSERT_COVERED(MulM4CPP); - return MulM4(Left, Right); -} - -COVERAGE(MulM2FCPP, 1) -static inline Mat2 Mul(Mat2 Left, float Right) -{ - ASSERT_COVERED(MulM2FCPP); - return MulM2F(Left, Right); -} - -COVERAGE(MulM3FCPP, 1) -static inline Mat3 Mul(Mat3 Left, float Right) -{ - ASSERT_COVERED(MulM3FCPP); - return MulM3F(Left, Right); -} - -COVERAGE(MulM4FCPP, 1) -static inline Mat4 Mul(Mat4 Left, float Right) -{ - ASSERT_COVERED(MulM4FCPP); - return MulM4F(Left, Right); -} - -COVERAGE(MulM2V2CPP, 1) -static inline Vec2 Mul(Mat2 Matrix, Vec2 Vector) -{ - ASSERT_COVERED(MulM2V2CPP); - return MulM2V2(Matrix, Vector); -} - -COVERAGE(MulM3V3CPP, 1) -static inline Vec3 Mul(Mat3 Matrix, Vec3 Vector) -{ - ASSERT_COVERED(MulM3V3CPP); - return MulM3V3(Matrix, Vector); -} - -COVERAGE(MulM4V4CPP, 1) -static inline Vec4 Mul(Mat4 Matrix, Vec4 Vector) -{ - ASSERT_COVERED(MulM4V4CPP); - return MulM4V4(Matrix, Vector); -} - -COVERAGE(MulQCPP, 1) -static inline Quat Mul(Quat Left, Quat Right) -{ - ASSERT_COVERED(MulQCPP); - return MulQ(Left, Right); -} - -COVERAGE(MulQFCPP, 1) -static inline Quat Mul(Quat Left, float Right) -{ - ASSERT_COVERED(MulQFCPP); - return MulQF(Left, Right); -} - -COVERAGE(DivV2CPP, 1) -static inline Vec2 Div(Vec2 Left, Vec2 Right) -{ - ASSERT_COVERED(DivV2CPP); - return DivV2(Left, Right); -} - -COVERAGE(DivV2FCPP, 1) -static inline Vec2 Div(Vec2 Left, float Right) -{ - ASSERT_COVERED(DivV2FCPP); - return DivV2F(Left, Right); -} - -COVERAGE(DivV3CPP, 1) -static inline Vec3 Div(Vec3 Left, Vec3 Right) -{ - ASSERT_COVERED(DivV3CPP); - return DivV3(Left, Right); -} - -COVERAGE(DivV3FCPP, 1) -static inline Vec3 Div(Vec3 Left, float Right) -{ - ASSERT_COVERED(DivV3FCPP); - return DivV3F(Left, Right); -} - -COVERAGE(DivV4CPP, 1) -static inline Vec4 Div(Vec4 Left, Vec4 Right) -{ - ASSERT_COVERED(DivV4CPP); - return DivV4(Left, Right); -} - -COVERAGE(DivV4FCPP, 1) -static inline Vec4 Div(Vec4 Left, float Right) -{ - ASSERT_COVERED(DivV4FCPP); - return DivV4F(Left, Right); -} - -COVERAGE(DivM2FCPP, 1) -static inline Mat2 Div(Mat2 Left, float Right) -{ - ASSERT_COVERED(DivM2FCPP); - return DivM2F(Left, Right); -} - -COVERAGE(DivM3FCPP, 1) -static inline Mat3 Div(Mat3 Left, float Right) -{ - ASSERT_COVERED(DivM3FCPP); - return DivM3F(Left, Right); -} - -COVERAGE(DivM4FCPP, 1) -static inline Mat4 Div(Mat4 Left, float Right) -{ - ASSERT_COVERED(DivM4FCPP); - return DivM4F(Left, Right); -} - -COVERAGE(DivQFCPP, 1) -static inline Quat Div(Quat Left, float Right) -{ - ASSERT_COVERED(DivQFCPP); - return DivQF(Left, Right); -} - -COVERAGE(EqV2CPP, 1) -static inline Bool Eq(Vec2 Left, Vec2 Right) -{ - ASSERT_COVERED(EqV2CPP); - return EqV2(Left, Right); -} - -COVERAGE(EqV3CPP, 1) -static inline Bool Eq(Vec3 Left, Vec3 Right) -{ - ASSERT_COVERED(EqV3CPP); - return EqV3(Left, Right); -} - -COVERAGE(EqV4CPP, 1) -static inline Bool Eq(Vec4 Left, Vec4 Right) -{ - ASSERT_COVERED(EqV4CPP); - return EqV4(Left, Right); -} - -COVERAGE(AddV2Op, 1) -static inline Vec2 operator+(Vec2 Left, Vec2 Right) -{ - ASSERT_COVERED(AddV2Op); - return AddV2(Left, Right); -} - -COVERAGE(AddV3Op, 1) -static inline Vec3 operator+(Vec3 Left, Vec3 Right) -{ - ASSERT_COVERED(AddV3Op); - return AddV3(Left, Right); -} - -COVERAGE(AddV4Op, 1) -static inline Vec4 operator+(Vec4 Left, Vec4 Right) -{ - ASSERT_COVERED(AddV4Op); - return AddV4(Left, Right); -} - -COVERAGE(AddM2Op, 1) -static inline Mat2 operator+(Mat2 Left, Mat2 Right) -{ - ASSERT_COVERED(AddM2Op); - return AddM2(Left, Right); -} - -COVERAGE(AddM3Op, 1) -static inline Mat3 operator+(Mat3 Left, Mat3 Right) -{ - ASSERT_COVERED(AddM3Op); - return AddM3(Left, Right); -} - -COVERAGE(AddM4Op, 1) -static inline Mat4 operator+(Mat4 Left, Mat4 Right) -{ - ASSERT_COVERED(AddM4Op); - return AddM4(Left, Right); -} - -COVERAGE(AddQOp, 1) -static inline Quat operator+(Quat Left, Quat Right) -{ - ASSERT_COVERED(AddQOp); - return AddQ(Left, Right); -} - -COVERAGE(SubV2Op, 1) -static inline Vec2 operator-(Vec2 Left, Vec2 Right) -{ - ASSERT_COVERED(SubV2Op); - return SubV2(Left, Right); -} - -COVERAGE(SubV3Op, 1) -static inline Vec3 operator-(Vec3 Left, Vec3 Right) -{ - ASSERT_COVERED(SubV3Op); - return SubV3(Left, Right); -} - -COVERAGE(SubV4Op, 1) -static inline Vec4 operator-(Vec4 Left, Vec4 Right) -{ - ASSERT_COVERED(SubV4Op); - return SubV4(Left, Right); -} - -COVERAGE(SubM2Op, 1) -static inline Mat2 operator-(Mat2 Left, Mat2 Right) -{ - ASSERT_COVERED(SubM2Op); - return SubM2(Left, Right); -} - -COVERAGE(SubM3Op, 1) -static inline Mat3 operator-(Mat3 Left, Mat3 Right) -{ - ASSERT_COVERED(SubM3Op); - return SubM3(Left, Right); -} - -COVERAGE(SubM4Op, 1) -static inline Mat4 operator-(Mat4 Left, Mat4 Right) -{ - ASSERT_COVERED(SubM4Op); - return SubM4(Left, Right); -} - -COVERAGE(SubQOp, 1) -static inline Quat operator-(Quat Left, Quat Right) -{ - ASSERT_COVERED(SubQOp); - return SubQ(Left, Right); -} - -COVERAGE(MulV2Op, 1) -static inline Vec2 operator*(Vec2 Left, Vec2 Right) -{ - ASSERT_COVERED(MulV2Op); - return MulV2(Left, Right); -} - -COVERAGE(MulV3Op, 1) -static inline Vec3 operator*(Vec3 Left, Vec3 Right) -{ - ASSERT_COVERED(MulV3Op); - return MulV3(Left, Right); -} - -COVERAGE(MulV4Op, 1) -static inline Vec4 operator*(Vec4 Left, Vec4 Right) -{ - ASSERT_COVERED(MulV4Op); - return MulV4(Left, Right); -} - -COVERAGE(MulM2Op, 1) -static inline Mat2 operator*(Mat2 Left, Mat2 Right) -{ - ASSERT_COVERED(MulM2Op); - return MulM2(Left, Right); -} - -COVERAGE(MulM3Op, 1) -static inline Mat3 operator*(Mat3 Left, Mat3 Right) -{ - ASSERT_COVERED(MulM3Op); - return MulM3(Left, Right); -} - -COVERAGE(MulM4Op, 1) -static inline Mat4 operator*(Mat4 Left, Mat4 Right) -{ - ASSERT_COVERED(MulM4Op); - return MulM4(Left, Right); -} - -COVERAGE(MulQOp, 1) -static inline Quat operator*(Quat Left, Quat Right) -{ - ASSERT_COVERED(MulQOp); - return MulQ(Left, Right); -} - -COVERAGE(MulV2FOp, 1) -static inline Vec2 operator*(Vec2 Left, float Right) -{ - ASSERT_COVERED(MulV2FOp); - return MulV2F(Left, Right); -} - -COVERAGE(MulV3FOp, 1) -static inline Vec3 operator*(Vec3 Left, float Right) -{ - ASSERT_COVERED(MulV3FOp); - return MulV3F(Left, Right); -} - -COVERAGE(MulV4FOp, 1) -static inline Vec4 operator*(Vec4 Left, float Right) -{ - ASSERT_COVERED(MulV4FOp); - return MulV4F(Left, Right); -} - -COVERAGE(MulM2FOp, 1) -static inline Mat2 operator*(Mat2 Left, float Right) -{ - ASSERT_COVERED(MulM2FOp); - return MulM2F(Left, Right); -} - -COVERAGE(MulM3FOp, 1) -static inline Mat3 operator*(Mat3 Left, float Right) -{ - ASSERT_COVERED(MulM3FOp); - return MulM3F(Left, Right); -} - -COVERAGE(MulM4FOp, 1) -static inline Mat4 operator*(Mat4 Left, float Right) -{ - ASSERT_COVERED(MulM4FOp); - return MulM4F(Left, Right); -} - -COVERAGE(MulQFOp, 1) -static inline Quat operator*(Quat Left, float Right) -{ - ASSERT_COVERED(MulQFOp); - return MulQF(Left, Right); -} - -COVERAGE(MulV2FOpLeft, 1) -static inline Vec2 operator*(float Left, Vec2 Right) -{ - ASSERT_COVERED(MulV2FOpLeft); - return MulV2F(Right, Left); -} - -COVERAGE(MulV3FOpLeft, 1) -static inline Vec3 operator*(float Left, Vec3 Right) -{ - ASSERT_COVERED(MulV3FOpLeft); - return MulV3F(Right, Left); -} - -COVERAGE(MulV4FOpLeft, 1) -static inline Vec4 operator*(float Left, Vec4 Right) -{ - ASSERT_COVERED(MulV4FOpLeft); - return MulV4F(Right, Left); -} - -COVERAGE(MulM2FOpLeft, 1) -static inline Mat2 operator*(float Left, Mat2 Right) -{ - ASSERT_COVERED(MulM2FOpLeft); - return MulM2F(Right, Left); -} - -COVERAGE(MulM3FOpLeft, 1) -static inline Mat3 operator*(float Left, Mat3 Right) -{ - ASSERT_COVERED(MulM3FOpLeft); - return MulM3F(Right, Left); -} - -COVERAGE(MulM4FOpLeft, 1) -static inline Mat4 operator*(float Left, Mat4 Right) -{ - ASSERT_COVERED(MulM4FOpLeft); - return MulM4F(Right, Left); -} - -COVERAGE(MulQFOpLeft, 1) -static inline Quat operator*(float Left, Quat Right) -{ - ASSERT_COVERED(MulQFOpLeft); - return MulQF(Right, Left); -} - -COVERAGE(MulM2V2Op, 1) -static inline Vec2 operator*(Mat2 Matrix, Vec2 Vector) -{ - ASSERT_COVERED(MulM2V2Op); - return MulM2V2(Matrix, Vector); -} - -COVERAGE(MulM3V3Op, 1) -static inline Vec3 operator*(Mat3 Matrix, Vec3 Vector) -{ - ASSERT_COVERED(MulM3V3Op); - return MulM3V3(Matrix, Vector); -} - -COVERAGE(MulM4V4Op, 1) -static inline Vec4 operator*(Mat4 Matrix, Vec4 Vector) -{ - ASSERT_COVERED(MulM4V4Op); - return MulM4V4(Matrix, Vector); -} - -COVERAGE(DivV2Op, 1) -static inline Vec2 operator/(Vec2 Left, Vec2 Right) -{ - ASSERT_COVERED(DivV2Op); - return DivV2(Left, Right); -} - -COVERAGE(DivV3Op, 1) -static inline Vec3 operator/(Vec3 Left, Vec3 Right) -{ - ASSERT_COVERED(DivV3Op); - return DivV3(Left, Right); -} - -COVERAGE(DivV4Op, 1) -static inline Vec4 operator/(Vec4 Left, Vec4 Right) -{ - ASSERT_COVERED(DivV4Op); - return DivV4(Left, Right); -} - -COVERAGE(DivV2FOp, 1) -static inline Vec2 operator/(Vec2 Left, float Right) -{ - ASSERT_COVERED(DivV2FOp); - return DivV2F(Left, Right); -} - -COVERAGE(DivV3FOp, 1) -static inline Vec3 operator/(Vec3 Left, float Right) -{ - ASSERT_COVERED(DivV3FOp); - return DivV3F(Left, Right); -} - -COVERAGE(DivV4FOp, 1) -static inline Vec4 operator/(Vec4 Left, float Right) -{ - ASSERT_COVERED(DivV4FOp); - return DivV4F(Left, Right); -} - -COVERAGE(DivM4FOp, 1) -static inline Mat4 operator/(Mat4 Left, float Right) -{ - ASSERT_COVERED(DivM4FOp); - return DivM4F(Left, Right); -} - -COVERAGE(DivM3FOp, 1) -static inline Mat3 operator/(Mat3 Left, float Right) -{ - ASSERT_COVERED(DivM3FOp); - return DivM3F(Left, Right); -} - -COVERAGE(DivM2FOp, 1) -static inline Mat2 operator/(Mat2 Left, float Right) -{ - ASSERT_COVERED(DivM2FOp); - return DivM2F(Left, Right); -} - -COVERAGE(DivQFOp, 1) -static inline Quat operator/(Quat Left, float Right) -{ - ASSERT_COVERED(DivQFOp); - return DivQF(Left, Right); -} - -COVERAGE(AddV2Assign, 1) -static inline Vec2 &operator+=(Vec2 &Left, Vec2 Right) -{ - ASSERT_COVERED(AddV2Assign); - return Left = Left + Right; -} - -COVERAGE(AddV3Assign, 1) -static inline Vec3 &operator+=(Vec3 &Left, Vec3 Right) -{ - ASSERT_COVERED(AddV3Assign); - return Left = Left + Right; -} - -COVERAGE(AddV4Assign, 1) -static inline Vec4 &operator+=(Vec4 &Left, Vec4 Right) -{ - ASSERT_COVERED(AddV4Assign); - return Left = Left + Right; -} - -COVERAGE(AddM2Assign, 1) -static inline Mat2 &operator+=(Mat2 &Left, Mat2 Right) -{ - ASSERT_COVERED(AddM2Assign); - return Left = Left + Right; -} - -COVERAGE(AddM3Assign, 1) -static inline Mat3 &operator+=(Mat3 &Left, Mat3 Right) -{ - ASSERT_COVERED(AddM3Assign); - return Left = Left + Right; -} - -COVERAGE(AddM4Assign, 1) -static inline Mat4 &operator+=(Mat4 &Left, Mat4 Right) -{ - ASSERT_COVERED(AddM4Assign); - return Left = Left + Right; -} - -COVERAGE(AddQAssign, 1) -static inline Quat &operator+=(Quat &Left, Quat Right) -{ - ASSERT_COVERED(AddQAssign); - return Left = Left + Right; -} - -COVERAGE(SubV2Assign, 1) -static inline Vec2 &operator-=(Vec2 &Left, Vec2 Right) -{ - ASSERT_COVERED(SubV2Assign); - return Left = Left - Right; -} - -COVERAGE(SubV3Assign, 1) -static inline Vec3 &operator-=(Vec3 &Left, Vec3 Right) -{ - ASSERT_COVERED(SubV3Assign); - return Left = Left - Right; -} - -COVERAGE(SubV4Assign, 1) -static inline Vec4 &operator-=(Vec4 &Left, Vec4 Right) -{ - ASSERT_COVERED(SubV4Assign); - return Left = Left - Right; -} - -COVERAGE(SubM2Assign, 1) -static inline Mat2 &operator-=(Mat2 &Left, Mat2 Right) -{ - ASSERT_COVERED(SubM2Assign); - return Left = Left - Right; -} - -COVERAGE(SubM3Assign, 1) -static inline Mat3 &operator-=(Mat3 &Left, Mat3 Right) -{ - ASSERT_COVERED(SubM3Assign); - return Left = Left - Right; -} - -COVERAGE(SubM4Assign, 1) -static inline Mat4 &operator-=(Mat4 &Left, Mat4 Right) -{ - ASSERT_COVERED(SubM4Assign); - return Left = Left - Right; -} - -COVERAGE(SubQAssign, 1) -static inline Quat &operator-=(Quat &Left, Quat Right) -{ - ASSERT_COVERED(SubQAssign); - return Left = Left - Right; -} - -COVERAGE(MulV2Assign, 1) -static inline Vec2 &operator*=(Vec2 &Left, Vec2 Right) -{ - ASSERT_COVERED(MulV2Assign); - return Left = Left * Right; -} - -COVERAGE(MulV3Assign, 1) -static inline Vec3 &operator*=(Vec3 &Left, Vec3 Right) -{ - ASSERT_COVERED(MulV3Assign); - return Left = Left * Right; -} - -COVERAGE(MulV4Assign, 1) -static inline Vec4 &operator*=(Vec4 &Left, Vec4 Right) -{ - ASSERT_COVERED(MulV4Assign); - return Left = Left * Right; -} - -COVERAGE(MulV2FAssign, 1) -static inline Vec2 &operator*=(Vec2 &Left, float Right) -{ - ASSERT_COVERED(MulV2FAssign); - return Left = Left * Right; -} - -COVERAGE(MulV3FAssign, 1) -static inline Vec3 &operator*=(Vec3 &Left, float Right) -{ - ASSERT_COVERED(MulV3FAssign); - return Left = Left * Right; -} - -COVERAGE(MulV4FAssign, 1) -static inline Vec4 &operator*=(Vec4 &Left, float Right) -{ - ASSERT_COVERED(MulV4FAssign); - return Left = Left * Right; -} - -COVERAGE(MulM2FAssign, 1) -static inline Mat2 &operator*=(Mat2 &Left, float Right) -{ - ASSERT_COVERED(MulM2FAssign); - return Left = Left * Right; -} - -COVERAGE(MulM3FAssign, 1) -static inline Mat3 &operator*=(Mat3 &Left, float Right) -{ - ASSERT_COVERED(MulM3FAssign); - return Left = Left * Right; -} - -COVERAGE(MulM4FAssign, 1) -static inline Mat4 &operator*=(Mat4 &Left, float Right) -{ - ASSERT_COVERED(MulM4FAssign); - return Left = Left * Right; -} - -COVERAGE(MulQFAssign, 1) -static inline Quat &operator*=(Quat &Left, float Right) -{ - ASSERT_COVERED(MulQFAssign); - return Left = Left * Right; -} - -COVERAGE(DivV2Assign, 1) -static inline Vec2 &operator/=(Vec2 &Left, Vec2 Right) -{ - ASSERT_COVERED(DivV2Assign); - return Left = Left / Right; -} - -COVERAGE(DivV3Assign, 1) -static inline Vec3 &operator/=(Vec3 &Left, Vec3 Right) -{ - ASSERT_COVERED(DivV3Assign); - return Left = Left / Right; -} - -COVERAGE(DivV4Assign, 1) -static inline Vec4 &operator/=(Vec4 &Left, Vec4 Right) -{ - ASSERT_COVERED(DivV4Assign); - return Left = Left / Right; -} - -COVERAGE(DivV2FAssign, 1) -static inline Vec2 &operator/=(Vec2 &Left, float Right) -{ - ASSERT_COVERED(DivV2FAssign); - return Left = Left / Right; -} - -COVERAGE(DivV3FAssign, 1) -static inline Vec3 &operator/=(Vec3 &Left, float Right) -{ - ASSERT_COVERED(DivV3FAssign); - return Left = Left / Right; -} - -COVERAGE(DivV4FAssign, 1) -static inline Vec4 &operator/=(Vec4 &Left, float Right) -{ - ASSERT_COVERED(DivV4FAssign); - return Left = Left / Right; -} - -COVERAGE(DivM4FAssign, 1) -static inline Mat4 &operator/=(Mat4 &Left, float Right) -{ - ASSERT_COVERED(DivM4FAssign); - return Left = Left / Right; -} - -COVERAGE(DivQFAssign, 1) -static inline Quat &operator/=(Quat &Left, float Right) -{ - ASSERT_COVERED(DivQFAssign); - return Left = Left / Right; -} - -COVERAGE(EqV2Op, 1) -static inline Bool operator==(Vec2 Left, Vec2 Right) -{ - ASSERT_COVERED(EqV2Op); - return EqV2(Left, Right); -} - -COVERAGE(EqV3Op, 1) -static inline Bool operator==(Vec3 Left, Vec3 Right) -{ - ASSERT_COVERED(EqV3Op); - return EqV3(Left, Right); -} - -COVERAGE(EqV4Op, 1) -static inline Bool operator==(Vec4 Left, Vec4 Right) -{ - ASSERT_COVERED(EqV4Op); - return EqV4(Left, Right); -} - -COVERAGE(EqV2OpNot, 1) -static inline Bool operator!=(Vec2 Left, Vec2 Right) -{ - ASSERT_COVERED(EqV2OpNot); - return !EqV2(Left, Right); -} - -COVERAGE(EqV3OpNot, 1) -static inline Bool operator!=(Vec3 Left, Vec3 Right) -{ - ASSERT_COVERED(EqV3OpNot); - return !EqV3(Left, Right); -} - -COVERAGE(EqV4OpNot, 1) -static inline Bool operator!=(Vec4 Left, Vec4 Right) -{ - ASSERT_COVERED(EqV4OpNot); - return !EqV4(Left, Right); -} - -COVERAGE(UnaryMinusV2, 1) -static inline Vec2 operator-(Vec2 In) -{ - ASSERT_COVERED(UnaryMinusV2); - - Vec2 Result; - Result.X = -In.X; - Result.Y = -In.Y; - - return Result; -} - -COVERAGE(UnaryMinusV3, 1) -static inline Vec3 operator-(Vec3 In) -{ - ASSERT_COVERED(UnaryMinusV3); - - Vec3 Result; - Result.X = -In.X; - Result.Y = -In.Y; - Result.Z = -In.Z; - - return Result; -} - -COVERAGE(UnaryMinusV4, 1) -static inline Vec4 operator-(Vec4 In) -{ - ASSERT_COVERED(UnaryMinusV4); - - Vec4 Result; -#if HANDMADE_MATH__USE_SSE - Result.SSE = _mm_xor_ps(In.SSE, _mm_set1_ps(-0.0f)); -#elif defined(HANDMADE_MATH__USE_NEON) - float32x4_t Zero = vdupq_n_f32(0.0f); - Result.NEON = vsubq_f32(Zero, In.NEON); -#else - Result.X = -In.X; - Result.Y = -In.Y; - Result.Z = -In.Z; - Result.W = -In.W; -#endif - - return Result; -} - -#endif /* __cplusplus*/ - -#ifdef HANDMADE_MATH__USE_C11_GENERICS - -void __invalid_generic(); - -#define Add(A, B) _Generic((A), \ - Vec2: AddV2, \ - Vec3: AddV3, \ - Vec4: AddV4, \ - Mat2: AddM2, \ - Mat3: AddM3, \ - Mat4: AddM4, \ - Quat: AddQ \ -)(A, B) - -#define Sub(A, B) _Generic((A), \ - Vec2: SubV2, \ - Vec3: SubV3, \ - Vec4: SubV4, \ - Mat2: SubM2, \ - Mat3: SubM3, \ - Mat4: SubM4, \ - Quat: SubQ \ -)(A, B) - -#define Mul(A, B) _Generic((B), \ - float: _Generic((A), \ - Vec2: MulV2F, \ - Vec3: MulV3F, \ - Vec4: MulV4F, \ - Mat2: MulM2F, \ - Mat3: MulM3F, \ - Mat4: MulM4F, \ - Quat: MulQF, \ - default: __invalid_generic \ - ), \ - Vec2: _Generic((A), \ - Vec2: MulV2, \ - Mat2: MulM2V2, \ - default: __invalid_generic \ - ), \ - Vec3: _Generic((A), \ - Vec3: MulV3, \ - Mat3: MulM3V3, \ - default: __invalid_generic \ - ), \ - Vec4: _Generic((A), \ - Vec4: MulV4, \ - Mat4: MulM4V4, \ - default: __invalid_generic \ - ), \ - Mat2: MulM2, \ - Mat3: MulM3, \ - Mat4: MulM4, \ - Quat: MulQ \ -)(A, B) - -#define Div(A, B) _Generic((B), \ - float: _Generic((A), \ - Vec2: DivV2F, \ - Vec3: DivV3F, \ - Vec4: DivV4F, \ - Mat2: DivM2F, \ - Mat3: DivM3F, \ - Mat4: DivM4F, \ - Quat: DivQF \ - ), \ - Vec2: DivV2, \ - Vec3: DivV3, \ - Vec4: DivV4 \ -)(A, B) - -#define Len(A) _Generic((A), \ - Vec2: LenV2, \ - Vec3: LenV3, \ - Vec4: LenV4 \ -)(A) - -#define LenSqr(A) _Generic((A), \ - Vec2: LenSqrV2, \ - Vec3: LenSqrV3, \ - Vec4: LenSqrV4 \ -)(A) - -#define Norm(A) _Generic((A), \ - Vec2: NormV2, \ - Vec3: NormV3, \ - Vec4: NormV4, \ - Quat: NormQ \ -)(A) - -#define Dot(A, B) _Generic((A), \ - Vec2: DotV2, \ - Vec3: DotV3, \ - Vec4: DotV4, \ - Quat: DotQ \ -)(A, B) - -#define Lerp(A, T, B) _Generic((A), \ - float: Lerp, \ - Vec2: LerpV2, \ - Vec3: LerpV3, \ - Vec4: LerpV4 \ -)(A, T, B) - -#define Eq(A, B) _Generic((A), \ - Vec2: EqV2, \ - Vec3: EqV3, \ - Vec4: EqV4 \ -)(A, B) - -#define Transpose(M) _Generic((M), \ - Mat2: TransposeM2, \ - Mat3: TransposeM3, \ - Mat4: TransposeM4 \ -)(M) - -#define Determinant(M) _Generic((M), \ - Mat2: DeterminantM2, \ - Mat3: DeterminantM3, \ - Mat4: DeterminantM4 \ -)(M) - -#define InvGeneral(M) _Generic((M), \ - Mat2: InvGeneralM2, \ - Mat3: InvGeneralM3, \ - Mat4: InvGeneralM4 \ -)(M) - -#endif - -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic pop -#endif - -#endif /* HANDMADE_MATH_H */ \ No newline at end of file +typedef struct vec2f { + float x, y; +} vec2f; +typedef struct vec3f { + float x, y, z; +} vec3f; +typedef struct vec4f { + float x, y, z, w; +} vec4f; + +typedef struct vec2u { + uint32_t x, y; +} vec2u; +typedef struct vec3u { + uint32_t x, y, z; +} vec3u; +typedef struct vec4u { + uint32_t x, y, z, w; +} vec4u; + +typedef struct vec2 { + int32_t x, y; +} vec2; +typedef struct vec3 { + int32_t x, y, z; +} vec3; +typedef struct vec4 { + int32_t x, y, z, w; +} vec4; + +typedef struct mat4x4f { + float e[4][4]; +} mat4x4f; +typedef struct mat4x4u { + uint32_t e[4][4]; +} mat4x4u; +typedef union mat4x4 { + int32_t e[4][4]; +} mat4x4; + +#endif \ No newline at end of file diff --git a/src/rand.h b/src/rand.h index 0ab2f70..a48d53f 100644 --- a/src/rand.h +++ b/src/rand.h @@ -1,22 +1,27 @@ -uint32_t seed; +#ifndef RAND_H +#define RAND_H -uint32_t xorshift32(void); -void rand_seed(uint32_t _seed); -uint32_t next_int(void); -uint32_t next_int_max(uint32_t max); -uint32_t next_int_minmax(uint32_t min, uint32_t max); -float next_float(void); -float next_float_max(float_t max); -float next_float_minmax(float_t min, float_t max); +#include "api.h" -uint32_t xorshift32(void) +static uint32_t seed; + +static uint32_t xorshift32(void); +static void rand_seed(uint32_t _seed); +static uint32_t next_int(void); +static uint32_t next_int_max(uint32_t max); +static uint32_t next_int_minmax(uint32_t min, uint32_t max); +static float next_float(void); +static float next_float_max(float max); +static float next_float_minmax(float min, float max); + +static uint32_t xorshift32(void) { seed ^= seed<<13; seed ^= seed>>17; seed ^= seed<<5; return seed; } -void rand_seed(uint32_t _seed) +static void rand_seed(uint32_t _seed) { if(_seed == 0) return; @@ -25,35 +30,37 @@ void rand_seed(uint32_t _seed) xorshift32(); } // PRNG [0-UINT32_MAX] -uint32_t next_int(void) +static uint32_t next_int(void) { return xorshift32(); } // PRNG [0-max] -uint32_t next_int_max(uint32_t max) +static uint32_t next_int_max(uint32_t max) { return (uint32_t) floorf(xorshift32() / (float) UINT32_MAX * max); } // PRNG [min-max] -uint32_t next_int_minmax(uint32_t min, uint32_t max) +static uint32_t next_int_minmax(uint32_t min, uint32_t max) { - const float x = xorshift32() / (float) UINT32_MAX; + const float x = (float) xorshift32() / UINT32_MAX; //(1.0f - Time) * A + Time * B return (1.0f - x) * min + x * max; } // PRNG [0-1] -float next_float(void) +static float next_float(void) { - return xorshift32() / (float) UINT32_MAX; + return (float) xorshift32() / UINT32_MAX; } // PRNG [0-max] -float next_float_max(float_t max) +static float next_float_max(float max) { - return xorshift32() / (float) UINT32_MAX * max; + return (float) xorshift32() / UINT32_MAX * max; } // PRNG [min-max] -float next_float_minmax(float_t min, float_t max) +static float next_float_minmax(float min, float max) { - const float x = xorshift32() / (float) UINT32_MAX; + const float x = (float) xorshift32() / UINT32_MAX; return (1.0f - x) * min + x * max; -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/src/shaders/base.glsl b/src/shaders/base.glsl deleted file mode 100644 index e257d9f..0000000 --- a/src/shaders/base.glsl +++ /dev/null @@ -1,61 +0,0 @@ -@block common -@ctype vec2 position_t; - -struct cell -{ - vec2 pos; -}; -vec3 color(int i) -{ - float r = ((i >> 0) & 0xff)/255.0f; - float g = ((i >> 8) & 0xff)/255.0f; - float b = ((i >> 16) & 0xff)/255.0f; - return vec3(r, g, b); -} -@end - -@vs vs -@include_block common -layout(binding = 0) uniform vs_uniform { - float radius; -}; - -layout(location = 0) in vec2 in_quad; -layout(location = 1) out vec2 _quad; -layout(location = 2) out vec2 _centroid; -layout(location = 3) flat out vec3 _color; - -readonly: layout(binding = 0) readonly buffer vs_ssbo { - cell cells[]; -}; - -void main() -{ - _centroid = cells[gl_InstanceIndex].pos; - _color = color(gl_InstanceIndex); - _quad = radius * in_quad + _centroid; - gl_Position = vec4(_quad, 0.0, 1.0); -} -@end - -@fs fs -@include_block common - -layout(binding = 1) uniform fs_uniform { - float radius; -}; - -layout(location = 0) out vec4 frag_color; -layout(location = 1) in vec2 _quad; -layout(location = 2) in vec2 _centroid; -layout(location = 3) flat in vec3 _color; - -void main() -{ - gl_FragDepth = length(_quad - _centroid); - if(gl_FragDepth > radius) discard; - frag_color = vec4(_color, 1.0); -} -@end - -@program base vs fs \ No newline at end of file diff --git a/src/shaders/sprite.wgsl b/src/shaders/sprite.wgsl index 1f550a9..5d12597 100644 --- a/src/shaders/sprite.wgsl +++ b/src/shaders/sprite.wgsl @@ -1,47 +1,56 @@ -struct Cell { - position: vec2f, +struct Sprite { + matrix: mat4x4f, +}; +struct VsUniform { + mvp: mat4x4f, }; struct VsI { //Vertex shader input @builtin(instance_index) instance: u32, @location(0) position: vec2f, + @location(1) uv: vec2f, }; struct Vs2Fs { //Vertex shader to Fragment shader @builtin(position) pos: vec4f, - @location(0) @interpolate(flat) instance: u32, + @location(0) @interpolate(linear) uv: vec2f, }; struct FsO { //Fragment shader output - @builtin(frag_depth) depth: f32, @location(0) color: vec4f, }; -fn color(i: u32) -> vec3f -{ - let r: f32 = f32(((i >> 0) & 0xff)); - let g: f32 = f32(((i >> 8) & 0xff)); - let b: f32 = f32(((i >> 16) & 0xff)); - return vec3f(r / 255, g / 255, b / 255); -} +@binding(0) @group(0) var vs_uniforms: VsUniform; +@binding(0) @group(1) var tex: texture_2d; +@binding(1) @group(1) var samp: sampler; +@binding(2) @group(1) var sprites: array; -//@binding(0) @group(0) var mvp: mat4x4f; -@binding(0) @group(1) var cells: array; - -@vertex -fn vs_main(input: VsI) -> Vs2Fs { +@vertex fn vs_main(input: VsI) -> Vs2Fs { var output: Vs2Fs; - - output.pos = vec4f(cells[input.instance].position.xy, 0.0, 0.0)/* * mvp*/; - output.instance = input.instance; + + output.pos = vec4f(input.position.x, input.position.y, 0, 0) * sprites[input.instance].matrix * vs_uniforms.mvp; + output.uv = input.uv; return output; } -@fragment -fn fs_main(input: Vs2Fs) -> FsO { +// Convert a 32bit uint color (hex representation) into a normalized vec4f +/*fn convertColor(input: u32) -> vec4f { + let r: f32 = f32(((input >> 0) & 0xff)); + let g: f32 = f32(((input >> 8) & 0xff)); + let b: f32 = f32(((input >> 16) & 0xff)); + let a: f32 = f32(((input >> 24) & 0xff)); + + return vec4f(r / 255, g / 255, b / 255, a / 255); +}*/ +// Get the texture array index from the UV +/*fn indexFromCoord(uv: vec2f, width: u32, height: u32) -> u32 { + let x: u32 = clamp(floor(uv.x * width), 0, width); + let y: u32 = clamp(floor(uv.y * height), 0, height); + return y * width + x; +}*/ + +@fragment fn fs_main(input: Vs2Fs) -> FsO { var output: FsO; - output.depth = 1.0; - output.color = vec4f(1.0, 0.0, 1.0, 1.0); - //output.color = vec4f(color(input.instance), 1.0); + output.color = textureSample(tex, samp, input.uv); return output; } diff --git a/src/sprite.h b/src/sprite.h new file mode 100644 index 0000000..6d39af3 --- /dev/null +++ b/src/sprite.h @@ -0,0 +1,17 @@ +#ifndef SPRITE_H +#define SPRITE_H + +#include "api.h" + +typedef struct texture_t { + uint32_t id; //Texture ID + sg_bindings binding; //Texture bindings (texture, sampler and buffer) + vector_t sprites; + bool dirty; +} texture_t; + +typedef struct sprite_t { + mat4x4f transform; +} sprite_t; + +#endif \ No newline at end of file diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..26c7b93 --- /dev/null +++ b/src/util.h @@ -0,0 +1,236 @@ +#ifndef UTIL_H +#define UTIL_H + +#include "api.h" + +/*typedef struct linked_list_t { + linked_item_t *first, *last; + uint16_t size; +} linked_list_t; + +typedef struct linked_item_t { + linked_item_t *next, *prev; + void *data; +} linked_item_t; + +typedef void (*linked_list_callback)(void *item); + +//Currently, these are the only method required. +//Many more could be implemented but this is unnecessary. +static void l_list_push(linked_list_t *l_list, void *item); +static void l_list_append(linked_list_t *l_list, void *item); +static void* l_list_pop(linked_list_t *l_list); +static void* l_list_unppend(linked_list_t *l_list); +static void l_list_each(linked_list_t *l_list, linked_list_callback callback); + +static inline void l_list_push(linked_list_t *l_list, void *item) +{ + linked_item_t l_item = (linked_item_t) { .data = item, .prev = l_list->last, .next = nullptr }; + + if(l_list->first == nullptr) + l_list->first = &l_item; + + l_list->last->next = &l_item; + l_list->last = &l_item; + l_list->size++; +} +static inline void l_list_append(linked_list_t *l_list, void *item) +{ + linked_item_t l_item = (linked_item_t) { .data = item, .prev = nullptr, .next = l_list->last }; + + if(l_list->last == nullptr) + l_list->last = &l_item; + + l_list->first->prev = &l_item; + l_list->first = &l_item; + l_list->size++; +} +static inline void* l_list_pop(linked_list_t *l_list) +{ + if(l_list->last == nullptr) + return; + + if(l_list->first == l_list->last) + l_list->first = nullptr; + + linked_item_t *item = l_list->last->prev; + l_list->last->prev = nullptr; + l_list->last = item; + l_list->size--; +} +static inline void* l_list_unppend(linked_list_t *l_list) +{ + if(l_list->first == nullptr) + return; + + if(l_list->last == l_list->first) + l_list->last = nullptr; + + linked_item_t *item = l_list->first->next; + l_list->first->next = nullptr; + l_list->first = item; + l_list->size--; +} +static inline void l_list_each(linked_list_t *l_list, linked_list_callback callback) +{ + +}*/ + +typedef struct vector_t { + void **data; //Memory pool + uint16_t stripe; //Bit per item + uint32_t size; //Current amount of items + uint32_t capacity; //Max capacity +} vector_t; + +#define MAX_BUCKET_SIZE (0xffffffffu) +#define MAX_STRIPE_SIZE (0xffffu) +#define FIXED_START (0xfffu) + +static vector_t vector_create(uint16_t stripe); //Create a new vector with a default size +static void vector_clear(vector_t *vector); +static void vector_free(vector_t *vector); + +static uint32_t vector_length(vector_t *vector); +static void* vector_get(vector_t *vector, uint32_t index); +static void vector_set(vector_t *vector, uint32_t index, void *data); +static uint32_t vector_push(vector_t *vector, void *data); +static sg_range vector_range(vector_t *vector); + +static vector_t vector_create(uint16_t stripe) +{ + assert(stripe >= sizeof(uint32_t)); + assert(stripe <= MAX_STRIPE_SIZE); + assert(FIXED_START * stripe <= MAX_BUCKET_SIZE); + + return (vector_t) { + .capacity = FIXED_START, + .size = 0, + .stripe = stripe, + .data = (void**) malloc(FIXED_START * stripe), + }; +} +static void vector_clear(vector_t *vector) +{ + vector->size = 0; +} +static void vector_free(vector_t *vector) +{ + free(vector->data); +} + +static uint32_t vector_length(vector_t *vector) +{ + return vector->size; +} +static void* vector_get(vector_t *vector, uint32_t index) +{ + assert(index > 0); + assert(index < vector->size); + + return vector->data[index * vector->stripe]; +} +static void vector_set(vector_t *vector, uint32_t index, void *data) +{ + assert(index > 0); + assert(index < vector->size); + + vector->data[index * vector->stripe] = data; +} +static uint32_t vector_push(vector_t *vector, void *data) +{ + if(vector->size >= vector->capacity) + { + vector->capacity *= 2; + + vector->data = (void**) realloc(vector->data, vector->capacity * vector->stripe); + } + + return vector->size++; +} +static sg_range vector_range(vector_t *vector) +{ + return (sg_range) { + .ptr = vector->data, + .size = vector->size, + }; +} + +typedef struct mem_pool_t { + void **data; //Memory pool + uint16_t stripe; //Bit per item + uint32_t size; //Current amount of items + uint32_t capacity; //Max capacity + uint32_t free; //Linked list of available indices +} mem_pool_t; + +static mem_pool_t pool_create(uint16_t stripe); //Create a new memory pool with a default size +static void pool_clear(mem_pool_t *pool); +static void pool_free(mem_pool_t *pool); + +static uint32_t pool_add(mem_pool_t *pool); //Request a new free index +static void* pool_get(mem_pool_t *pool, uint32_t index); //Get the pointer +static void pool_remove(mem_pool_t *pool, uint32_t index); //Flag the given index as free + +static mem_pool_t pool_create(uint16_t stripe) +{ + assert(stripe >= sizeof(uint32_t)); + assert(stripe <= MAX_STRIPE_SIZE); + assert(FIXED_START * stripe <= MAX_BUCKET_SIZE); + + return (mem_pool_t) { + .capacity = FIXED_START, + .size = 0, + .stripe = stripe, + .free = UINT32_MAX, + .data = (void**) malloc(FIXED_START * stripe), + }; +} +static void pool_clear(mem_pool_t *pool) +{ + pool->size = 0; + pool->free = UINT32_MAX; +} +static void pool_free(mem_pool_t *pool) +{ + free(pool->data); +} + +static uint32_t pool_add(mem_pool_t *pool) +{ + if(pool->free != UINT32_MAX) + { + const uint32_t index = pool->free; + + pool->free = (uint32_t) pool->data[index * pool->stripe]; + + return index; + } + else + { + if(pool->size >= pool->capacity) + { + pool->capacity *= 2; + + pool->data = (void**) realloc(pool->data, pool->capacity * pool->stripe); + } + + return pool->size++; + } +} +static void* pool_get(mem_pool_t *pool, uint32_t index) +{ + assert(index > 0); + assert(index < pool->capacity); + + return pool->data[index * pool->stripe]; +} +static void pool_remove(mem_pool_t *pool, uint32_t index) +{ + const uint32_t pos = index * pool->stripe; + + pool->data[pos] = (void*) pool->free; + pool->free = index; +} + +#endif \ No newline at end of file