Merge pull request #4208 from laytan/more-wasm-vendor-support

wasm: support more vendor libraries
This commit is contained in:
gingerBill
2024-09-17 11:37:10 +01:00
committed by GitHub
45 changed files with 2828 additions and 231 deletions

View File

@@ -334,7 +334,7 @@ Inputs:
Returns:
- index: The index of the byte `c`, or -1 if it was not found.
*/
index_byte :: proc(s: []byte, c: byte) -> (index: int) #no_bounds_check {
index_byte :: proc "contextless" (s: []byte, c: byte) -> (index: int) #no_bounds_check {
i, l := 0, len(s)
// Guard against small strings. On modern systems, it is ALWAYS
@@ -469,7 +469,7 @@ Inputs:
Returns:
- index: The index of the byte `c`, or -1 if it was not found.
*/
last_index_byte :: proc(s: []byte, c: byte) -> int #no_bounds_check {
last_index_byte :: proc "contextless" (s: []byte, c: byte) -> int #no_bounds_check {
i := len(s)
// Guard against small strings. On modern systems, it is ALWAYS

View File

@@ -2277,3 +2277,81 @@ buddy_allocator_proc :: proc(
}
return nil, nil
}
// An allocator that keeps track of allocation sizes and passes it along to resizes.
// This is useful if you are using a library that needs an equivalent of `realloc` but want to use
// the Odin allocator interface.
//
// You want to wrap your allocator into this one if you are trying to use any allocator that relies
// on the old size to work.
//
// The overhead of this allocator is an extra max(alignment, size_of(Header)) bytes allocated for each allocation, these bytes are
// used to store the size and original pointer.
Compat_Allocator :: struct {
parent: Allocator,
}
compat_allocator_init :: proc(rra: ^Compat_Allocator, allocator := context.allocator) {
rra.parent = allocator
}
compat_allocator :: proc(rra: ^Compat_Allocator) -> Allocator {
return Allocator{
data = rra,
procedure = compat_allocator_proc,
}
}
compat_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int,
location := #caller_location) -> (data: []byte, err: Allocator_Error) {
size, old_size := size, old_size
Header :: struct {
size: int,
ptr: rawptr,
}
rra := (^Compat_Allocator)(allocator_data)
switch mode {
case .Alloc, .Alloc_Non_Zeroed:
a := max(alignment, size_of(Header))
size += a
assert(size >= 0, "overflow")
allocation := rra.parent.procedure(rra.parent.data, mode, size, alignment, old_memory, old_size, location) or_return
#no_bounds_check data = allocation[a:]
([^]Header)(raw_data(data))[-1] = {
size = size,
ptr = raw_data(allocation),
}
return
case .Free:
header := ([^]Header)(old_memory)[-1]
return rra.parent.procedure(rra.parent.data, mode, size, alignment, header.ptr, header.size, location)
case .Resize, .Resize_Non_Zeroed:
header := ([^]Header)(old_memory)[-1]
a := max(alignment, size_of(header))
size += a
assert(size >= 0, "overflow")
allocation := rra.parent.procedure(rra.parent.data, mode, size, alignment, header.ptr, header.size, location) or_return
#no_bounds_check data = allocation[a:]
([^]Header)(raw_data(data))[-1] = {
size = size,
ptr = raw_data(allocation),
}
return
case .Free_All, .Query_Info, .Query_Features:
return rra.parent.procedure(rra.parent.data, mode, size, alignment, old_memory, old_size, location)
case: unreachable()
}
}

View File

