wasm: support more vendor libraries

Adds support for:
- box2d
- cgltf
- stb image
- stb rect pack
This commit is contained in:
Laytan Laats
2024-09-09 18:49:13 +02:00
parent d783bca297
commit 5ae27c6ebc
45 changed files with 2828 additions and 231 deletions
+44 -13
View File
@@ -7,6 +7,7 @@ LIB :: (
"../lib/stb_image.lib" when ODIN_OS == .Windows
else "../lib/stb_image.a" when ODIN_OS == .Linux
else "../lib/darwin/stb_image.a" when ODIN_OS == .Darwin
else "../lib/stb_image_wasm.o" when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32
else ""
)
@@ -15,12 +16,19 @@ when LIB != "" {
// The STB libraries are shipped with the compiler on Windows so a Windows specific message should not be needed.
#panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`")
}
}
when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
foreign import stbi "../lib/stb_image_wasm.o"
foreign import stbi { LIB }
} else when LIB != "" {
foreign import stbi { LIB }
} else {
foreign import stbi "system:stb_image"
}
NO_STDIO :: ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32
#assert(size_of(c.int) == size_of(b32))
#assert(size_of(b32) == size_of(c.int))
@@ -33,14 +41,48 @@ Io_Callbacks :: struct {
eof: proc "c" (user: rawptr) -> c.int, // returns nonzero if we are at end of file/data
}
when !NO_STDIO {
@(default_calling_convention="c", link_prefix="stbi_")
foreign stbi {
////////////////////////////////////
//
// 8-bits-per-channel interface
//
load :: proc(filename: cstring, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]byte ---
load_from_file :: proc(f: ^c.FILE, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]byte ---
////////////////////////////////////
//
// 16-bits-per-channel interface
//
load_16 :: proc(filename: cstring, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]u16 ---
load_16_from_file :: proc(f: ^c.FILE, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]u16 ---
////////////////////////////////////
//
// float-per-channel interface
//
loadf :: proc(filename: cstring, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]f32 ---
loadf_from_file :: proc(f: ^c.FILE, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]f32 ---
is_hdr :: proc(filename: cstring) -> c.int ---
is_hdr_from_file :: proc(f: ^c.FILE) -> c.int ---
// get image dimensions & components without fully decoding
info :: proc(filename: cstring, x, y, comp: ^c.int) -> c.int ---
info_from_file :: proc(f: ^c.FILE, x, y, comp: ^c.int) -> c.int ---
is_16_bit :: proc(filename: cstring) -> b32 ---
is_16_bit_from_file :: proc(f: ^c.FILE) -> b32 ---
}
}
@(default_calling_convention="c", link_prefix="stbi_")
foreign stbi {
////////////////////////////////////
//
// 8-bits-per-channel interface
//
load :: proc(filename: cstring, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]byte ---
load_from_file :: proc(f: ^c.FILE, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]byte ---
load_from_memory :: proc(buffer: [^]byte, len: c.int, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]byte ---
load_from_callbacks :: proc(clbk: ^Io_Callbacks, user: rawptr, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]byte ---
@@ -50,8 +92,6 @@ foreign stbi {
//
// 16-bits-per-channel interface
//
load_16 :: proc(filename: cstring, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]u16 ---
load_16_from_file :: proc(f: ^c.FILE, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]u16 ---
load_16_from_memory :: proc(buffer: [^]byte, len: c.int, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]u16 ---
load_16_from_callbacks :: proc(clbk: ^Io_Callbacks, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]u16 ---
@@ -59,8 +99,6 @@ foreign stbi {
//
// float-per-channel interface
//
loadf :: proc(filename: cstring, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]f32 ---
loadf_from_file :: proc(f: ^c.FILE, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]f32 ---
loadf_from_memory :: proc(buffer: [^]byte, len: c.int, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]f32 ---
loadf_from_callbacks :: proc(clbk: ^Io_Callbacks, user: rawptr, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]f32 ---
@@ -73,9 +111,6 @@ foreign stbi {
is_hdr_from_callbacks :: proc(clbk: ^Io_Callbacks, user: rawptr) -> c.int ---
is_hdr_from_memory :: proc(buffer: [^]byte, len: c.int) -> c.int ---
is_hdr :: proc(filename: cstring) -> c.int ---
is_hdr_from_file :: proc(f: ^c.FILE) -> c.int ---
// get a VERY brief reason for failure
// NOT THREADSAFE
failure_reason :: proc() -> cstring ---
@@ -84,13 +119,9 @@ foreign stbi {
image_free :: proc(retval_from_load: rawptr) ---
// get image dimensions & components without fully decoding
info :: proc(filename: cstring, x, y, comp: ^c.int) -> c.int ---
info_from_file :: proc(f: ^c.FILE, x, y, comp: ^c.int) -> c.int ---
info_from_memory :: proc(buffer: [^]byte, len: c.int, x, y, comp: ^c.int) -> c.int ---
info_from_callbacks :: proc(clbk: ^Io_Callbacks, user: rawptr, x, y, comp: ^c.int) -> c.int ---
is_16_bit :: proc(filename: cstring) -> b32 ---
is_16_bit_from_file :: proc(f: ^c.FILE) -> b32 ---
is_16_bit_from_memory :: proc(buffer: [^]byte, len: c.int) -> c.int ---
// for image formats that explicitly notate that they have premultiplied alpha,
+5
View File
@@ -7,6 +7,7 @@ RESIZE_LIB :: (
"../lib/stb_image_resize.lib" when ODIN_OS == .Windows
else "../lib/stb_image_resize.a" when ODIN_OS == .Linux
else "../lib/darwin/stb_image_resize.a" when ODIN_OS == .Darwin
else "../lib/stb_image_resize_wasm.o" when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32
else ""
)
@@ -15,7 +16,11 @@ when RESIZE_LIB != "" {
// The STB libraries are shipped with the compiler on Windows so a Windows specific message should not be needed.
#panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`")
}
}
when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
foreign import lib "../lib/stb_image_resize_wasm.o"
} else when RESIZE_LIB != "" {
foreign import lib { RESIZE_LIB }
} else {
foreign import lib "system:stb_image_resize"
+4
View File
@@ -0,0 +1,4 @@
//+build wasm32, wasm64p32
package stb_image
@(require) import _ "vendor:libc"
+16 -6
View File
@@ -7,6 +7,7 @@ WRITE_LIB :: (
"../lib/stb_image_write.lib" when ODIN_OS == .Windows
else "../lib/stb_image_write.a" when ODIN_OS == .Linux
else "../lib/darwin/stb_image_write.a" when ODIN_OS == .Darwin
else "../lib/stb_image_write_wasm.o" when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32
else ""
)
@@ -15,7 +16,11 @@ when WRITE_LIB != "" {
// The STB libraries are shipped with the compiler on Windows so a Windows specific message should not be needed.
#panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`")
}
}
when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
foreign import stbiw "../lib/stb_image_write_wasm.o"
} else when WRITE_LIB != "" {
foreign import stbiw { WRITE_LIB }
} else {
foreign import stbiw "system:stb_image_write"
@@ -25,12 +30,6 @@ write_func :: proc "c" (ctx: rawptr, data: rawptr, size: c.int)
@(default_calling_convention="c", link_prefix="stbi_")
foreign stbiw {
write_png :: proc(filename: cstring, w, h, comp: c.int, data: rawptr, stride_in_bytes: c.int) -> c.int ---
write_bmp :: proc(filename: cstring, w, h, comp: c.int, data: rawptr) -> c.int ---
write_tga :: proc(filename: cstring, w, h, comp: c.int, data: rawptr) -> c.int ---
write_hdr :: proc(filename: cstring, w, h, comp: c.int, data: [^]f32) -> c.int ---
write_jpg :: proc(filename: cstring, w, h, comp: c.int, data: rawptr, quality: c.int /*0..=100*/) -> c.int ---
write_png_to_func :: proc(func: write_func, ctx: rawptr, w, h, comp: c.int, data: rawptr, stride_in_bytes: c.int) -> c.int ---
write_bmp_to_func :: proc(func: write_func, ctx: rawptr, w, h, comp: c.int, data: rawptr) -> c.int ---
write_tga_to_func :: proc(func: write_func, ctx: rawptr, w, h, comp: c.int, data: rawptr) -> c.int ---
@@ -39,3 +38,14 @@ foreign stbiw {
flip_vertically_on_write :: proc(flip_boolean: b32) ---
}
when !NO_STDIO {
@(default_calling_convention="c", link_prefix="stbi_")
foreign stbiw {
write_png :: proc(filename: cstring, w, h, comp: c.int, data: rawptr, stride_in_bytes: c.int) -> c.int ---
write_bmp :: proc(filename: cstring, w, h, comp: c.int, data: rawptr) -> c.int ---
write_tga :: proc(filename: cstring, w, h, comp: c.int, data: rawptr) -> c.int ---
write_hdr :: proc(filename: cstring, w, h, comp: c.int, data: [^]f32) -> c.int ---
write_jpg :: proc(filename: cstring, w, h, comp: c.int, data: rawptr, quality: c.int /*0..=100*/) -> c.int ---
}
}
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+5
View File
@@ -9,6 +9,7 @@ LIB :: (
"../lib/stb_rect_pack.lib" when ODIN_OS == .Windows
else "../lib/stb_rect_pack.a" when ODIN_OS == .Linux
else "../lib/darwin/stb_rect_pack.a" when ODIN_OS == .Darwin
else "../lib/stb_rect_pack_wasm.o" when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32
else ""
)
@@ -16,7 +17,11 @@ when LIB != "" {
when !#exists(LIB) {
#panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`")
}
}
when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
foreign import lib "../lib/stb_rect_pack_wasm.o"
} else when LIB != "" {
foreign import lib { LIB }
} else {
foreign import lib "system:stb_rect_pack"
+4
View File
@@ -0,0 +1,4 @@
//+build wasm32, wasm64p32
package stb_rect_pack
@(require) import _ "vendor:libc"
+37
View File
@@ -0,0 +1,37 @@
package stb_sprintf
import "core:c"
@(private)
LIB :: (
"../lib/stb_sprintf.lib" when ODIN_OS == .Windows
else "../lib/stb_sprintf.a" when ODIN_OS == .Linux
else "../lib/darwin/stb_sprintf.a" when ODIN_OS == .Darwin
else "../lib/stb_sprintf_wasm.o" when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32
else ""
)
when LIB != "" {
when !#exists(LIB) {
#panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`")
}
}
when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
foreign import stbpf "../lib/stb_sprintf_wasm.o"
} else when LIB != "" {
foreign import stbpf { LIB }
} else {
foreign import stbpf "system:stb_sprintf"
}
@(link_prefix="stbsp_", default_calling_convention="c")
foreign stbpf {
sprintf :: proc(buf: [^]byte, fmt: cstring, #c_vararg args: ..any) -> i32 ---
snprintf :: proc(buf: [^]byte, count: i32, fmt: cstring, #c_vararg args: ..any) -> i32 ---
vsprintf :: proc(buf: [^]byte, fmt: cstring, va: c.va_list) -> i32 ---
vsnprintf :: proc(buf: [^]byte, count: i32, fmt: cstring, va: ^c.va_list) -> i32 ---
vsprintfcb :: proc(callback: SPRINTFCB, user: rawptr, buf: [^]byte, fmt: cstring, va: ^c.va_list) -> i32 ---
}
SPRINTFCB :: #type proc "c" (buf: [^]byte, user: rawptr, len: i32) -> cstring
+12 -2
View File
@@ -8,17 +8,24 @@ endif
wasm:
mkdir -p ../lib
$(CC) -c -Os --target=wasm32 -nostdlib stb_truetype_wasm.c -o ../lib/stb_truetype_wasm.o
$(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_image.c -o ../lib/stb_image_wasm.o -DSTBI_NO_STDIO
$(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_image_write.c -o ../lib/stb_image_write_wasm.o -DSTBI_WRITE_NO_STDIO
$(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_image_resize.c -o ../lib/stb_image_resize_wasm.o
$(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_truetype.c -o ../lib/stb_truetype_wasm.o
# $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_vorbis.c -o ../lib/stb_vorbis_wasm.o -DSTB_VORBIS_NO_STDIO
$(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_rect_pack.c -o ../lib/stb_rect_pack_wasm.o
$(CC) -c -Os --target=wasm32 stb_sprintf.c -o ../lib/stb_sprintf_wasm.o
unix:
mkdir -p ../lib
$(CC) -c -O2 -Os -fPIC stb_image.c stb_image_write.c stb_image_resize.c stb_truetype.c stb_rect_pack.c stb_vorbis.c
$(CC) -c -O2 -Os -fPIC stb_image.c stb_image_write.c stb_image_resize.c stb_truetype.c stb_rect_pack.c stb_vorbis.c stb_sprintf.c
$(AR) rcs ../lib/stb_image.a stb_image.o
$(AR) rcs ../lib/stb_image_write.a stb_image_write.o
$(AR) rcs ../lib/stb_image_resize.a stb_image_resize.o
$(AR) rcs ../lib/stb_truetype.a stb_truetype.o
$(AR) rcs ../lib/stb_rect_pack.a stb_rect_pack.o
$(AR) rcs ../lib/stb_vorbis.a stb_vorbis.o
$(AR) rcs ../lib/stb_sprintf.a stb_sprintf.o
#$(CC) -fPIC -shared -Wl,-soname=stb_image.so -o ../lib/stb_image.so stb_image.o
#$(CC) -fPIC -shared -Wl,-soname=stb_image_write.so -o ../lib/stb_image_write.so stb_image_write.o
#$(CC) -fPIC -shared -Wl,-soname=stb_image_resize.so -o ../lib/stb_image_resize.so stb_image_resize.o
@@ -47,4 +54,7 @@ darwin:
$(CC) -arch x86_64 -c -O2 -Os -fPIC stb_vorbis.c -o stb_vorbis-x86_64.o -mmacosx-version-min=10.12
$(CC) -arch arm64 -c -O2 -Os -fPIC stb_vorbis.c -o stb_vorbis-arm64.o -mmacosx-version-min=10.12
lipo -create stb_vorbis-x86_64.o stb_vorbis-arm64.o -output ../lib/darwin/stb_vorbis.a
$(CC) -arch x86_64 -c -O2 -Os -fPIC stb_sprintf.c -o stb_sprintf-x86_64.o -mmacosx-version-min=10.12
$(CC) -arch arm64 -c -O2 -Os -fPIC stb_sprintf.c -o stb_sprintf-arm64.o -mmacosx-version-min=10.12
lipo -create stb_sprintf-x86_64.o stb_sprintf-arm64.o -output ../lib/darwin/stb_sprintf.a
rm *.o
+2
View File
@@ -0,0 +1,2 @@
#define STB_SPRINTF_IMPLEMENTATION
#include "stb_sprintf.h"
+1906
View File
File diff suppressed because it is too large Load Diff
-46
View File
@@ -1,46 +0,0 @@
#include <stddef.h>
void *stbtt_malloc(size_t size);
void stbtt_free(void *ptr);
void stbtt_qsort(void* base, size_t num, size_t size, int (*compare)(const void*, const void*));
double stbtt_floor(double x);
double stbtt_ceil(double x);
double stbtt_sqrt(double x);
double stbtt_pow(double x, double y);
double stbtt_fmod(double x, double y);
double stbtt_cos(double x);
double stbtt_acos(double x);
double stbtt_fabs(double x);
unsigned long stbtt_strlen(const char *str);
void *memcpy(void *dst, const void *src, size_t count);
void *memset(void *dst, int x, size_t count);
#define STBRP_SORT stbtt_qsort
#define STBRP_ASSERT(condition) ((void)0)
#define STBTT_malloc(x,u) ((void)(u),stbtt_malloc(x))
#define STBTT_free(x,u) ((void)(u),stbtt_free(x))
#define STBTT_assert(condition) ((void)0)
#define STBTT_ifloor(x) ((int) stbtt_floor(x))
#define STBTT_iceil(x) ((int) stbtt_ceil(x))
#define STBTT_sqrt(x) stbtt_sqrt(x)
#define STBTT_pow(x,y) stbtt_pow(x,y)
#define STBTT_fmod(x,y) stbtt_fmod(x,y)
#define STBTT_cos(x) stbtt_cos(x)
#define STBTT_acos(x) stbtt_acos(x)
#define STBTT_fabs(x) stbtt_fabs(x)
#define STBTT_strlen(x) stbtt_strlen(x)
#define STBTT_memcpy memcpy
#define STBTT_memset memset
#define STB_RECT_PACK_IMPLEMENTATION
#include "stb_rect_pack.h"
#define STB_TRUETYPE_IMPLEMENTATION
#include "stb_truetype.h"
+5 -2
View File
@@ -8,6 +8,7 @@ LIB :: (
"../lib/stb_truetype.lib" when ODIN_OS == .Windows
else "../lib/stb_truetype.a" when ODIN_OS == .Linux
else "../lib/darwin/stb_truetype.a" when ODIN_OS == .Darwin
else "../lib/stb_truetype_wasm.o" when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32
else ""
)
@@ -15,10 +16,12 @@ when LIB != "" {
when !#exists(LIB) {
#panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`")
}
}
foreign import stbtt { LIB }
} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
foreign import stbtt "../lib/stb_truetype_wasm.o"
} else when LIB != "" {
foreign import stbtt { LIB }
} else {
foreign import stbtt "system:stb_truetype"
}
+1 -79
View File
@@ -1,82 +1,4 @@
//+build wasm32, wasm64p32
package stb_truetype
import "base:builtin"
import "base:intrinsics"
import "base:runtime"
import "core:c"
import "core:math"
import "core:slice"
import "core:sort"
@(require, linkage="strong", link_name="stbtt_malloc")
malloc :: proc "c" (size: uint) -> rawptr {
context = runtime.default_context()
ptr, _ := runtime.mem_alloc_non_zeroed(int(size))
return raw_data(ptr)
}
@(require, linkage="strong", link_name="stbtt_free")
free :: proc "c" (ptr: rawptr) {
context = runtime.default_context()
builtin.free(ptr)
}
@(require, linkage="strong", link_name="stbtt_qsort")
qsort :: proc "c" (base: rawptr, num: uint, size: uint, cmp: proc "c" (a, b: rawptr) -> i32) {
context = runtime.default_context()
Inputs :: struct {
base: rawptr,
num: uint,
size: uint,
cmp: proc "c" (a, b: rawptr) -> i32,
}
sort.sort({
collection = &Inputs{base, num, size, cmp},
len = proc(it: sort.Interface) -> int {
inputs := (^Inputs)(it.collection)
return int(inputs.num)
},
less = proc(it: sort.Interface, i, j: int) -> bool {
inputs := (^Inputs)(it.collection)
a := rawptr(uintptr(inputs.base) + (uintptr(i) * uintptr(inputs.size)))
b := rawptr(uintptr(inputs.base) + (uintptr(j) * uintptr(inputs.size)))
return inputs.cmp(a, b) < 0
},
swap = proc(it: sort.Interface, i, j: int) {
inputs := (^Inputs)(it.collection)
a := rawptr(uintptr(inputs.base) + (uintptr(i) * uintptr(inputs.size)))
b := rawptr(uintptr(inputs.base) + (uintptr(j) * uintptr(inputs.size)))
slice.ptr_swap_non_overlapping(a, b, int(inputs.size))
},
})
}
@(require, linkage="strong", link_name="stbtt_floor")
floor :: proc "c" (x: f64) -> f64 { return math.floor(x) }
@(require, linkage="strong", link_name="stbtt_ceil")
ceil :: proc "c" (x: f64) -> f64 { return math.ceil(x) }
@(require, linkage="strong", link_name="stbtt_sqrt")
sqrt :: proc "c" (x: f64) -> f64 { return math.sqrt(x) }
@(require, linkage="strong", link_name="stbtt_pow")
pow :: proc "c" (x, y: f64) -> f64 { return math.pow(x, y) }
@(require, linkage="strong", link_name="stbtt_fmod")
fmod :: proc "c" (x, y: f64) -> f64 { return math.mod(x, y) }
@(require, linkage="strong", link_name="stbtt_cos")
cos :: proc "c" (x: f64) -> f64 { return math.cos(x) }
@(require, linkage="strong", link_name="stbtt_acos")
acos :: proc "c" (x: f64) -> f64 { return math.acos(x) }
@(require, linkage="strong", link_name="stbtt_fabs")
fabs :: proc "c" (x: f64) -> f64 { return math.abs(x) }
@(require, linkage="strong", link_name="stbtt_strlen")
strlen :: proc "c" (str: cstring) -> c.ulong { return c.ulong(len(str)) }
// NOTE: defined in runtime.
// void *memcpy(void *dst, const void *src, size_t count);
// void *memset(void *dst, int x, size_t count);
@(require) import _ "vendor:libc"