@@ -3,33 +3,38 @@ package os
import "base:runtime"
foreign import "odin_env"
@(require_results)
is_path_separator :: proc(c: byte) -> bool {
return c == '/' || c == '\\'
}
Handle :: distinct u32
stdout: Handle = 1
stderr: Handle = 2
@(require_results)
open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Error) {
unimplemented("core:os procedure not supported on JS target")
}
close :: proc(fd: Handle) -> Error {
unimplemented("core:os procedure not supported on JS target")
return nil
}
flush :: proc(fd: Handle) -> (err: Error) {
unimplemented("core:os procedure not supported on JS target")
return nil
}
write :: proc(fd: Handle, data: []byte) -> (int, Error) {
unimplemented("core:os procedure not supported on JS target")
}
@(private="file")
read_console :: proc(handle: Handle, b: []byte) -> (n: int, err: Error) {
unimplemented("core:os procedure not supported on JS target")
foreign odin_env {
@(link_name="write")
_write :: proc "contextless" (fd: Handle, p: []byte) ---
}
_write(fd, data)
return len(data), nil
}
read :: proc(fd: Handle, data: []byte) -> (int, Error) {
@@ -45,19 +50,6 @@ file_size :: proc(fd: Handle) -> (i64, Error) {
unimplemented("core:os procedure not supported on JS target")
}
@(private)
MAX_RW :: 1<<30
@(private)
pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) {
unimplemented("core:os procedure not supported on JS target")
}
@(private)
pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) {
unimplemented("core:os procedure not supported on JS target")
}
read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
unimplemented("core:os procedure not supported on JS target")
}
@@ -65,16 +57,6 @@ write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error)
unimplemented("core:os procedure not supported on JS target")
}
stdout: Handle = 1
stderr: Handle = 2
@(require_results)
get_std_handle :: proc "contextless" (h: uint) -> Handle {
context = runtime.default_context()
unimplemented("core:os procedure not supported on JS target")
}
@(require_results)
exists :: proc(path: string) -> bool {
unimplemented("core:os procedure not supported on JS target")
@@ -90,9 +72,6 @@ is_dir :: proc(path: string) -> bool {
unimplemented("core:os procedure not supported on JS target")
}
// NOTE(tetra): GetCurrentDirectory is not thread safe with SetCurrentDirectory and GetFullPathName
//@private cwd_lock := win32.SRWLOCK{} // zero is initialized
@(require_results)
get_current_directory :: proc(allocator := context.allocator) -> string {
unimplemented("core:os procedure not supported on JS target")
@@ -118,18 +97,6 @@ remove_directory :: proc(path: string) -> (err: Error) {
}
@(private, require_results)
is_abs :: proc(path: string) -> bool {
unimplemented("core:os procedure not supported on JS target")
}
@(private, require_results)
fix_long_path :: proc(path: string) -> string {
unimplemented("core:os procedure not supported on JS target")
}
link :: proc(old_name, new_name: string) -> (err: Error) {
unimplemented("core:os procedure not supported on JS target")
}
@@ -169,7 +136,6 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
unimplemented("core:os procedure not supported on JS target")
}
Handle :: distinct uintptr
File_Time :: distinct u64
_Platform_Error :: enum i32 {
@@ -254,12 +220,7 @@ WSAECONNRESET :: Platform_Error.WSAECONNRESET
ERROR_FILE_IS_PIPE :: General_Error.File_Is_Pipe
ERROR_FILE_IS_NOT_DIR :: General_Error.Not_Dir
// "Argv" arguments converted to Odin strings
args := _alloc_command_line_arguments()
args: []string
@(require_results)
last_write_time :: proc(fd: Handle) -> (File_Time, Error) {
@@ -279,26 +240,14 @@ get_page_size :: proc() -> int {
@(private, require_results)
_processor_core_count :: proc() -> int {
unimplemented("core:os procedure not supported on JS target")
return 1
}
exit :: proc "contextless" (code: int) -> ! {
context = runtime.default_context()
unimplemented("core:os procedure not supported on JS target")
unimplemented_contextless("core:os procedure not supported on JS target")
}
@(require_results)
current_thread_id :: proc "contextless" () -> int {
context = runtime.default_context()
unimplemented("core:os procedure not supported on JS target")
return 0
}
@(require_results)
_alloc_command_line_arguments :: proc() -> []string {
return nil
}

View File

@@ -93,7 +93,7 @@ Inputs:
Returns:
- res: A string created from the null-terminated byte pointer and length
*/
string_from_null_terminated_ptr :: proc(ptr: [^]byte, len: int) -> (res: string) {
string_from_null_terminated_ptr :: proc "contextless" (ptr: [^]byte, len: int) -> (res: string) {
s := string(ptr[:len])
s = truncate_to_byte(s, 0)
return s
@@ -139,7 +139,7 @@ NOTE: Failure to find the byte results in returning the entire string.
Returns:
- res: The truncated string
*/
truncate_to_byte :: proc(str: string, b: byte) -> (res: string) {
truncate_to_byte :: proc "contextless" (str: string, b: byte) -> (res: string) {
n := index_byte(str, b)
if n < 0 {
n = len(str)
@@ -261,7 +261,7 @@ Inputs:
Returns:
- result: `-1` if `lhs` comes first, `1` if `rhs` comes first, or `0` if they are equal
*/
compare :: proc(lhs, rhs: string) -> (result: int) {
compare :: proc "contextless" (lhs, rhs: string) -> (result: int) {
return mem.compare(transmute([]byte)lhs, transmute([]byte)rhs)
}
/*
@@ -1447,7 +1447,7 @@ Output:
-1
*/
index_byte :: proc(s: string, c: byte) -> (res: int) {
index_byte :: proc "contextless" (s: string, c: byte) -> (res: int) {
return #force_inline bytes.index_byte(transmute([]u8)s, c)
}
/*
@@ -1482,7 +1482,7 @@ Output:
-1
*/
last_index_byte :: proc(s: string, c: byte) -> (res: int) {
last_index_byte :: proc "contextless" (s: string, c: byte) -> (res: int) {
return #force_inline bytes.last_index_byte(transmute([]u8)s, c)
}
/*
@@ -1576,8 +1576,8 @@ Output:
-1
*/
index :: proc(s, substr: string) -> (res: int) {
hash_str_rabin_karp :: proc(s: string) -> (hash: u32 = 0, pow: u32 = 1) {
index :: proc "contextless" (s, substr: string) -> (res: int) {
hash_str_rabin_karp :: proc "contextless" (s: string) -> (hash: u32 = 0, pow: u32 = 1) {
for i := 0; i < len(s); i += 1 {
hash = hash*PRIME_RABIN_KARP + u32(s[i])
}

View File

@@ -3,7 +3,11 @@ package vendor_box2d
import "base:intrinsics"
import "core:c"
@(private) VECTOR_EXT :: "avx2" when #config(VENDOR_BOX2D_ENABLE_AVX2, intrinsics.has_target_feature("avx2")) else "sse2"
when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
@(private) VECTOR_EXT :: "_simd" when #config(VENDOR_BOX2D_ENABLE_SIMD128, intrinsics.has_target_feature("simd128")) else ""
} else {
@(private) VECTOR_EXT :: "avx2" when #config(VENDOR_BOX2D_ENABLE_AVX2, intrinsics.has_target_feature("avx2")) else "sse2"
}
when ODIN_OS == .Windows {
@(private) LIB_PATH :: "lib/box2d_windows_amd64_" + VECTOR_EXT + ".lib"
@@ -13,6 +17,8 @@ when ODIN_OS == .Windows {
@(private) LIB_PATH :: "lib/box2d_darwin_amd64_" + VECTOR_EXT + ".a"
} else when ODIN_ARCH == .amd64 {
@(private) LIB_PATH :: "lib/box2d_other_amd64_" + VECTOR_EXT + ".a"
} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
@(private) LIB_PATH :: "lib/box2d_wasm" + VECTOR_EXT + ".o"
} else {
@(private) LIB_PATH :: "lib/box2d_other.a"
}
@@ -21,8 +27,16 @@ when !#exists(LIB_PATH) {
#panic("Could not find the compiled box2d libraries at \"" + LIB_PATH + "\", they can be compiled by running the `build.sh` script at `" + ODIN_ROOT + "vendor/box2d/build_box2d.sh\"`")
}
foreign import lib {
LIB_PATH,
when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
when VECTOR_EXT == "_simd" {
foreign import lib "lib/box2d_wasm_simd.o"
} else {
foreign import lib "lib/box2d_wasm.o"
}
} else {
foreign import lib {
LIB_PATH,
}
}
@@ -1520,4 +1534,4 @@ IsValid :: proc{
Joint_IsValid,
IsValidRay,
}
}

4
vendor/box2d/box2d_wasm.odin vendored Normal file
View File

@@ -0,0 +1,4 @@
//+build wasm32, wasm64p32
package vendor_box2d
@(require) import _ "vendor:libc"

View File

@@ -68,5 +68,7 @@ esac
cd ..
make -f wasm.Makefile
rm -rf v3.0.0.tar.gz
rm -rf box2d-3.0.0

BIN
vendor/box2d/lib/box2d_wasm.o vendored Executable file

Binary file not shown.

BIN
vendor/box2d/lib/box2d_wasm_simd.o vendored Executable file

Binary file not shown.

32
vendor/box2d/wasm.Makefile vendored Normal file
View File

@@ -0,0 +1,32 @@
# Custom Makefile to build box2d for Odin's WASM targets.
# I tried to make a cmake toolchain file for this / use cmake but this is far easier.
# NOTE: We are pretending to be emscripten to box2d so it takes WASM code paths, but we don't actually use emscripten.
# CC = $(shell brew --prefix llvm)/bin/clang
# LD = $(shell brew --prefix llvm)/bin/wasm-ld
VERSION = 3.0.0
SRCS = $(wildcard box2d-$(VERSION)/src/*.c)
OBJS_SIMD = $(SRCS:.c=_simd.o)
OBJS = $(SRCS:.c=.o)
SYSROOT = $(shell odin root)/vendor/libc
CFLAGS = -Ibox2d-$(VERSION)/include -Ibox2d-$(VERSION)/Extern/simde --target=wasm32 -D__EMSCRIPTEN__ -DNDEBUG -O3 --sysroot=$(SYSROOT)
all: lib/box2d_wasm.o lib/box2d_wasm_simd.o clean
%.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
%_simd.o: %.c
$(CC) -c $(CFLAGS) -msimd128 $< -o $@
lib/box2d_wasm.o: $(OBJS)
$(LD) -r -o lib/box2d_wasm.o $(OBJS)
lib/box2d_wasm_simd.o: $(OBJS_SIMD)
$(LD) -r -o lib/box2d_wasm_simd.o $(OBJS_SIMD)
clean:
rm -rf $(OBJS) $(OBJS_SIMD)
.PHONY: clean

View File

@@ -5,6 +5,7 @@ LIB :: (
"lib/cgltf.lib" when ODIN_OS == .Windows
else "lib/cgltf.a" when ODIN_OS == .Linux
else "lib/darwin/cgltf.a" when ODIN_OS == .Darwin
else "lib/cgltf_wasm.o" when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32
else ""
)
@@ -13,7 +14,11 @@ when LIB != "" {
// Windows library is shipped with the compiler, so a Windows specific message should not be needed.
#panic("Could not find the compiled cgltf library, it can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/cgltf/src\"`")
}
}
when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
foreign import lib "lib/cgltf_wasm.o"
} else when LIB != "" {
foreign import lib { LIB }
} else {
foreign import lib "system:cgltf"

4
vendor/cgltf/cgltf_wasm.odin vendored Normal file
View File

@@ -0,0 +1,4 @@
//+build wasm32, wasm64p32
package cgltf
@(require) import _ "vendor:libc"

BIN
vendor/cgltf/lib/cgltf_wasm.o vendored Normal file

Binary file not shown.

View File

@@ -6,6 +6,10 @@ else
all: unix
endif
wasm:
mkdir -p ../lib
$(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc cgltf.c -o ../lib/cgltf_wasm.o
unix:
mkdir -p ../lib
$(CC) -c -O2 -Os -fPIC cgltf.c

12
vendor/libc/README.md vendored Normal file
View File

@@ -0,0 +1,12 @@
# vendor:libc
A (very small) subset of a libc implementation over Odin libraries.
This is mainly intended for use in Odin WASM builds to allow using libraries like box2d, cgltf etc. without emscripten hacks.
You can use this with clang by doing `clang -c --target=wasm32 --sysroot=$(odin root)/vendor/libc` (+ all other flags and inputs).
This will (if all the libc usage of the library is implemented) spit out a `.o` file you can use with the foreign import system.
If you then also make sure this package is included in the Odin side of the project (`@(require) import "vendor:libc"`) you will be able
compile to WASM like Odin expects.
This is currently used by `vendor:box2d`, `vendor:stb/image`, `vendor:stb/truetype`, `vendor:stb/rect_pack`, and `vendor:cgltf`.
You can see how building works by looking at those.

15
vendor/libc/assert.odin vendored Normal file
View File

@@ -0,0 +1,15 @@
package odin_libc
import "base:runtime"
@(require, linkage="strong", link_name="__odin_libc_assert_fail")
__odin_libc_assert_fail :: proc "c" (func: cstring, file: cstring, line: i32, expr: cstring) -> ! {
context = g_ctx
loc := runtime.Source_Code_Location{
file_path = string(file),
line = line,
column = 0,
procedure = string(func),
}
context.assertion_failure_proc("runtime assertion", string(expr), loc)
}

16
vendor/libc/include/assert.h vendored Normal file
View File

@@ -0,0 +1,16 @@
#ifdef NDEBUG
#define assert(e) ((void)0)
#else
#ifdef __FILE_NAME__
#define __ASSERT_FILE_NAME __FILE_NAME__
#else /* __FILE_NAME__ */
#define __ASSERT_FILE_NAME __FILE__
#endif /* __FILE_NAME__ */
void __odin_libc_assert_fail(const char *, const char *, int, const char *);
#define assert(e) \
(__builtin_expect(!(e), 0) ? __odin_libc_assert_fail(__func__, __ASSERT_FILE_NAME, __LINE__, #e) : (void)0)
#endif /* NDEBUG */

21
vendor/libc/include/math.h vendored Normal file
View File

@@ -0,0 +1,21 @@
#include <stdbool.h>
float sqrtf(float);
float cosf(float);
float sinf(float);
float atan2f(float, float);
bool isnan(float);
bool isinf(float);
double floor(double x);
double ceil(double x);
double sqrt(double x);
double pow(double x, double y);
double fmod(double x, double y);
double cos(double x);
double acos(double x);
double fabs(double x);
int abs(int);
double ldexp(double, int);
double exp(double);
float log(float);
float sin(float);

47
vendor/libc/include/stdio.h vendored Normal file
View File

@@ -0,0 +1,47 @@
#include <stddef.h>
#include <stdarg.h>
#pragma once
typedef struct {} FILE;
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#define stdout ((FILE *)2)
#define stderr ((FILE *)3)
FILE *fopen(const char *, char *);
int fclose(FILE *);
int fseek(FILE *, long, int);
long ftell(FILE *);
size_t fread(void *, size_t, size_t, FILE *);
size_t fwrite(const void *, size_t, size_t, FILE *);
int vfprintf(FILE *, const char *, va_list);
int vsnprintf(char *, size_t, const char *, va_list);
static inline int snprintf(char *buf, size_t size, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
int result = vsnprintf(buf, size, fmt, args);
va_end(args);
return result;
}
static inline int fprintf(FILE *f, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
int result = vfprintf(f, fmt, args);
va_end(args);
return result;
}
static inline int printf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
int result = vfprintf(stdout, fmt, args);
va_end(args);
return result;
}

19
vendor/libc/include/stdlib.h vendored Normal file
View File

@@ -0,0 +1,19 @@
#include <stddef.h>
void *malloc(size_t size);
void *aligned_alloc(size_t alignment, size_t size);
void free(void *);
void *realloc(void *, size_t);
void qsort(void* base, size_t num, size_t size, int (*compare)(const void*, const void*));
int atoi(const char *);
long atol(const char *);
long long atoll(const char *);
double atof(const char *);
long strtol(const char *, char **, int);

21
vendor/libc/include/string.h vendored Normal file
View File

@@ -0,0 +1,21 @@
#include <stddef.h>
void *memcpy(void *, const void *, size_t);
void *memset(void *, int, size_t);
void *memmove(void *, void *, size_t);
int memcmp(const void *, const void *, size_t);
unsigned long strlen(const char *str);
char *strchr(const char *, int);
char *strrchr(const char *, int);
char *strncpy(char *, const char *, size_t);
char *strcpy(char *, const char *);
size_t strcspn(const char *, const char *);
int strcmp(const char *, const char *);
int strncmp(const char *, const char *, size_t);
char *strstr(const char *, const char *);

25
vendor/libc/libc.odin vendored Normal file
View File

@@ -0,0 +1,25 @@
package odin_libc
import "base:runtime"
import "core:mem"
@(private)
g_ctx: runtime.Context
@(private)
g_allocator: mem.Compat_Allocator
@(init)
init_context :: proc() {
g_ctx = context
// Wrapping the allocator with the mem.Compat_Allocator so we can
// mimic the realloc semantics.
mem.compat_allocator_init(&g_allocator, g_ctx.allocator)
g_ctx.allocator = mem.compat_allocator(&g_allocator)
}
// NOTE: the allocator must respect an `old_size` of `-1` on resizes!
set_context :: proc(ctx := context) {
g_ctx = ctx
}

100
vendor/libc/math.odin vendored Normal file
View File

@@ -0,0 +1,100 @@
package odin_libc
import "base:builtin"
import "core:math"
@(require, linkage="strong", link_name="sqrtf")
sqrtf :: proc "c" (v: f32) -> f32 {
return math.sqrt(v)
}
@(require, linkage="strong", link_name="cosf")
cosf :: proc "c" (v: f32) -> f32 {
return math.cos(v)
}
@(require, linkage="strong", link_name="sinf")
sinf :: proc "c" (v: f32) -> f32 {
return math.sin(v)
}
@(require, linkage="strong", link_name="atan2f")
atan2f :: proc "c" (v: f32, v2: f32) -> f32 {
return math.atan2(v, v2)
}
@(require, linkage="strong", link_name="isnan")
isnan :: proc "c" (v: f32) -> bool {
return math.is_nan(v)
}
@(require, linkage="strong", link_name="isinf")
isinf :: proc "c" (v: f32) -> bool {
return math.is_inf(v)
}
@(require, linkage="strong", link_name="sqrt")
sqrt :: proc "c" (x: f64) -> f64 {
return math.sqrt(x)
}
@(require, linkage="strong", link_name="floor")
floor :: proc "c" (x: f64) -> f64 {
return math.floor(x)
}
@(require, linkage="strong", link_name="ceil")
ceil :: proc "c" (x: f64) -> f64 {
return math.ceil(x)
}
@(require, linkage="strong", link_name="pow")
pow :: proc "c" (x, y: f64) -> f64 {
return math.pow(x, y)
}
@(require, linkage="strong", link_name="fmod")
fmod :: proc "c" (x, y: f64) -> f64 {
return math.mod(x, y)
}
@(require, linkage="strong", link_name="cos")
cos :: proc "c" (x: f64) -> f64 {
return math.cos(x)
}
@(require, linkage="strong", link_name="acos")
acos :: proc "c" (x: f64) -> f64 {
return math.acos(x)
}
@(require, linkage="strong", link_name="fabs")
fabs :: proc "c" (x: f64) -> f64 {
return math.abs(x)
}
@(require, linkage="strong", link_name="abs")
abs :: proc "c" (x: i32) -> i32 {
return builtin.abs(x)
}
@(require, linkage="strong", link_name="ldexp")
ldexp :: proc "c" (x: f64, y: i32) -> f64{
return math.ldexp(x, int(y))
}
@(require, linkage="strong", link_name="exp")
exp :: proc "c" (x: f64) -> f64 {
return math.exp(x)
}
@(require, linkage="strong", link_name="log")
log :: proc "c" (x: f32) -> f32 {
return math.ln(x)
}
@(require, linkage="strong", link_name="sin")
sin :: proc "c" (x: f32) -> f32 {
return math.sin(x)
}

106
vendor/libc/stdio.odin vendored Normal file
View File

@@ -0,0 +1,106 @@
package odin_libc
import "core:c"
import "core:io"
import "core:os"
import stb "vendor:stb/sprintf"
FILE :: uintptr
@(require, linkage="strong", link_name="fopen")
fopen :: proc "c" (path: cstring, mode: cstring) -> FILE {
context = g_ctx
unimplemented("odin_libc.fopen")
}
@(require, linkage="strong", link_name="fseek")
fseek :: proc "c" (file: FILE, offset: c.long, whence: i32) -> i32 {
context = g_ctx
handle := os.Handle(file-1)
_, err := os.seek(handle, i64(offset), int(whence))
if err != nil {
return -1
}
return 0
}
@(require, linkage="strong", link_name="ftell")
ftell :: proc "c" (file: FILE) -> c.long {
context = g_ctx
handle := os.Handle(file-1)
off, err := os.seek(handle, 0, os.SEEK_CUR)
if err != nil {
return -1
}
return c.long(off)
}
@(require, linkage="strong", link_name="fclose")
fclose :: proc "c" (file: FILE) -> i32 {
context = g_ctx
handle := os.Handle(file-1)
if os.close(handle) != nil {
return -1
}
return 0
}
@(require, linkage="strong", link_name="fread")
fread :: proc "c" (buffer: [^]byte, size: uint, count: uint, file: FILE) -> uint {
context = g_ctx
handle := os.Handle(file-1)
n, _ := os.read(handle, buffer[:min(size, count)])
return uint(max(0, n))
}
@(require, linkage="strong", link_name="fwrite")
fwrite :: proc "c" (buffer: [^]byte, size: uint, count: uint, file: FILE) -> uint {
context = g_ctx
handle := os.Handle(file-1)
n, _ := os.write(handle, buffer[:min(size, count)])
return uint(max(0, n))
}
@(require, linkage="strong", link_name="vsnprintf")
vsnprintf :: proc "c" (buf: [^]byte, count: uint, fmt: cstring, args: ^c.va_list) -> i32 {
i32_count := i32(count)
assert_contextless(i32_count >= 0)
return stb.vsnprintf(buf, i32_count, fmt, args)
}
@(require, linkage="strong", link_name="vfprintf")
vfprintf :: proc "c" (file: FILE, fmt: cstring, args: ^c.va_list) -> i32 {
context = g_ctx
handle := os.Handle(file-1)
MAX_STACK :: 4096
buf: []byte
stack_buf: [MAX_STACK]byte = ---
{
n := stb.vsnprintf(&stack_buf[0], MAX_STACK, fmt, args)
if n <= 0 {
return n
}
if n >= MAX_STACK {
buf = make([]byte, n)
n2 := stb.vsnprintf(raw_data(buf), i32(len(buf)), fmt, args)
assert(n == n2)
} else {
buf = stack_buf[:n]
}
}
defer if len(buf) > MAX_STACK {
delete(buf)
}
_, err := io.write_full(os.stream_from_handle(handle), buf)
if err != nil {
return -1
}
return i32(len(buf))
}

119
vendor/libc/stdlib.odin vendored Normal file
View File

@@ -0,0 +1,119 @@
package odin_libc
import "base:runtime"
import "core:c"
import "core:slice"
import "core:sort"
import "core:strconv"
import "core:strings"
@(require, linkage="strong", link_name="malloc")
malloc :: proc "c" (size: uint) -> rawptr {
context = g_ctx
ptr, err := runtime.mem_alloc_non_zeroed(int(size))
assert(err == nil, "allocation failure")
return raw_data(ptr)
}
@(require, linkage="strong", link_name="aligned_alloc")
aligned_alloc :: proc "c" (alignment: uint, size: uint) -> rawptr {
context = g_ctx
ptr, err := runtime.mem_alloc_non_zeroed(int(size), int(alignment))
assert(err == nil, "allocation failure")
return raw_data(ptr)
}
@(require, linkage="strong", link_name="free")
free :: proc "c" (ptr: rawptr) {
context = g_ctx
runtime.mem_free(ptr)
}
@(require, linkage="strong", link_name="realloc")
realloc :: proc "c" (ptr: rawptr, new_size: uint) -> rawptr {
context = g_ctx
// -1 for the old_size, assumed to be wrapped with the mem.Compat_Allocator to get the right size.
// Note that realloc does not actually care about alignment and is allowed to just align it to something
// else than the original allocation.
ptr, err := runtime.non_zero_mem_resize(ptr, -1, int(new_size))
assert(err != nil, "realloc failure")
return raw_data(ptr)
}
@(require, linkage="strong", link_name="qsort")
qsort :: proc "c" (base: rawptr, num: uint, size: uint, cmp: proc "c" (a, b: rawptr) -> i32) {
context = g_ctx
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="atoi")
atoi :: proc "c" (str: cstring) -> i32 {
return i32(atoll(str))
}
@(require, linkage="strong", link_name="atol")
atol :: proc "c" (str: cstring) -> c.long {
return c.long(atoll(str))
}
@(require, linkage="strong", link_name="atoll")
atoll :: proc "c" (str: cstring) -> c.longlong {
context = g_ctx
sstr := string(str)
sstr = strings.trim_left_space(sstr)
i, _ := strconv.parse_i64_of_base(sstr, 10)
return c.longlong(i)
}
@(require, linkage="strong", link_name="atof")
atof :: proc "c" (str: cstring) -> f64 {
context = g_ctx
sstr := string(str)
sstr = strings.trim_left_space(sstr)
f, _ := strconv.parse_f64(sstr)
return f
}
@(require, linkage="strong", link_name="strtol")
strtol :: proc "c" (str: cstring, str_end: ^cstring, base: i32) -> c.long {
context = g_ctx
sstr := string(str)
sstr = strings.trim_left_space(sstr)
n: int
i, _ := strconv.parse_i64_of_base(sstr, int(base), &n)
str_end ^= cstring(raw_data(sstr)[n:])
return c.long(clamp(i, i64(min(c.long)), i64(max(c.long))))
}

111
vendor/libc/string.odin vendored Normal file
View File

@@ -0,0 +1,111 @@
package odin_libc
import "base:intrinsics"
import "core:c"
import "core:strings"
import "core:mem"
// NOTE: already defined by Odin.
// void *memcpy(void *, const void *, size_t);
// void *memset(void *, int, size_t);
@(require, linkage="strong", link_name="memcmp")
memcmp :: proc "c" (lhs: [^]byte, rhs: [^]byte, count: uint) -> i32 {
icount := int(count)
assert_contextless(icount >= 0)
return i32(mem.compare(lhs[:icount], rhs[:icount]))
}
@(require, linkage="strong", link_name="strlen")
strlen :: proc "c" (str: cstring) -> c.ulong {
return c.ulong(len(str))
}
@(require, linkage="strong", link_name="strchr")
strchr :: proc "c" (str: cstring, ch: i32) -> cstring {
bch := u8(ch)
sstr := string(str)
if bch == 0 {
return cstring(raw_data(sstr)[len(sstr):])
}
idx := strings.index_byte(sstr, bch)
if idx < 0 {
return nil
}
return cstring(raw_data(sstr)[idx:])
}
@(require, linkage="strong", link_name="strrchr")
strrchr :: proc "c" (str: cstring, ch: i32) -> cstring {
bch := u8(ch)
sstr := string(str)
if bch == 0 {
return cstring(raw_data(sstr)[len(sstr):])
}
idx := strings.last_index_byte(sstr, bch)
if idx < 0 {
return nil
}
return cstring(raw_data(sstr)[idx:])
}
@(require, linkage="strong", link_name="strncpy")
strncpy :: proc "c" (dst: [^]byte, src: cstring, count: uint) -> cstring {
icount := int(count)
assert_contextless(icount >= 0)
cnt := min(len(src), icount)
intrinsics.mem_copy_non_overlapping(dst, rawptr(src), cnt)
intrinsics.mem_zero(dst, icount-cnt)
return cstring(dst)
}
@(require, linkage="strong", link_name="strcpy")
strcpy :: proc "c" (dst: [^]byte, src: cstring) -> cstring {
intrinsics.mem_copy_non_overlapping(dst, rawptr(src), len(src)+1)
return cstring(dst)
}
@(require, linkage="strong", link_name="strcspn")
strcspn :: proc "c" (dst: cstring, src: cstring) -> uint {
context = g_ctx
sdst := string(dst)
idx := strings.index_any(sdst, string(src))
if idx == -1 {
return len(sdst)
}
return uint(idx)
}
@(require, linkage="strong", link_name="strncmp")
strncmp :: proc "c" (lhs: cstring, rhs: cstring, count: uint) -> i32 {
icount := int(count)
assert_contextless(icount >= 0)
lhss := strings.string_from_null_terminated_ptr(([^]byte)(lhs), icount)
rhss := strings.string_from_null_terminated_ptr(([^]byte)(rhs), icount)
return i32(strings.compare(lhss, rhss))
}
@(require, linkage="strong", link_name="strcmp")
strcmp :: proc "c" (lhs: cstring, rhs: cstring) -> i32 {
return i32(strings.compare(string(lhs), string(rhs)))
}
@(require, linkage="strong", link_name="strstr")
strstr :: proc "c" (str: cstring, substr: cstring) -> cstring {
if substr == "" {
return str
}
idx := strings.index(string(str), string(substr))
if idx < 0 {
return nil
}
return cstring(([^]byte)(str)[idx:])
}

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,

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
vendor/stb/image/stb_image_wasm.odin vendored Normal file
View File

@@ -0,0 +1,4 @@
//+build wasm32, wasm64p32
package stb_image
@(require) import _ "vendor:libc"

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 ---
}
}

BIN
vendor/stb/lib/stb_image_resize_wasm.o vendored Normal file

Binary file not shown.

BIN
vendor/stb/lib/stb_image_wasm.o vendored Normal file

Binary file not shown.

BIN
vendor/stb/lib/stb_image_write_wasm.o vendored Normal file

Binary file not shown.

BIN
vendor/stb/lib/stb_rect_pack_wasm.o vendored Normal file

Binary file not shown.

BIN
vendor/stb/lib/stb_sprintf_wasm.o vendored Normal file

Binary file not shown.

Binary file not shown.

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"

View File

@@ -0,0 +1,4 @@
//+build wasm32, wasm64p32
package stb_rect_pack
@(require) import _ "vendor:libc"

37
vendor/stb/sprintf/stb_sprintf.odin vendored Normal file
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

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
vendor/stb/src/stb_sprintf.c vendored Normal file
View File

@@ -0,0 +1,2 @@
#define STB_SPRINTF_IMPLEMENTATION
#include "stb_sprintf.h"

1906
vendor/stb/src/stb_sprintf.h vendored Normal file

File diff suppressed because it is too large Load Diff

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"

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"
}

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"