cleanup
This commit is contained in:
@@ -255,7 +255,6 @@ src += 'qjs_http.c'
|
||||
|
||||
src += [ # engine
|
||||
'qjs_soloud.c',
|
||||
'HandmadeMath.c',
|
||||
]
|
||||
|
||||
src += ['quickjs.c', 'libregexp.c', 'libunicode.c', 'cutils.c', 'dtoa.c']
|
||||
|
||||
491
qopconv.c
491
qopconv.c
@@ -1,491 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2024, Dominic Szablewski - https://phoboslab.org
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
Command line tool to create and unpack qop archives
|
||||
|
||||
*/
|
||||
|
||||
#define _DEFAULT_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define QOP_IMPLEMENTATION
|
||||
#include "qop.h"
|
||||
|
||||
#define MAX_PATH_LEN 1024
|
||||
#define BUFFER_SIZE 4096
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
#define STRINGIFY(x) #x
|
||||
#define TOSTRING(x) STRINGIFY(x)
|
||||
#define die(...) \
|
||||
printf("Abort at " TOSTRING(__FILE__) " line " TOSTRING(__LINE__) ": " __VA_ARGS__); \
|
||||
printf("\n"); \
|
||||
exit(1)
|
||||
|
||||
#define error_if(TEST, ...) \
|
||||
if (TEST) { \
|
||||
die(__VA_ARGS__); \
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Platform specific file/dir handling
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
unsigned char is_dir;
|
||||
unsigned char is_file;
|
||||
} pi_dirent;
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
|
||||
typedef struct {
|
||||
WIN32_FIND_DATA data;
|
||||
pi_dirent current;
|
||||
HANDLE dir;
|
||||
unsigned char is_first;
|
||||
} pi_dir;
|
||||
|
||||
pi_dir *pi_dir_open(const char *path) {
|
||||
char find_str[MAX_PATH_LEN];
|
||||
snprintf(find_str, MAX_PATH_LEN, "%s/*", path);
|
||||
|
||||
pi_dir *d = malloc(sizeof(pi_dir));
|
||||
d->is_first = 1;
|
||||
d->dir = FindFirstFile(find_str, &d->data);
|
||||
if (d->dir == INVALID_HANDLE_VALUE) {
|
||||
free(d);
|
||||
return NULL;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
pi_dirent *pi_dir_next(pi_dir *d) {
|
||||
if (!d->is_first) {
|
||||
if (FindNextFile(d->dir, &d->data) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
d->is_first = 0;
|
||||
d->current.name = d->data.cFileName;
|
||||
d->current.is_dir = d->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
||||
d->current.is_file = !d->current.is_dir;
|
||||
return &d->current;
|
||||
}
|
||||
|
||||
void pi_dir_close(pi_dir *d) {
|
||||
FindClose(d->dir);
|
||||
free(d);
|
||||
}
|
||||
|
||||
int pi_mkdir(char *path, int mode) {
|
||||
UNUSED(mode);
|
||||
return CreateDirectory(path, NULL) ? 0 : -1;
|
||||
}
|
||||
#else
|
||||
#include <dirent.h>
|
||||
|
||||
typedef struct {
|
||||
DIR *dir;
|
||||
struct dirent *data;
|
||||
pi_dirent current;
|
||||
} pi_dir;
|
||||
|
||||
pi_dir *pi_dir_open(const char *path) {
|
||||
DIR *dir = opendir(path);
|
||||
if (!dir) {
|
||||
return NULL;
|
||||
}
|
||||
pi_dir *d = malloc(sizeof(pi_dir));
|
||||
d->dir = dir;
|
||||
return d;
|
||||
}
|
||||
|
||||
pi_dirent *pi_dir_next(pi_dir *d) {
|
||||
d->data = readdir(d->dir);
|
||||
if (!d->data) {
|
||||
return NULL;
|
||||
}
|
||||
d->current.name = d->data->d_name;
|
||||
d->current.is_dir = d->data->d_type & DT_DIR;
|
||||
d->current.is_file = d->data->d_type == DT_REG;
|
||||
return &d->current;
|
||||
}
|
||||
|
||||
void pi_dir_close(pi_dir *d) {
|
||||
closedir(d->dir);
|
||||
free(d);
|
||||
}
|
||||
|
||||
int pi_mkdir(char *path, int mode) {
|
||||
return mkdir(path, mode);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Unpack
|
||||
|
||||
int create_path(const char *path, const mode_t mode) {
|
||||
char tmp[MAX_PATH_LEN];
|
||||
char *p = NULL;
|
||||
struct stat sb;
|
||||
size_t len;
|
||||
|
||||
// copy path
|
||||
len = strnlen(path, MAX_PATH_LEN);
|
||||
if (len == 0 || len == MAX_PATH_LEN) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(tmp, path, len);
|
||||
tmp[len] = '\0';
|
||||
|
||||
// remove file part
|
||||
char *last_slash = strrchr(tmp, '/');
|
||||
if (last_slash == NULL) {
|
||||
return 0;
|
||||
}
|
||||
*last_slash = '\0';
|
||||
|
||||
// check if path exists and is a directory
|
||||
if (stat(tmp, &sb) == 0) {
|
||||
if (S_ISDIR(sb.st_mode)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// recursive mkdir
|
||||
for (p = tmp + 1; *p; p++) {
|
||||
if (*p == '/') {
|
||||
*p = 0;
|
||||
if (stat(tmp, &sb) != 0) {
|
||||
if (pi_mkdir(tmp, mode) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (!S_ISDIR(sb.st_mode)) {
|
||||
return -1;
|
||||
}
|
||||
*p = '/';
|
||||
}
|
||||
}
|
||||
if (stat(tmp, &sb) != 0) {
|
||||
if (pi_mkdir(tmp, mode) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (!S_ISDIR(sb.st_mode)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int copy_out(FILE *src, unsigned int offset, unsigned int size, const char *dest_path) {
|
||||
FILE *dest = fopen(dest_path, "wb");
|
||||
error_if(!dest, "Could not open file %s for writing", dest_path);
|
||||
|
||||
char buffer[BUFFER_SIZE];
|
||||
size_t bytes_read, bytes_written;
|
||||
unsigned int bytes_total = 0;
|
||||
unsigned int read_size = size < BUFFER_SIZE ? size : BUFFER_SIZE;
|
||||
|
||||
fseek(src, offset, SEEK_SET);
|
||||
while (read_size > 0 && (bytes_read = fread(buffer, 1, read_size, src)) > 0) {
|
||||
bytes_written = fwrite(buffer, 1, bytes_read, dest);
|
||||
error_if(bytes_written != bytes_read, "Write error");
|
||||
bytes_total += bytes_written;
|
||||
if (bytes_total >= size) {
|
||||
break;
|
||||
}
|
||||
if (size - bytes_total < read_size) {
|
||||
read_size = size - bytes_total;
|
||||
}
|
||||
}
|
||||
|
||||
error_if(ferror(src), "read error for file %s", dest_path);
|
||||
fclose(dest);
|
||||
return bytes_total;
|
||||
}
|
||||
|
||||
void unpack(const char *archive_path, int list_only) {
|
||||
qop_desc qop;
|
||||
int archive_size = qop_open(archive_path, &qop);
|
||||
error_if(archive_size == 0, "Could not open archive %s", archive_path);
|
||||
|
||||
// Read the archive index
|
||||
int index_len = qop_read_index(&qop, malloc(qop.hashmap_size));
|
||||
error_if(index_len == 0, "Could not read index from archive %s", archive_path);
|
||||
|
||||
// Extract all files
|
||||
for (unsigned int i = 0; i < qop.hashmap_len; i++) {
|
||||
qop_file *file = &qop.hashmap[i];
|
||||
if (file->size == 0) {
|
||||
continue;
|
||||
}
|
||||
error_if(file->path_len >= MAX_PATH_LEN, "Path for file %016llx exceeds %d", file->hash, MAX_PATH_LEN);
|
||||
char path[MAX_PATH_LEN];
|
||||
qop_read_path(&qop, file, path);
|
||||
|
||||
// Integrity check
|
||||
// error_if(!qop_find(&qop, path), "could not find %s", path);
|
||||
|
||||
printf("%6d %016llx %10d %s\n", i, file->hash, file->size, path);
|
||||
|
||||
if (!list_only) {
|
||||
error_if(create_path(path, 0755) != 0, "Could not create path %s", path);
|
||||
copy_out(qop.fh, qop.files_offset + file->offset + file->path_len, file->size, path);
|
||||
}
|
||||
}
|
||||
|
||||
free(qop.hashmap);
|
||||
qop_close(&qop);
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Pack
|
||||
|
||||
typedef struct {
|
||||
qop_file *files;
|
||||
int len;
|
||||
int capacity;
|
||||
int size;
|
||||
char dest_path[MAX_PATH_LEN];
|
||||
} pack_state;
|
||||
|
||||
int canonicalize_path(const char *path, char *buffer, size_t buffer_len) {
|
||||
#if defined(_WIN32)
|
||||
return _fullpath(buffer, path, buffer_len) != NULL;
|
||||
#else
|
||||
UNUSED(buffer_len);
|
||||
return realpath(path, buffer) != NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void write_16(unsigned int v, FILE *fh) {
|
||||
unsigned char b[sizeof(unsigned short)];
|
||||
b[0] = 0xff & (v );
|
||||
b[1] = 0xff & (v >> 8);
|
||||
int written = fwrite(b, sizeof(unsigned short), 1, fh);
|
||||
error_if(!written, "Write error");
|
||||
}
|
||||
|
||||
void write_32(unsigned int v, FILE *fh) {
|
||||
unsigned char b[sizeof(unsigned int)];
|
||||
b[0] = 0xff & (v );
|
||||
b[1] = 0xff & (v >> 8);
|
||||
b[2] = 0xff & (v >> 16);
|
||||
b[3] = 0xff & (v >> 24);
|
||||
int written = fwrite(b, sizeof(unsigned int), 1, fh);
|
||||
error_if(!written, "Write error");
|
||||
}
|
||||
|
||||
void write_64(qop_uint64_t v, FILE *fh) {
|
||||
unsigned char b[sizeof(qop_uint64_t)];
|
||||
b[0] = 0xff & (v );
|
||||
b[1] = 0xff & (v >> 8);
|
||||
b[2] = 0xff & (v >> 16);
|
||||
b[3] = 0xff & (v >> 24);
|
||||
b[4] = 0xff & (v >> 32);
|
||||
b[5] = 0xff & (v >> 40);
|
||||
b[6] = 0xff & (v >> 48);
|
||||
b[7] = 0xff & (v >> 56);
|
||||
int written = fwrite(b, sizeof(qop_uint64_t), 1, fh);
|
||||
error_if(!written, "Write error");
|
||||
}
|
||||
|
||||
unsigned int copy_into(const char *src_path, FILE *dest) {
|
||||
FILE *src = fopen(src_path, "rb");
|
||||
error_if(!src, "Could not open file %s for reading", src_path);
|
||||
|
||||
char buffer[BUFFER_SIZE];
|
||||
size_t bytes_read, bytes_written;
|
||||
unsigned int bytes_total = 0;
|
||||
|
||||
while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, src)) > 0) {
|
||||
bytes_written = fwrite(buffer, 1, bytes_read, dest);
|
||||
error_if(bytes_written != bytes_read, "Write error");
|
||||
bytes_total += bytes_written;
|
||||
}
|
||||
|
||||
error_if(ferror(src), "read error for file %s", src_path);
|
||||
fclose(src);
|
||||
return bytes_total;
|
||||
}
|
||||
|
||||
void add_file(const char *path, FILE *dest, pack_state *state) {
|
||||
if (state->dest_path[0]) {
|
||||
char absolute[MAX_PATH_LEN];
|
||||
if (canonicalize_path(path, absolute, MAX_PATH_LEN) && strcmp(absolute, state->dest_path) == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (state->len >= state->capacity) {
|
||||
state->capacity *= 2;
|
||||
state->files = realloc(state->files, state->capacity * sizeof(qop_file));
|
||||
}
|
||||
|
||||
// Strip leading "./" from path for archive
|
||||
const char *archive_path = path;
|
||||
if (path[0] == '.' && path[1] == '/') {
|
||||
archive_path = path + 2;
|
||||
}
|
||||
|
||||
qop_uint64_t hash = qop_hash(archive_path);
|
||||
|
||||
|
||||
// Write the path into the archive
|
||||
int path_len = strlen(archive_path) + 1;
|
||||
int path_written = fwrite(archive_path, sizeof(char), path_len, dest);
|
||||
error_if(path_written != path_len, "Write error");
|
||||
|
||||
// Copy the file into the archive
|
||||
unsigned int size = copy_into(path, dest);
|
||||
|
||||
printf("%6d %016llx %10d %s\n", state->len, hash, size, archive_path);
|
||||
|
||||
// Collect file info for the index
|
||||
state->files[state->len] = (qop_file){
|
||||
.hash = hash,
|
||||
.offset = state->size,
|
||||
.size = size,
|
||||
.path_len = path_len,
|
||||
.flags = QOP_FLAG_NONE
|
||||
};
|
||||
state->size += size + path_len;
|
||||
state->len++;
|
||||
}
|
||||
|
||||
void add_dir(const char *path, FILE *dest, pack_state *state) {
|
||||
pi_dir *dir = pi_dir_open(path);
|
||||
error_if(!dir, "Could not open directory %s for reading", path);
|
||||
|
||||
pi_dirent *entry;
|
||||
while ((entry = pi_dir_next(dir))) {
|
||||
if (
|
||||
entry->is_dir &&
|
||||
strcmp(entry->name, ".") != 0 &&
|
||||
strcmp(entry->name, "..") != 0
|
||||
) {
|
||||
char subpath[MAX_PATH_LEN];
|
||||
snprintf(subpath, MAX_PATH_LEN, "%s/%s", path, entry->name);
|
||||
add_dir(subpath, dest, state);
|
||||
}
|
||||
else if (entry->is_file) {
|
||||
char subpath[MAX_PATH_LEN];
|
||||
snprintf(subpath, MAX_PATH_LEN, "%s/%s", path, entry->name);
|
||||
add_file(subpath, dest, state);
|
||||
}
|
||||
}
|
||||
pi_dir_close(dir);
|
||||
}
|
||||
|
||||
void pack(const char *read_dir, char **sources, int sources_len, const char *archive_path) {
|
||||
FILE *dest = fopen(archive_path, "wb");
|
||||
error_if(!dest, "Could not open file %s for writing", archive_path);
|
||||
|
||||
pack_state state;
|
||||
state.files = malloc(sizeof(qop_file) * 1024);
|
||||
state.len = 0;
|
||||
state.capacity = 1024;
|
||||
state.size = 0;
|
||||
state.dest_path[0] = '\0';
|
||||
if (!canonicalize_path(archive_path, state.dest_path, MAX_PATH_LEN)) {
|
||||
state.dest_path[0] = '\0';
|
||||
}
|
||||
|
||||
if (read_dir) {
|
||||
error_if(chdir(read_dir) != 0, "Could not change to directory %s", read_dir);
|
||||
}
|
||||
|
||||
// Add files/directories
|
||||
for (int i = 0; i < sources_len; i++) {
|
||||
struct stat s;
|
||||
error_if(stat(sources[i], &s) != 0, "Could not stat file %s", sources[i]);
|
||||
if (S_ISDIR(s.st_mode)) {
|
||||
add_dir(sources[i], dest, &state);
|
||||
}
|
||||
else if (S_ISREG(s.st_mode)) {
|
||||
add_file(sources[i], dest, &state);
|
||||
}
|
||||
else {
|
||||
die("Path %s is neither a directory nor a regular file", sources[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Write index and header
|
||||
unsigned int total_size = state.size + QOP_HEADER_SIZE;
|
||||
for (int i = 0; i < state.len; i++) {
|
||||
write_64(state.files[i].hash, dest);
|
||||
write_32(state.files[i].offset, dest);
|
||||
write_32(state.files[i].size, dest);
|
||||
write_16(state.files[i].path_len, dest);
|
||||
write_16(state.files[i].flags, dest);
|
||||
total_size += 20;
|
||||
}
|
||||
|
||||
write_32(state.len, dest);
|
||||
write_32(total_size, dest);
|
||||
write_32(QOP_MAGIC, dest);
|
||||
|
||||
free(state.files);
|
||||
fclose(dest);
|
||||
|
||||
printf("files: %d, size: %d bytes\n", state.len, total_size);
|
||||
}
|
||||
|
||||
void exit_usage(void) {
|
||||
puts(
|
||||
"Usage: qopconv [OPTION...] FILE...\n"
|
||||
"\n"
|
||||
"Examples:\n"
|
||||
" qopconv dir1 archive.qop # Create archive.qop from dir1/\n"
|
||||
" qopconv foo bar archive.qop # Create archive.qop from files foo and bar\n"
|
||||
" qoponvv -u archive.qop # Unpack archive.qop in current directory\n"
|
||||
" qopconv -l archive.qop # List files in archive.qop\n"
|
||||
" qopconv -d dir1 dir2 archive.qop # Use dir1 prefix for reading, create\n"
|
||||
" archive.qop from files in dir1/dir2/\n"
|
||||
"\n"
|
||||
"Options (mutually exclusive):\n"
|
||||
" -u <archive> ... unpack archive\n"
|
||||
" -l <archive> ... list contents of archive\n"
|
||||
" -d <dir> ....... change read dir when creating archives\n"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 3) {
|
||||
exit_usage();
|
||||
}
|
||||
|
||||
// Unpack
|
||||
if (strcmp(argv[1], "-u") == 0) {
|
||||
unpack(argv[2], 0);
|
||||
}
|
||||
else if (strcmp(argv[1], "-l") == 0) {
|
||||
unpack(argv[2], 1);
|
||||
}
|
||||
else {
|
||||
int files_start = 1;
|
||||
char *read_dir = NULL;
|
||||
if (strcmp(argv[1], "-d") == 0) {
|
||||
read_dir = argv[2];
|
||||
files_start = 3;
|
||||
}
|
||||
if (argc < 2 + files_start) {
|
||||
exit_usage();
|
||||
}
|
||||
pack(read_dir, argv + files_start, argc - 1 - files_start, argv[argc-1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
85
scripts/compile.ce
Normal file
85
scripts/compile.ce
Normal file
@@ -0,0 +1,85 @@
|
||||
// cell compile
|
||||
var os = use('os')
|
||||
var io = use('cellfs')
|
||||
|
||||
log.console(json.encode(cell.config))
|
||||
|
||||
var project_name = cell.config.project.name
|
||||
|
||||
if (!project_name) {
|
||||
log.console("Error: project.name not found in cell.toml")
|
||||
$_.stop()
|
||||
}
|
||||
|
||||
log.console("Building project: " + project_name)
|
||||
|
||||
// 2. Prepare output directory
|
||||
if (!io.exists('.cell')) {
|
||||
io.mkdir('.cell')
|
||||
}
|
||||
|
||||
// 3. Find source files
|
||||
var files = io.enumerate('.', true)
|
||||
var objects = []
|
||||
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
var file = files[i]
|
||||
if (file.endsWith('.c')) {
|
||||
var path_no_ext = file.substring(0, file.length - 2)
|
||||
var safe_path = path_no_ext.replace(/\//g, '_').replace(/\\/g, '_')
|
||||
if (safe_path.startsWith('._')) safe_path = safe_path.substring(2)
|
||||
|
||||
var use_name = 'js_' + project_name + '_' + safe_path + '_use'
|
||||
|
||||
var obj_file = '.cell/build/' + file + '.o'
|
||||
var obj_dir = io.realdir(obj_file)
|
||||
var last_slash = file.lastIndexOf('/')
|
||||
if (last_slash != -1) {
|
||||
var dir = '.cell/build/' + file.substring(0, last_slash)
|
||||
if (!io.exists(dir)) {
|
||||
obj_file = '.cell/build/' + safe_path + '.o'
|
||||
}
|
||||
} else {
|
||||
obj_file = '.cell/build/' + file + '.o'
|
||||
}
|
||||
|
||||
objects.push(obj_file)
|
||||
|
||||
log.console("Compiling " + file + " -> " + obj_file)
|
||||
log.console(`export name is ${use_name}`)
|
||||
|
||||
// Compile command
|
||||
// cc -fPIC -c <file> -O3 -DCELL_USE_NAME=<name> -o <obj_file>
|
||||
var cmd = 'cc -fPIC -c ' + file + ' -O3 -DCELL_USE_NAME=' + use_name + ' -o ' + obj_file
|
||||
var ret = os.system(cmd)
|
||||
if (ret != 0) {
|
||||
log.console("Compilation failed for " + file)
|
||||
$_.stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Link shared library
|
||||
var lib_ext = '.so'
|
||||
var link_flags = '-shared'
|
||||
if (os.platform() == 'macOS') {
|
||||
lib_ext = '.dylib'
|
||||
link_flags = '-shared'
|
||||
} else if (os.platform() == 'Windows') {
|
||||
lib_ext = '.dll'
|
||||
}
|
||||
|
||||
var lib_name = project_name + lib_ext
|
||||
log.console("Linking " + lib_name)
|
||||
|
||||
var link_cmd = 'cc ' + link_flags + ' ' + objects.join(' ') + ' -lcell -o ' + lib_name
|
||||
var ret = os.system(link_cmd)
|
||||
|
||||
if (ret != 0) {
|
||||
log.console("Linking failed")
|
||||
$_.stop()
|
||||
}
|
||||
|
||||
log.console("Build complete: " + lib_name)
|
||||
|
||||
$_.stop()
|
||||
@@ -1,4 +1,3 @@
|
||||
// doc.js
|
||||
function docOf(obj, prop) {
|
||||
var block = obj[cell.DOC];
|
||||
if (!block) return '';
|
||||
|
||||
@@ -497,6 +497,8 @@ config ??= {}
|
||||
config.system ??= {}
|
||||
config.system.__proto__ = default_config
|
||||
|
||||
cell.config = config
|
||||
|
||||
ENETSERVICE = config.system.net_service
|
||||
REPLYTIMEOUT = config.system.reply_timeout
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,673 +0,0 @@
|
||||
/*
|
||||
HandmadeMath.h v2.0.0
|
||||
|
||||
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:
|
||||
|
||||
HMM_AngleRad(radians)
|
||||
HMM_AngleDeg(degrees)
|
||||
HMM_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 HMM_SINF, HMM_COSF, HMM_TANF, HMM_ACOSF, and HMM_SQRTF
|
||||
before including HandmadeMath.h, like so:
|
||||
|
||||
#define HANDMADE_MATH_PROVIDE_MATH_FUNCTIONS
|
||||
#define HMM_SINF MySinF
|
||||
#define HMM_COSF MyCosF
|
||||
#define HMM_TANF MyTanF
|
||||
#define HMM_ACOSF MyACosF
|
||||
#define HMM_SQRTF MySqrtF
|
||||
#include "HandmadeMath.h"
|
||||
|
||||
By default, it is assumed that your math functions take radians. To use
|
||||
different units, you must define HMM_ANGLE_USER_TO_INTERNAL and
|
||||
HMM_ANGLE_INTERNAL_TO_USER. For example, if you want to use degrees in your
|
||||
code but your math functions use turns:
|
||||
|
||||
#define HMM_ANGLE_USER_TO_INTERNAL(a) ((a)*HMM_DegToTurn)
|
||||
#define HMM_ANGLE_INTERNAL_TO_USER(a) ((a)*HMM_TurnToDeg)
|
||||
|
||||
=============================================================================
|
||||
|
||||
LICENSE
|
||||
|
||||
This software is in the public domain. Where that dedictaion 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
|
||||
|
||||
#if !defined(HANDMADE_MATH_NO_SIMD)
|
||||
#if defined(__ARM_NEON) || defined(__ARM_NEON__)
|
||||
#define HANDMADE_MATH__USE_NEON 1
|
||||
#include <arm_neon.h>
|
||||
#elif defined(_MSC_VER)
|
||||
#if defined(_M_AMD64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1)
|
||||
#define HANDMADE_MATH__USE_SSE 1
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
#elif defined(__SSE__)
|
||||
#define HANDMADE_MATH__USE_SSE 1
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4201)
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define HMM_DEPRECATED(msg) __attribute__((deprecated(msg)))
|
||||
#elif defined(_MSC_VER)
|
||||
#define HMM_DEPRECATED(msg) __declspec(deprecated(msg))
|
||||
#else
|
||||
#define HMM_DEPRECATED(msg)
|
||||
#endif
|
||||
|
||||
#if !defined(HANDMADE_MATH_USE_DEGREES) && !defined(HANDMADE_MATH_USE_TURNS) && !defined(HANDMADE_MATH_USE_RADIANS)
|
||||
#define HANDMADE_MATH_USE_RADIANS
|
||||
#endif
|
||||
|
||||
#define HMM_PI 3.14159265358979323846
|
||||
#define HMM_PI32 3.14159265359f
|
||||
#define HMM_DEG180 180.0
|
||||
#define HMM_DEG18032 180.0f
|
||||
#define HMM_TURNHALF 0.5
|
||||
#define HMM_TURNHALF32 0.5f
|
||||
#define HMM_RadToDeg ((float)(HMM_DEG180 / HMM_PI))
|
||||
#define HMM_RadToTurn ((float)(HMM_TURNHALF / HMM_PI))
|
||||
#define HMM_DegToRad ((float)(HMM_PI / HMM_DEG180))
|
||||
#define HMM_DegToTurn ((float)(HMM_TURNHALF / HMM_DEG180))
|
||||
#define HMM_TurnToRad ((float)(HMM_PI / HMM_TURNHALF))
|
||||
#define HMM_TurnToDeg ((float)(HMM_DEG180 / HMM_TURNHALF))
|
||||
|
||||
#if defined(HANDMADE_MATH_USE_RADIANS)
|
||||
#define HMM_AngleRad(a) (a)
|
||||
#define HMM_AngleDeg(a) ((a)*HMM_DegToRad)
|
||||
#define HMM_AngleTurn(a) ((a)*HMM_TurnToRad)
|
||||
#elif defined(HANDMADE_MATH_USE_DEGREES)
|
||||
#define HMM_AngleRad(a) ((a)*HMM_RadToDeg)
|
||||
#define HMM_AngleDeg(a) (a)
|
||||
#define HMM_AngleTurn(a) ((a)*HMM_TurnToDeg)
|
||||
#elif defined(HANDMADE_MATH_USE_TURNS)
|
||||
#define HMM_AngleRad(a) ((a)*HMM_RadToTurn)
|
||||
#define HMM_AngleDeg(a) ((a)*HMM_DegToTurn)
|
||||
#define HMM_AngleTurn(a) (a)
|
||||
#endif
|
||||
|
||||
#if !defined(HANDMADE_MATH_PROVIDE_MATH_FUNCTIONS)
|
||||
#include <math.h>
|
||||
#define HMM_SINF sinf
|
||||
#define HMM_COSF cosf
|
||||
#define HMM_TANF tanf
|
||||
#define HMM_SQRTF sqrtf
|
||||
#define HMM_ACOSF acosf
|
||||
#endif
|
||||
|
||||
#if !defined(HMM_ANGLE_USER_TO_INTERNAL)
|
||||
#define HMM_ANGLE_USER_TO_INTERNAL(a) (HMM_ToRad(a))
|
||||
#endif
|
||||
|
||||
#if !defined(HMM_ANGLE_INTERNAL_TO_USER)
|
||||
#if defined(HANDMADE_MATH_USE_RADIANS)
|
||||
#define HMM_ANGLE_INTERNAL_TO_USER(a) (a)
|
||||
#elif defined(HANDMADE_MATH_USE_DEGREES)
|
||||
#define HMM_ANGLE_INTERNAL_TO_USER(a) ((a)*HMM_RadToDeg)
|
||||
#elif defined(HANDMADE_MATH_USE_TURNS)
|
||||
#define HMM_ANGLE_INTERNAL_TO_USER(a) ((a)*HMM_RadToTurn)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define HMM_MIN(a, b) ((a) > (b) ? (b) : (a))
|
||||
#define HMM_MAX(a, b) ((a) < (b) ? (b) : (a))
|
||||
#define HMM_ABS(a) ((a) > 0 ? (a) : -(a))
|
||||
#define HMM_MOD(a, m) (((a) % (m)) >= 0 ? ((a) % (m)) : (((a) % (m)) + (m)))
|
||||
#define HMM_SQUARE(x) ((x) * (x))
|
||||
|
||||
#define HMMFMT_VEC3 "[%g,%g,%g]"
|
||||
#define HMMPRINT_VEC3(vec) vec.x, vec.y, vec.z
|
||||
|
||||
#define FMT_VEC4 "[%g,%g,%g,%g]"
|
||||
#define PRINT_VEC4(vec) vec.x, vec.y, vec.z, vec.w
|
||||
|
||||
#define FMT_M4 "[%g,%g,%g,%g\n%g,%g,%g,%g\n%g,%g,%g,%g\n%g,%g,%g,%g]"
|
||||
#define PRINT_M4(m) m.e[0][0], m.e[0][1], m.e[0][2], m.e[0][3], m.e[1][0], m.e[1][1], m.e[1][2], m.e[1][3], m.e[2][0], m.e[2][1], m.e[2][2], m.e[2][3], m.e[3][0], m.e[3][1], m.e[3][2], m.e[3][3]
|
||||
|
||||
typedef union HMM_Vec2 {
|
||||
struct
|
||||
{
|
||||
float X, Y;
|
||||
};
|
||||
|
||||
struct {
|
||||
float x, y;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
float U, V;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
float Left, Right;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
float Width, Height;
|
||||
};
|
||||
|
||||
float Elements[2];
|
||||
float e[2];
|
||||
|
||||
} HMM_Vec2;
|
||||
|
||||
typedef union HMM_Vec3 {
|
||||
struct
|
||||
{
|
||||
float X, Y, Z;
|
||||
};
|
||||
|
||||
struct { float x, y, z; };
|
||||
|
||||
struct
|
||||
{
|
||||
float U, V, W;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
float R, G, B;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
HMM_Vec2 XY;
|
||||
float _Ignored0;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
HMM_Vec2 xy;
|
||||
float _Ignored4;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
float _Ignored1;
|
||||
HMM_Vec2 YZ;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
HMM_Vec2 UV;
|
||||
float _Ignored2;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
float _Ignored3;
|
||||
HMM_Vec2 VW;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
HMM_Vec2 cp;
|
||||
float _Ignored5;
|
||||
};
|
||||
|
||||
float Elements[3];
|
||||
float e[3];
|
||||
|
||||
} HMM_Vec3;
|
||||
|
||||
typedef union HMM_Quat {
|
||||
struct
|
||||
{
|
||||
union {
|
||||
HMM_Vec3 XYZ;
|
||||
struct
|
||||
{
|
||||
float X, Y, Z;
|
||||
};
|
||||
};
|
||||
|
||||
float W;
|
||||
};
|
||||
|
||||
struct {float x, y, z, w;};
|
||||
|
||||
float Elements[4];
|
||||
float e[4];
|
||||
|
||||
#ifdef HANDMADE_MATH__USE_SSE
|
||||
__m128 SSE;
|
||||
#endif
|
||||
} HMM_Quat;
|
||||
|
||||
|
||||
typedef union HMM_Vec4 {
|
||||
struct
|
||||
{
|
||||
union {
|
||||
HMM_Vec3 XYZ;
|
||||
struct
|
||||
{
|
||||
float X, Y, Z;
|
||||
};
|
||||
HMM_Vec3 xyz;
|
||||
};
|
||||
|
||||
float W;
|
||||
};
|
||||
struct
|
||||
{
|
||||
union {
|
||||
HMM_Vec3 RGB;
|
||||
struct
|
||||
{
|
||||
float R, G, B;
|
||||
};
|
||||
};
|
||||
|
||||
float A;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
HMM_Vec2 XY;
|
||||
float _Ignored0;
|
||||
float _Ignored1;
|
||||
};
|
||||
|
||||
struct {
|
||||
HMM_Vec2 xy;
|
||||
float _ig0;
|
||||
float _ig1;
|
||||
};
|
||||
|
||||
struct {
|
||||
HMM_Vec2 _2;
|
||||
float _ig2;
|
||||
float _ig3;
|
||||
};
|
||||
|
||||
struct {
|
||||
HMM_Vec3 _3;
|
||||
float _ig4;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
float _Ignored2;
|
||||
HMM_Vec2 YZ;
|
||||
float _Ignored3;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
float _Ignored4;
|
||||
float _Ignored5;
|
||||
HMM_Vec2 ZW;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
HMM_Vec2 cp;
|
||||
HMM_Vec2 wh;
|
||||
};
|
||||
|
||||
HMM_Quat quat;
|
||||
struct {float x, y, z, w; };
|
||||
struct {float r, g, b, a; };
|
||||
struct {float u0, u1, v0, v1;};
|
||||
|
||||
float Elements[4];
|
||||
float e[4];
|
||||
|
||||
#ifdef HANDMADE_MATH__USE_SSE
|
||||
__m128 SSE;
|
||||
#endif
|
||||
#ifdef HANDMADE_MATH__USE_NEON
|
||||
float32x4_t NEON;
|
||||
#endif
|
||||
} HMM_Vec4;
|
||||
|
||||
typedef union HMM_Mat2 {
|
||||
float Elements[2][2];
|
||||
HMM_Vec2 Columns[2];
|
||||
|
||||
} HMM_Mat2;
|
||||
|
||||
typedef union HMM_Mat3 {
|
||||
float Elements[3][3];
|
||||
HMM_Vec3 Columns[3];
|
||||
|
||||
} HMM_Mat3;
|
||||
|
||||
typedef union HMM_Mat4 {
|
||||
float Elements[4][4];
|
||||
HMM_Vec4 Columns[4];
|
||||
HMM_Vec4 col[4];
|
||||
float e[4][4];
|
||||
float em[16];
|
||||
} HMM_Mat4;
|
||||
|
||||
extern const HMM_Vec2 v2zero;
|
||||
extern const HMM_Vec2 v2one;
|
||||
extern const HMM_Vec3 v3zero;
|
||||
extern const HMM_Vec3 v3one;
|
||||
extern const HMM_Vec4 v4zero;
|
||||
|
||||
typedef signed int HMM_Bool;
|
||||
|
||||
extern const HMM_Vec3 vX;
|
||||
extern const HMM_Vec3 vY;
|
||||
extern const HMM_Vec3 vZ;
|
||||
|
||||
extern const HMM_Vec3 vUP;
|
||||
extern const HMM_Vec3 vDOWN;
|
||||
extern const HMM_Vec3 vFWD;
|
||||
extern const HMM_Vec3 vBKWD;
|
||||
extern const HMM_Vec3 vLEFT;
|
||||
extern const HMM_Vec3 vRIGHT;
|
||||
|
||||
extern const HMM_Mat4 MAT1;
|
||||
|
||||
extern const HMM_Quat QUAT1;
|
||||
|
||||
/*
|
||||
* Angle unit conversion functions
|
||||
*/
|
||||
float HMM_ToRad(float Angle);
|
||||
float HMM_ToDeg(float Angle);
|
||||
float HMM_ToTurn(float Angle);
|
||||
|
||||
/*
|
||||
* Floating-point math functions
|
||||
*/
|
||||
float HMM_SinF(float Angle);
|
||||
float HMM_CosF(float Angle);
|
||||
float HMM_TanF(float Angle);
|
||||
float HMM_ACosF(float Arg);
|
||||
float HMM_SqrtF(float Float);
|
||||
float HMM_InvSqrtF(float Float);
|
||||
|
||||
/*
|
||||
* Utility functions
|
||||
*/
|
||||
float HMM_Lerp(float A, float Time, float B);
|
||||
float HMM_Clamp(float Min, float Value, float Max);
|
||||
float frand(float max);
|
||||
|
||||
/*
|
||||
* Vector initialization
|
||||
*/
|
||||
HMM_Vec2 HMM_V2(float X, float Y);
|
||||
HMM_Vec3 HMM_V3(float X, float Y, float Z);
|
||||
HMM_Vec3 HMM_V3i(float i);
|
||||
HMM_Vec4 HMM_V4(float X, float Y, float Z, float W);
|
||||
HMM_Vec4 HMM_V4V(HMM_Vec3 Vector, float W);
|
||||
|
||||
/*
|
||||
* Binary vector operations
|
||||
*/
|
||||
HMM_Vec2 HMM_AddV2(HMM_Vec2 Left, HMM_Vec2 Right);
|
||||
HMM_Vec3 HMM_AddV3(HMM_Vec3 Left, HMM_Vec3 Right);
|
||||
HMM_Vec4 HMM_AddV4(HMM_Vec4 Left, HMM_Vec4 Right);
|
||||
HMM_Vec2 HMM_SubV2(HMM_Vec2 Left, HMM_Vec2 Right);
|
||||
HMM_Vec3 HMM_SubV3(HMM_Vec3 Left, HMM_Vec3 Right);
|
||||
HMM_Vec4 HMM_SubV4(HMM_Vec4 Left, HMM_Vec4 Right);
|
||||
HMM_Vec2 HMM_MulV2(HMM_Vec2 Left, HMM_Vec2 Right);
|
||||
HMM_Vec2 HMM_MulV2F(HMM_Vec2 Left, float Right);
|
||||
HMM_Vec3 HMM_MulV3(HMM_Vec3 Left, HMM_Vec3 Right);
|
||||
HMM_Vec3 HMM_MulV3F(HMM_Vec3 Left, float Right);
|
||||
HMM_Vec4 HMM_MulV4(HMM_Vec4 Left, HMM_Vec4 Right);
|
||||
HMM_Vec4 HMM_MulV4F(HMM_Vec4 Left, float Right);
|
||||
HMM_Vec2 HMM_DivV2(HMM_Vec2 Left, HMM_Vec2 Right);
|
||||
HMM_Vec2 HMM_DivV2F(HMM_Vec2 Left, float Right);
|
||||
HMM_Vec3 HMM_DivV3(HMM_Vec3 Left, HMM_Vec3 Right);
|
||||
HMM_Vec3 HMM_DivV3F(HMM_Vec3 Left, float Right);
|
||||
HMM_Vec4 HMM_DivV4(HMM_Vec4 Left, HMM_Vec4 Right);
|
||||
HMM_Vec4 HMM_DivV4F(HMM_Vec4 Left, float Right);
|
||||
HMM_Bool HMM_EqV2(HMM_Vec2 Left, HMM_Vec2 Right);
|
||||
HMM_Bool HMM_EqV3(HMM_Vec3 Left, HMM_Vec3 Right);
|
||||
HMM_Bool HMM_EqV4(HMM_Vec4 Left, HMM_Vec4 Right);
|
||||
float HMM_DotV2(HMM_Vec2 Left, HMM_Vec2 Right);
|
||||
HMM_Vec2 HMM_ProjV2(HMM_Vec2 a, HMM_Vec2 b);
|
||||
float HMM_DotV3(HMM_Vec3 Left, HMM_Vec3 Right);
|
||||
float HMM_DotV4(HMM_Vec4 Left, HMM_Vec4 Right);
|
||||
HMM_Vec3 HMM_Cross(HMM_Vec3 Left, HMM_Vec3 Right);
|
||||
|
||||
/*
|
||||
* Unary vector operations
|
||||
*/
|
||||
float HMM_LenSqrV2(HMM_Vec2 A);
|
||||
float HMM_LenSqrV3(HMM_Vec3 A);
|
||||
float HMM_LenSqrV4(HMM_Vec4 A);
|
||||
float HMM_LenV2(HMM_Vec2 A);
|
||||
float HMM_AngleV2(HMM_Vec2 a, HMM_Vec2 b);
|
||||
float HMM_DistV2(HMM_Vec2 a, HMM_Vec2 b);
|
||||
HMM_Vec2 HMM_V2Rotate(HMM_Vec2 v, float angle);
|
||||
float HMM_LenV3(HMM_Vec3 A);
|
||||
float HMM_DistV3(HMM_Vec3 a, HMM_Vec3 b);
|
||||
float HMM_AngleV3(HMM_Vec3 a, HMM_Vec3 b);
|
||||
float HMM_LenV4(HMM_Vec4 A);
|
||||
float HMM_AngleV4(HMM_Vec4 a, HMM_Vec4 b);
|
||||
HMM_Vec2 HMM_NormV2(HMM_Vec2 A);
|
||||
HMM_Vec3 HMM_NormV3(HMM_Vec3 A);
|
||||
HMM_Vec4 HMM_NormV4(HMM_Vec4 A);
|
||||
|
||||
/*
|
||||
* Utility vector functions
|
||||
*/
|
||||
HMM_Vec2 HMM_LerpV2(HMM_Vec2 A, float Time, HMM_Vec2 B);
|
||||
HMM_Vec3 HMM_LerpV3(HMM_Vec3 A, float Time, HMM_Vec3 B);
|
||||
HMM_Vec4 HMM_LerpV4(HMM_Vec4 A, float Time, HMM_Vec4 B);
|
||||
|
||||
/*
|
||||
* SSE stuff
|
||||
*/
|
||||
HMM_Vec4 HMM_LinearCombineV4M4(HMM_Vec4 Left, HMM_Mat4 Right);
|
||||
|
||||
/*
|
||||
* 2x2 Matrices
|
||||
*/
|
||||
HMM_Mat2 HMM_M2(void);
|
||||
HMM_Mat2 HMM_M2D(float Diagonal);
|
||||
HMM_Mat2 HMM_TransposeM2(HMM_Mat2 Matrix);
|
||||
HMM_Mat2 HMM_RotateM2(float angle);
|
||||
HMM_Mat2 HMM_AddM2(HMM_Mat2 Left, HMM_Mat2 Right);
|
||||
HMM_Mat2 HMM_SubM2(HMM_Mat2 Left, HMM_Mat2 Right);
|
||||
HMM_Vec2 HMM_MulM2V2(HMM_Mat2 Matrix, HMM_Vec2 Vector);
|
||||
HMM_Mat2 HMM_MulM2(HMM_Mat2 Left, HMM_Mat2 Right);
|
||||
HMM_Mat2 HMM_MulM2F(HMM_Mat2 Matrix, float Scalar);
|
||||
HMM_Mat2 HMM_DivM2F(HMM_Mat2 Matrix, float Scalar);
|
||||
float HMM_DeterminantM2(HMM_Mat2 Matrix);
|
||||
HMM_Mat2 HMM_InvGeneralM2(HMM_Mat2 Matrix);
|
||||
|
||||
/*
|
||||
* 3x3 Matrices
|
||||
*/
|
||||
HMM_Mat3 HMM_M3(void);
|
||||
HMM_Mat3 HMM_M3D(float Diagonal);
|
||||
HMM_Mat3 HMM_Translate2D(HMM_Vec2 p);
|
||||
HMM_Mat3 HMM_RotateM3(float angle);
|
||||
HMM_Mat3 HMM_ScaleM3(HMM_Vec2 s);
|
||||
HMM_Mat3 HMM_TransposeM3(HMM_Mat3 Matrix);
|
||||
HMM_Mat3 HMM_AddM3(HMM_Mat3 Left, HMM_Mat3 Right);
|
||||
HMM_Mat3 HMM_SubM3(HMM_Mat3 Left, HMM_Mat3 Right);
|
||||
HMM_Vec3 HMM_MulM3V3(HMM_Mat3 Matrix, HMM_Vec3 Vector);
|
||||
HMM_Mat3 HMM_MulM3(HMM_Mat3 Left, HMM_Mat3 Right);
|
||||
HMM_Mat3 HMM_MulM3F(HMM_Mat3 Matrix, float Scalar);
|
||||
HMM_Mat3 HMM_DivM3F(HMM_Mat3 Matrix, float Scalar);
|
||||
HMM_Mat2 HMM_ScaleM2(HMM_Vec2 Scale);
|
||||
float HMM_DeterminantM3(HMM_Mat3 Matrix);
|
||||
HMM_Mat3 HMM_M2Basis(HMM_Mat2 basis);
|
||||
HMM_Mat3 HMM_InvGeneralM3(HMM_Mat3 Matrix);
|
||||
|
||||
/*
|
||||
* 4x4 Matrices
|
||||
*/
|
||||
HMM_Mat4 HMM_M4(void);
|
||||
HMM_Mat4 HMM_M4D(float Diagonal);
|
||||
HMM_Mat4 HMM_TransposeM4(HMM_Mat4 Matrix);
|
||||
HMM_Mat4 HMM_AddM4(HMM_Mat4 Left, HMM_Mat4 Right);
|
||||
HMM_Mat4 HMM_SubM4(HMM_Mat4 Left, HMM_Mat4 Right);
|
||||
HMM_Mat4 HMM_MulM4(HMM_Mat4 Left, HMM_Mat4 Right);
|
||||
HMM_Mat4 HMM_MulM4_P(HMM_Mat4 *Left, HMM_Mat4 *Right);
|
||||
HMM_Mat4 HMM_MulM4F(HMM_Mat4 Matrix, float Scalar);
|
||||
HMM_Vec4 HMM_MulM4V4(HMM_Mat4 Matrix, HMM_Vec4 Vector);
|
||||
HMM_Vec4 HMM_MulM4V4_P(HMM_Mat4 *Matrix, HMM_Vec4 *Vector);
|
||||
HMM_Mat4 HMM_DivM4F(HMM_Mat4 Matrix, float Scalar);
|
||||
float HMM_DeterminantM4(HMM_Mat4 Matrix);
|
||||
|
||||
// Returns a general-purpose inverse of an HMM_Mat4. Note that special-purpose inverses of many transformations
|
||||
// are available and will be more efficient.
|
||||
HMM_Mat4 HMM_InvGeneralM4(HMM_Mat4 Matrix);
|
||||
|
||||
/*
|
||||
* Common graphics transformations
|
||||
*/
|
||||
|
||||
// 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.
|
||||
HMM_Mat4 HMM_Orthographic_RH_NO(float Left, float Right, float Bottom, float Top, float Near, float Far);
|
||||
|
||||
// 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.
|
||||
HMM_Mat4 HMM_Orthographic_RH_ZO(float Left, float Right, float Bottom, float Top, float Near, float Far);
|
||||
|
||||
// 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.
|
||||
HMM_Mat4 HMM_Orthographic_LH_NO(float Left, float Right, float Bottom, float Top, float Near, float Far);
|
||||
|
||||
// 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.
|
||||
HMM_Mat4 HMM_Orthographic_LH_ZO(float Left, float Right, float Bottom, float Top, float Near, float Far);
|
||||
|
||||
// Returns an inverse for the given orthographic projection matrix. Works for all orthographic
|
||||
// projection matrices, regardless of handedness or NDC convention.
|
||||
HMM_Mat4 HMM_InvOrthographic(HMM_Mat4 OrthoMatrix);
|
||||
HMM_Mat4 HMM_Perspective_RH_NO(float FOV, float AspectRatio, float Near, float Far);
|
||||
HMM_Mat4 HMM_Perspective_RH_ZO(float FOV, float AspectRatio, float Near, float Far);
|
||||
HMM_Mat4 HMM_Perspective_LH_NO(float FOV, float AspectRatio, float Near, float Far);
|
||||
HMM_Mat4 HMM_Perspective_LH_ZO(float FOV, float AspectRatio, float Near, float Far);
|
||||
|
||||
HMM_Mat4 HMM_Perspective_Metal(float FOV, float AspectRation, float Near, float Far);
|
||||
HMM_Mat4 HMM_Orthographic_Metal(float l, float r, float b, float t, float near, float far);
|
||||
|
||||
HMM_Mat4 HMM_Orthographic_DX(float l, float r, float b, float t, float near, float far);
|
||||
HMM_Mat4 HMM_Orthographic_GL(float l, float r, float b, float t, float near, float far);
|
||||
|
||||
HMM_Mat4 HMM_InvPerspective_RH(HMM_Mat4 PerspectiveMatrix);
|
||||
HMM_Mat4 HMM_InvPerspective_LH(HMM_Mat4 PerspectiveMatrix);
|
||||
HMM_Mat4 HMM_Translate(HMM_Vec3 Translation);
|
||||
HMM_Mat4 HMM_InvTranslate(HMM_Mat4 TranslationMatrix);
|
||||
HMM_Mat4 HMM_Rotate_RH(float Angle, HMM_Vec3 Axis);
|
||||
HMM_Mat4 HMM_Rotate_LH(float Angle, HMM_Vec3 Axis);
|
||||
HMM_Mat4 HMM_InvRotate(HMM_Mat4 RotationMatrix);
|
||||
HMM_Mat4 HMM_Scale(HMM_Vec3 Scale);
|
||||
HMM_Mat4 HMM_InvScale(HMM_Mat4 ScaleMatrix);
|
||||
HMM_Mat4 _HMM_LookAt(HMM_Vec3 F, HMM_Vec3 S, HMM_Vec3 U, HMM_Vec3 Eye);
|
||||
HMM_Mat4 HMM_LookAt_RH(HMM_Vec3 Eye, HMM_Vec3 Center, HMM_Vec3 Up);
|
||||
HMM_Mat4 HMM_LookAt_LH(HMM_Vec3 Eye, HMM_Vec3 Center, HMM_Vec3 Up);
|
||||
HMM_Mat4 HMM_InvLookAt(HMM_Mat4 Matrix);
|
||||
|
||||
/*
|
||||
* Quaternion operations
|
||||
*/
|
||||
HMM_Vec3 HMM_QVRot(HMM_Vec3 v, HMM_Quat q)
|
||||
;
|
||||
HMM_Quat HMM_Q(float X, float Y, float Z, float W);
|
||||
HMM_Quat HMM_QV4(HMM_Vec4 Vector);
|
||||
HMM_Quat HMM_AddQ(HMM_Quat Left, HMM_Quat Right);
|
||||
HMM_Quat HMM_SubQ(HMM_Quat Left, HMM_Quat Right);
|
||||
HMM_Quat HMM_MulQ(HMM_Quat Left, HMM_Quat Right);
|
||||
HMM_Quat HMM_MulQF(HMM_Quat Left, float Multiplicative);
|
||||
HMM_Quat HMM_DivQF(HMM_Quat Left, float Divnd);
|
||||
float HMM_DotQ(HMM_Quat Left, HMM_Quat Right);
|
||||
HMM_Quat HMM_InvQ(HMM_Quat Left);
|
||||
HMM_Quat HMM_NormQ(HMM_Quat Quat);
|
||||
HMM_Quat _HMM_MixQ(HMM_Quat Left, float MixLeft, HMM_Quat Right, float MixRight);
|
||||
HMM_Quat HMM_NLerp(HMM_Quat Left, float Time, HMM_Quat Right);
|
||||
HMM_Quat HMM_SLerp(HMM_Quat Left, float Time, HMM_Quat Right);
|
||||
HMM_Mat4 HMM_QToM4(HMM_Quat Left);
|
||||
HMM_Mat4 HMM_M4TRS(HMM_Vec3 t, HMM_Quat q, HMM_Vec3 s);
|
||||
HMM_Mat3 HMM_M3TRS(HMM_Vec2 t, float angle, HMM_Vec2 s);
|
||||
HMM_Mat3 HMM_Mat4ToMat3(HMM_Mat4 m);
|
||||
|
||||
HMM_Quat HMM_M4ToQ_RH(HMM_Mat4 M);
|
||||
HMM_Quat HMM_M4ToQ_LH(HMM_Mat4 M);
|
||||
HMM_Quat HMM_QFromAxisAngle_RH(HMM_Vec3 Axis, float AngleOfRotation);
|
||||
HMM_Quat HMM_QFromAxisAngle_LH(HMM_Vec3 Axis, float AngleOfRotation);
|
||||
|
||||
float HMM_Q_Roll(HMM_Quat q);
|
||||
float HMM_Q_Yaw(HMM_Quat q);
|
||||
float HMM_Q_Pitch(HMM_Quat q);
|
||||
|
||||
#endif /* HANDMADE_MATH_H */
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef PROSPERON_H
|
||||
#define PROSPERON_H
|
||||
#ifndef CELL_H
|
||||
#define CELL_H
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include "quickjs.h"
|
||||
@@ -113,6 +113,11 @@ void actor_clock(cell_rt *actor, JSValue fn);
|
||||
|
||||
int JS_ArrayLength(JSContext *js, JSValue a);
|
||||
|
||||
int js2bool(JSContext *js, JSValue v);
|
||||
JSValue bool2js(JSContext *js, int b);
|
||||
double js2number(JSContext *js, JSValue v);
|
||||
JSValue number2js(JSContext *js, double g);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
479
source/jsffi.c
479
source/jsffi.c
@@ -81,18 +81,13 @@ double rand_range(JSContext *js, double min, double max)
|
||||
return genRand(mrand) * (max-min)+min;
|
||||
}
|
||||
|
||||
typedef struct texture_vertex {
|
||||
float x, y, z;
|
||||
float u, v;
|
||||
uint8_t r, g, b,a;
|
||||
} texture_vertex;
|
||||
|
||||
#define JS_GETNUM(JS,VAL,I,TO,TYPE) { \
|
||||
JSValue val = JS_GetPropertyUint32(JS,VAL,I); \
|
||||
TO = js2##TYPE(JS, val); \
|
||||
JS_FreeValue(JS, val); } \
|
||||
|
||||
int js2bool(JSContext *js, JSValue v) { return JS_ToBool(js,v); }
|
||||
JSValue bool2js(JSContext *js, int b) { return JS_NewBool(js,b); }
|
||||
|
||||
JSValue number2js(JSContext *js, double g) { return JS_NewFloat64(js,g); }
|
||||
double js2number(JSContext *js, JSValue v) {
|
||||
@@ -102,47 +97,6 @@ double js2number(JSContext *js, JSValue v) {
|
||||
return g;
|
||||
}
|
||||
|
||||
JSValue js_getpropertyuint32(JSContext *js, JSValue v, unsigned int i)
|
||||
{
|
||||
JSValue ret = JS_GetPropertyUint32(js,v,i);
|
||||
JS_FreeValue(js,ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
double js_getnum_uint32(JSContext *js, JSValue v, unsigned int i)
|
||||
{
|
||||
JSValue val = JS_GetPropertyUint32(js,v,i);
|
||||
double ret = js2number(js, val);
|
||||
JS_FreeValue(js,val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
double js_getnum_str(JSContext *js, JSValue v, const char *str)
|
||||
{
|
||||
JSValue val = JS_GetPropertyStr(js,v,str);
|
||||
double ret = js2number(js,val);
|
||||
JS_FreeValue(js,val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define JS_GETPROP(JS, TARGET, VALUE, PROP, TYPE) {\
|
||||
JSValue __##PROP##__v = JS_GetPropertyStr(JS,VALUE,#PROP); \
|
||||
TARGET = js2##TYPE(JS, __##PROP##__v); \
|
||||
JS_FreeValue(JS,__##PROP##__v); }\
|
||||
|
||||
#define JS_GETATOM(JS, TARGET, VALUE, ATOM, TYPE) {\
|
||||
JSValue __##PROP##__v = JS_GetPropertyStr(JS,VALUE,#ATOM); \
|
||||
TARGET = js2##TYPE(JS, __##PROP##__v); \
|
||||
JS_FreeValue(JS,__##PROP##__v); }\
|
||||
|
||||
int JS_GETBOOL(JSContext *js, JSValue v, const char *prop)
|
||||
{
|
||||
JSValue __v = JS_GetPropertyStr(js,v,prop);
|
||||
int r = JS_ToBool(js,__v);
|
||||
JS_FreeValue(js,__v);
|
||||
return r;
|
||||
}
|
||||
|
||||
JSValue js_getproperty(JSContext *js, JSValue v, const char *prop)
|
||||
{
|
||||
JSValue ret = JS_GetPropertyStr(js, v, prop);
|
||||
@@ -176,28 +130,6 @@ JSValue make_quad_indices_buffer(JSContext *js, int quads)
|
||||
return JS_DupValue(js,rt->idx_buffer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef struct lrtb lrtb;
|
||||
|
||||
lrtb js2lrtb(JSContext *js, JSValue v)
|
||||
{
|
||||
lrtb ret = {0};
|
||||
JS_GETATOM(js,ret.l,v,l,number)
|
||||
JS_GETATOM(js,ret.r,v,r,number)
|
||||
JS_GETATOM(js,ret.b,v,b,number)
|
||||
JS_GETATOM(js,ret.t,v,t,number)
|
||||
return ret;
|
||||
}
|
||||
|
||||
JSValue vec22js(JSContext *js,HMM_Vec2 v)
|
||||
{
|
||||
JSValue array = JS_NewArray(js);
|
||||
JS_SetPropertyUint32(js, array,0,number2js(js,v.x));
|
||||
JS_SetPropertyUint32(js, array,1,number2js(js,v.y));
|
||||
return array;
|
||||
}
|
||||
|
||||
char *js2strdup(JSContext *js, JSValue v) {
|
||||
const char *str = JS_ToCString(js, v);
|
||||
char *ret = strdup(str);
|
||||
@@ -216,340 +148,6 @@ double js2angle(JSContext *js,JSValue v) {
|
||||
return n * HMM_TurnToRad;
|
||||
}
|
||||
|
||||
typedef HMM_Vec4 colorf;
|
||||
|
||||
colorf js2color(JSContext *js,JSValue v) {
|
||||
if (JS_IsNull(v)) return (colorf){1,1,1,1};
|
||||
|
||||
colorf color = {1,1,1,1}; // Default to white
|
||||
|
||||
if (JS_IsArray(js, v)) {
|
||||
// Handle array format: [r, g, b, a]
|
||||
JSValue c[4];
|
||||
for (int i = 0; i < 4; i++) c[i] = JS_GetPropertyUint32(js,v,i);
|
||||
|
||||
color.r = js2number(js,c[0]);
|
||||
color.g = js2number(js,c[1]);
|
||||
color.b = js2number(js,c[2]);
|
||||
color.a = JS_IsNull(c[3]) ? 1.0 : js2number(js,c[3]);
|
||||
|
||||
for (int i = 0; i < 4; i++) JS_FreeValue(js,c[i]);
|
||||
} else if (JS_IsObject(v)) {
|
||||
JS_GETPROP(js, color.r, v, r, number)
|
||||
JS_GETPROP(js, color.g, v, g, number)
|
||||
JS_GETPROP(js, color.b, v, b, number)
|
||||
JS_GETPROP(js, color.a, v, a, number)
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
JSValue color2js(JSContext *js, colorf color)
|
||||
{
|
||||
JSValue arr = JS_NewArray(js);
|
||||
JS_SetPropertyUint32(js, arr,0,number2js(js,(double)color.r));
|
||||
JS_SetPropertyUint32(js, arr,1,number2js(js,(double)color.g));
|
||||
JS_SetPropertyUint32(js, arr,2,number2js(js,(double)color.b));
|
||||
JS_SetPropertyUint32(js, arr,3,number2js(js,(double)color.a));
|
||||
return arr;
|
||||
}
|
||||
|
||||
HMM_Vec2 js2vec2(JSContext *js,JSValue v)
|
||||
{
|
||||
HMM_Vec2 v2;
|
||||
|
||||
// Check if it's an array
|
||||
if (JS_IsArray(js, v)) {
|
||||
v2.X = js_getnum_uint32(js,v,0);
|
||||
v2.Y = js_getnum_uint32(js,v,1);
|
||||
} else {
|
||||
// Try to get x,y properties from object
|
||||
JSValue x_val = JS_GetPropertyStr(js, v, "x");
|
||||
JSValue y_val = JS_GetPropertyStr(js, v, "y");
|
||||
|
||||
v2.X = js2number(js, x_val);
|
||||
v2.Y = js2number(js, y_val);
|
||||
|
||||
JS_FreeValue(js, x_val);
|
||||
JS_FreeValue(js, y_val);
|
||||
}
|
||||
|
||||
return v2;
|
||||
}
|
||||
|
||||
HMM_Vec3 js2vec3(JSContext *js,JSValue v)
|
||||
{
|
||||
HMM_Vec3 v3;
|
||||
v3.x = js_getnum_uint32(js, v,0);
|
||||
v3.y = js_getnum_uint32(js, v,1);
|
||||
v3.z = js_getnum_uint32(js, v,2);
|
||||
return v3;
|
||||
}
|
||||
|
||||
float *js2floats(JSContext *js, JSValue v, size_t *len)
|
||||
{
|
||||
*len = JS_ArrayLength(js,v);
|
||||
float *arr = malloc(sizeof(float)* *len);
|
||||
for (int i = 0; i < *len; i++)
|
||||
arr[i] = js_getnum_uint32(js,v,i);
|
||||
return arr;
|
||||
}
|
||||
|
||||
double *js2doubles(JSContext *js, JSValue v, size_t *len)
|
||||
{
|
||||
*len = JS_ArrayLength(js,v);
|
||||
double *arr = malloc(sizeof(double)* *len);
|
||||
for (int i = 0; i < *len; i++)
|
||||
arr[i] = js_getnum_uint32(js,v,i);
|
||||
return arr;
|
||||
}
|
||||
|
||||
HMM_Vec3 js2vec3f(JSContext *js, JSValue v)
|
||||
{
|
||||
HMM_Vec3 vec;
|
||||
if (JS_IsArray(js, v))
|
||||
return js2vec3(js,v);
|
||||
else
|
||||
vec.x = vec.y = vec.z = js2number(js,v);
|
||||
return vec;
|
||||
}
|
||||
|
||||
JSValue vec32js(JSContext *js, HMM_Vec3 v)
|
||||
{
|
||||
JSValue array = JS_NewArray(js);
|
||||
JS_SetPropertyUint32(js, array,0,number2js(js,v.x));
|
||||
JS_SetPropertyUint32(js, array,1,number2js(js,v.y));
|
||||
JS_SetPropertyUint32(js, array,2,number2js(js,v.z));
|
||||
return array;
|
||||
}
|
||||
|
||||
JSValue vec3f2js(JSContext *js, HMM_Vec3 v)
|
||||
{
|
||||
return vec32js(js,v);
|
||||
}
|
||||
|
||||
JSValue quat2js(JSContext *js, HMM_Quat q)
|
||||
{
|
||||
JSValue arr = JS_NewArray(js);
|
||||
JS_SetPropertyUint32(js, arr, 0, number2js(js,q.x));
|
||||
JS_SetPropertyUint32(js, arr,1,number2js(js,q.y));
|
||||
JS_SetPropertyUint32(js, arr,2,number2js(js,q.z));
|
||||
JS_SetPropertyUint32(js, arr,3,number2js(js,q.w));
|
||||
return arr;
|
||||
}
|
||||
|
||||
HMM_Vec4 js2vec4(JSContext *js, JSValue v)
|
||||
{
|
||||
HMM_Vec4 v4;
|
||||
for (int i = 0; i < 4; i++)
|
||||
v4.e[i] = js_getnum_uint32(js, v,i);
|
||||
return v4;
|
||||
}
|
||||
|
||||
double arr_vec_length(JSContext *js,JSValue v)
|
||||
{
|
||||
int len = JS_ArrayLength(js,v);
|
||||
switch(len) {
|
||||
case 2: return HMM_LenV2(js2vec2(js,v));
|
||||
case 3: return HMM_LenV3(js2vec3(js,v));
|
||||
case 4: return HMM_LenV4(js2vec4(js,v));
|
||||
}
|
||||
|
||||
double sum = 0;
|
||||
for (int i = 0; i < len; i++)
|
||||
sum += pow(js_getnum_uint32(js, v, i), 2);
|
||||
|
||||
return sqrt(sum);
|
||||
}
|
||||
|
||||
HMM_Quat js2quat(JSContext *js,JSValue v)
|
||||
{
|
||||
return js2vec4(js,v).quat;
|
||||
}
|
||||
|
||||
JSValue vec42js(JSContext *js, HMM_Vec4 v)
|
||||
{
|
||||
JSValue array = JS_NewArray(js);
|
||||
for (int i = 0; i < 4; i++)
|
||||
JS_SetPropertyUint32(js, array,i,number2js(js,v.e[i]));
|
||||
return array;
|
||||
}
|
||||
|
||||
HMM_Vec2 *js2cpvec2arr(JSContext *js,JSValue v) {
|
||||
HMM_Vec2 *arr = NULL;
|
||||
int n = JS_ArrayLength(js,v);
|
||||
arrsetlen(arr,n);
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
arr[i] = js2vec2(js,js_getpropertyuint32(js, v, i));
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
JSValue vecarr2js(JSContext *js,HMM_Vec2 *points, int n) {
|
||||
JSValue array = JS_NewArray(js);
|
||||
for (int i = 0; i < n; i++)
|
||||
JS_SetPropertyUint32(js, array,i,vec22js(js,points[i]));
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
rect js2rect(JSContext *js,JSValue v) {
|
||||
if (JS_IsNull(v)) return (rect){0,0,1,1};
|
||||
rect rect;
|
||||
JS_GETATOM(js,rect.x,v,x,number)
|
||||
JS_GETATOM(js,rect.y,v,y,number)
|
||||
JS_GETATOM(js,rect.w,v,width,number)
|
||||
JS_GETATOM(js,rect.h,v,height,number)
|
||||
float anchor_x, anchor_y;
|
||||
JS_GETATOM(js, anchor_x, v, anchor_x, number)
|
||||
JS_GETATOM(js, anchor_y, v, anchor_y, number)
|
||||
|
||||
rect.y -= anchor_y*rect.h;
|
||||
rect.x -= anchor_x*rect.w;
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
irect js2irect(JSContext *js, JSValue v)
|
||||
{
|
||||
if (JS_IsNull(v)) return (irect){0,0,1,1};
|
||||
irect rect;
|
||||
JS_GETATOM(js,rect.x,v,x,number)
|
||||
JS_GETATOM(js,rect.y,v,y,number)
|
||||
JS_GETATOM(js,rect.w,v,width,number)
|
||||
JS_GETATOM(js,rect.h,v,height,number)
|
||||
float anchor_x, anchor_y;
|
||||
JS_GETATOM(js, anchor_x, v, anchor_x, number)
|
||||
JS_GETATOM(js, anchor_y, v, anchor_y, number)
|
||||
|
||||
rect.y -= anchor_y*rect.h;
|
||||
rect.x -= anchor_x*rect.w;
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
JSValue rect2js(JSContext *js,rect rect) {
|
||||
JSValue obj = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js, obj, "x", number2js(js, rect.x));
|
||||
JS_SetPropertyStr(js, obj, "y", number2js(js, rect.y));
|
||||
JS_SetPropertyStr(js, obj, "width", number2js(js, rect.w));
|
||||
JS_SetPropertyStr(js, obj, "height", number2js(js, rect.h));
|
||||
return obj;
|
||||
}
|
||||
|
||||
static JSValue floats2array(JSContext *js, float *vals, size_t len) {
|
||||
JSValue arr = JS_NewArray(js);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
JS_SetPropertyUint32(js, arr, i, number2js(js, vals[i]));
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
#define JS_HMM_FN(OP, HMM, SIGN) \
|
||||
JSC_CCALL(array_##OP, \
|
||||
int len = JS_ArrayLength(js,self); \
|
||||
if (!JS_IsArray(js, argv[0])) { \
|
||||
double n = js2number(js,argv[0]); \
|
||||
JSValue arr = JS_NewArray(js); \
|
||||
for (int i = 0; i < len; i++) \
|
||||
JS_SetPropertyUint32(js, arr, i, number2js(js,js_getnum_uint32(js, self,i) SIGN n)); \
|
||||
return arr; \
|
||||
} \
|
||||
switch(len) { \
|
||||
case 2: \
|
||||
return vec22js(js,HMM_##HMM##V2(js2vec2(js,self), js2vec2(js,argv[0]))); \
|
||||
case 3: \
|
||||
return vec32js(js, HMM_##HMM##V3(js2vec3(js,self), js2vec3(js,argv[0]))); \
|
||||
case 4: \
|
||||
return vec42js(js,HMM_##HMM##V4(js2vec4(js,self), js2vec4(js,argv[0]))); \
|
||||
} \
|
||||
\
|
||||
JSValue arr = JS_NewArray(js); \
|
||||
for (int i = 0; i < len; i++) { \
|
||||
double a = js_getnum_uint32(js, self,i); \
|
||||
double b = js_getnum_uint32(js, argv[0],i); \
|
||||
JS_SetPropertyUint32(js, arr, i, number2js(js,a SIGN b)); \
|
||||
} \
|
||||
return arr; \
|
||||
) \
|
||||
|
||||
JS_HMM_FN(add, Add, +)
|
||||
JS_HMM_FN(sub, Sub, -)
|
||||
JS_HMM_FN(div, Div, /)
|
||||
JS_HMM_FN(scale, Mul, *)
|
||||
|
||||
JSC_CCALL(array_lerp,
|
||||
double t = js2number(js,argv[1]);
|
||||
int len = JS_ArrayLength(js,self);
|
||||
JSValue arr = JS_NewArray(js);
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
double from = js_getnum_uint32(js, self, i);
|
||||
double to = js_getnum_uint32(js, argv[0], i);
|
||||
JS_SetPropertyUint32(js, arr, i, number2js(js,(to - from) * t + from));
|
||||
}
|
||||
return arr;
|
||||
)
|
||||
|
||||
JSValue js_array_get_x(JSContext *js, JSValue self) { return JS_GetPropertyUint32(js,self,0); }
|
||||
JSValue js_array_set_x(JSContext *js, JSValue self, JSValue val) { JS_SetPropertyUint32(js,self,0,val); return JS_NULL; }
|
||||
|
||||
JSValue js_array_get_y(JSContext *js, JSValue self) { return JS_GetPropertyUint32(js,self,1); }
|
||||
JSValue js_array_set_y(JSContext *js, JSValue self, JSValue val) { JS_SetPropertyUint32(js,self,1,val); return JS_NULL; }
|
||||
|
||||
// Single-value accessors
|
||||
|
||||
JSValue js_array_get_r(JSContext *js, JSValue self)
|
||||
{ return JS_GetPropertyUint32(js, self, 0); }
|
||||
|
||||
JSValue js_array_set_r(JSContext *js, JSValue self, JSValue val)
|
||||
{ JS_SetPropertyUint32(js, self, 0, val); return JS_NULL; }
|
||||
|
||||
JSValue js_array_get_g(JSContext *js, JSValue self)
|
||||
{ return JS_GetPropertyUint32(js, self, 1); }
|
||||
|
||||
JSValue js_array_set_g(JSContext *js, JSValue self, JSValue val)
|
||||
{ JS_SetPropertyUint32(js, self, 1, val); return JS_NULL; }
|
||||
|
||||
JSValue js_array_get_b(JSContext *js, JSValue self)
|
||||
{ return JS_GetPropertyUint32(js, self, 2); }
|
||||
|
||||
JSValue js_array_set_b(JSContext *js, JSValue self, JSValue val)
|
||||
{ JS_SetPropertyUint32(js, self, 2, val); return JS_NULL; }
|
||||
|
||||
JSValue js_array_get_a(JSContext *js, JSValue self)
|
||||
{ return JS_GetPropertyUint32(js, self, 3); }
|
||||
|
||||
JSValue js_array_set_a(JSContext *js, JSValue self, JSValue val)
|
||||
{ JS_SetPropertyUint32(js, self, 3, val); return JS_NULL; }
|
||||
|
||||
// Multi-value accessors
|
||||
static const JSCFunctionListEntry js_array_funcs[] = {
|
||||
PROTO_FUNC_DEF(array, add, 1),
|
||||
PROTO_FUNC_DEF(array, sub, 1),
|
||||
PROTO_FUNC_DEF(array, div,1),
|
||||
PROTO_FUNC_DEF(array, scale, 1),
|
||||
PROTO_FUNC_DEF(array, lerp, 2),
|
||||
JS_CGETSET_DEF("x", js_array_get_x,js_array_set_x),
|
||||
JS_CGETSET_DEF("y", js_array_get_y, js_array_set_y),
|
||||
JS_CGETSET_DEF("r", js_array_get_r, js_array_set_r),
|
||||
JS_CGETSET_DEF("g", js_array_get_g, js_array_set_g),
|
||||
JS_CGETSET_DEF("b", js_array_get_b, js_array_set_b),
|
||||
JS_CGETSET_DEF("a", js_array_get_a, js_array_set_a),
|
||||
};
|
||||
|
||||
JSC_CCALL(number_lerp,
|
||||
double a = js2number(js,self);
|
||||
double b = js2number(js,argv[0]);
|
||||
double t = js2number(js,argv[1]);
|
||||
return number2js(js, (b-a)*t+a);
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_number_funcs[] = {
|
||||
PROTO_FUNC_DEF(number, lerp, 2),
|
||||
};
|
||||
|
||||
static uint32_t rng_state = 123456789;
|
||||
static uint32_t xorshift32(){
|
||||
uint32_t x = rng_state;
|
||||
@@ -601,73 +199,10 @@ JSC_CCALL(os_srand,
|
||||
m_seedRand(mrand, js2number(js,argv[0]));
|
||||
)
|
||||
|
||||
JSC_CCALL(os_make_line_prim,
|
||||
return JS_NULL;
|
||||
/*
|
||||
JSValue prim = JS_NewObject(js);
|
||||
HMM_Vec2 *v = js2cpvec2arr(js,argv[0]);
|
||||
|
||||
parsl_context *par_ctx = parsl_create_context((parsl_config){
|
||||
.thickness = js2number(js,argv[1]),
|
||||
.flags= PARSL_FLAG_ANNOTATIONS,
|
||||
.u_mode = js2number(js,argv[2])
|
||||
});
|
||||
|
||||
uint16_t spine_lens[] = {arrlen(v)};
|
||||
|
||||
parsl_mesh *m = parsl_mesh_from_lines(par_ctx, (parsl_spine_list){
|
||||
.num_vertices = arrlen(v),
|
||||
.num_spines = 1,
|
||||
.vertices = v,
|
||||
.spine_lengths = spine_lens,
|
||||
.closed = JS_ToBool(js,argv[3])
|
||||
});
|
||||
|
||||
JS_SetPropertyStr(js, prim, "pos", make_gpu_buffer(js,m->positions,sizeof(*m->positions)*m->num_vertices, 0, 2,1,0));
|
||||
|
||||
JS_SetPropertyStr(js, prim, "indices", make_gpu_buffer(js,m->triangle_indices,sizeof(*m->triangle_indices)*m->num_triangles*3, JS_TYPED_ARRAY_UINT32, 1,1,1));
|
||||
|
||||
float uv[m->num_vertices*2];
|
||||
for (int i = 0; i < m->num_vertices; i++) {
|
||||
uv[i*2] = m->annotations[i].u_along_curve;
|
||||
uv[i*2+1] = m->annotations[i].v_across_curve;
|
||||
}
|
||||
|
||||
JS_SetPropertyStr(js, prim, "uv", make_gpu_buffer(js, uv, sizeof(uv), 0,2,1,0));
|
||||
JS_SetPropertyStr(js,prim,"vertices", number2js(js,m->num_vertices));
|
||||
JS_SetPropertyStr(js,prim,"num_indices", number2js(js,m->num_triangles*3));
|
||||
JS_SetPropertyStr(js,prim,"first_index", number2js(js,0));
|
||||
|
||||
parsl_destroy_context(par_ctx);
|
||||
|
||||
return prim;
|
||||
*/
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_util_funcs[] = {
|
||||
MIST_FUNC_DEF(os, guid, 0),
|
||||
};
|
||||
|
||||
JSC_CCALL(graphics_hsl_to_rgb,
|
||||
float h, s, l;
|
||||
JS_ToFloat64(js, &h, argv[0]);
|
||||
JS_ToFloat64(js, &s, argv[1]);
|
||||
JS_ToFloat64(js, &l, argv[2]);
|
||||
float c = (1 - abs(2 * l - 1)) * s;
|
||||
float x = c * (1 - abs(fmod((h/60),2) - 1));
|
||||
float m = l - c / 2;
|
||||
float r = 0, g = 0, b = 0;
|
||||
|
||||
if (h < 60) { r = c; g = x; }
|
||||
else if (h < 120) { r = x; g = c; }
|
||||
else if (h < 180) { g = c; b = x; }
|
||||
else if (h < 240) { g = x; b = c; }
|
||||
else if (h < 300) { r = x; b = c; }
|
||||
else { r = c; b = x; }
|
||||
|
||||
return color2js(js, (colorf){r+m, g+m, b+m, 1});
|
||||
)
|
||||
|
||||
static void *get_main_module_handle() {
|
||||
#if defined(_WIN32)
|
||||
return GetModuleHandle(NULL);
|
||||
@@ -803,18 +338,6 @@ void ffi_load(JSContext *js)
|
||||
JSValue prosp = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js,globalThis,"prosperon", prosp);
|
||||
|
||||
JSValue jsarray = JS_GetPropertyStr(js,globalThis, "Array");
|
||||
JSValue array_proto = JS_GetPropertyStr(js,jsarray, "prototype");
|
||||
JS_SetPropertyFunctionList(js, array_proto, js_array_funcs, countof(js_array_funcs));
|
||||
JS_FreeValue(js,jsarray);
|
||||
JS_FreeValue(js,array_proto);
|
||||
|
||||
JSValue jsnumber = JS_GetPropertyStr(js,globalThis, "Number");
|
||||
JSValue number_proto = JS_GetPropertyStr(js,jsnumber, "prototype");
|
||||
JS_SetPropertyFunctionList(js, number_proto, js_number_funcs, countof(js_number_funcs));
|
||||
JS_FreeValue(js,jsnumber);
|
||||
JS_FreeValue(js,number_proto);
|
||||
|
||||
JSValue hidden_fn = JS_NewObject(js);
|
||||
|
||||
// Add functions that should only be accessible to engine.js
|
||||
|
||||
@@ -2,102 +2,7 @@
|
||||
#define FFI_H
|
||||
|
||||
#include "cell.h"
|
||||
#include "HandmadeMath.h"
|
||||
#include "render.h"
|
||||
|
||||
#define JS_SetProperty(js, tar, str, val) JS_SetPropertyStr(js, tar, #str, val)
|
||||
#define JS_GetProperty(js, tar, atom) JS_GetPropertyStr(js, tar, #atom)
|
||||
|
||||
// Core FFI functions
|
||||
void ffi_load(JSContext *js);
|
||||
int js_print_exception(JSContext *js, JSValue v);
|
||||
|
||||
// Global trace flag
|
||||
extern int trace;
|
||||
|
||||
// Common type definitions - rect and colorf are defined in render.h
|
||||
|
||||
// Common conversion functions used across modules
|
||||
JSValue rect2js(JSContext *js, rect r);
|
||||
JSValue vec22js(JSContext *js, HMM_Vec2 v);
|
||||
JSValue vec32js(JSContext *js, HMM_Vec3 v);
|
||||
JSValue vec42js(JSContext *js, HMM_Vec4 v);
|
||||
JSValue quat2js(JSContext *js, HMM_Quat q);
|
||||
JSValue color2js(JSContext *js, colorf c);
|
||||
JSValue number2js(JSContext *js, double d);
|
||||
JSValue angle2js(JSContext *js, double a);
|
||||
|
||||
rect js2rect(JSContext *js, JSValue v);
|
||||
HMM_Vec2 js2vec2(JSContext *js, JSValue v);
|
||||
HMM_Vec3 js2vec3(JSContext *js, JSValue v);
|
||||
HMM_Vec4 js2vec4(JSContext *js, JSValue v);
|
||||
HMM_Quat js2quat(JSContext *js, JSValue v);
|
||||
colorf js2color(JSContext *js, JSValue v);
|
||||
double js2number(JSContext *js, JSValue v);
|
||||
double js2angle(JSContext *js, JSValue v);
|
||||
|
||||
// Forward declaration for MTRand from prosperon.h
|
||||
typedef struct tagMTRand MTRand;
|
||||
|
||||
// Random number generation functions
|
||||
double genRand(MTRand *mrand);
|
||||
int64_t genRandLong(MTRand *mrand);
|
||||
void m_seedRand(MTRand *mrand, uint64_t seed);
|
||||
double rand_range(JSContext *js, double min, double max);
|
||||
|
||||
// Common data structures
|
||||
struct lrtb {
|
||||
float l;
|
||||
float r;
|
||||
float t;
|
||||
float b;
|
||||
};
|
||||
typedef struct lrtb lrtb;
|
||||
typedef struct text_vert text_vert;
|
||||
|
||||
// Common macros for property access
|
||||
#define JS_GETPROP(JS, TARGET, VALUE, PROP, TYPE) {\
|
||||
JSValue __##PROP##__v = JS_GetPropertyStr(JS,VALUE,#PROP); \
|
||||
TARGET = js2##TYPE(JS, __##PROP##__v); \
|
||||
JS_FreeValue(JS,__##PROP##__v); }\
|
||||
|
||||
#define JS_GETATOM(JS, TARGET, VALUE, ATOM, TYPE) {\
|
||||
JSValue __##PROP##__v = JS_GetPropertyStr(JS,VALUE,#ATOM); \
|
||||
TARGET = js2##TYPE(JS, __##PROP##__v); \
|
||||
JS_FreeValue(JS,__##PROP##__v); }\
|
||||
|
||||
// Common conversion functions
|
||||
lrtb js2lrtb(JSContext *js, JSValue v);
|
||||
int js2bool(JSContext *js, JSValue v);
|
||||
JSValue make_gpu_buffer(JSContext *js, void *data, size_t size, int type, int elements, int copy, int index);
|
||||
JSValue make_quad_indices_buffer(JSContext *js, int quads);
|
||||
|
||||
// SDL type conversion functions
|
||||
SDL_Window *js2SDL_Window(JSContext *js, JSValue v);
|
||||
JSValue SDL_Window2js(JSContext *js, SDL_Window *w);
|
||||
|
||||
// X-macro enum definition system for string<->enum conversion
|
||||
#define ENUM_MAPPING_TABLE(ENUM) \
|
||||
static const struct { int value; const char *name; } ENUM##_mapping[]
|
||||
|
||||
#define JS2ENUM(NAME) \
|
||||
int js2##NAME(JSContext *js, JSValue v) { \
|
||||
if (JS_IsNull(v)) return 0; \
|
||||
const char *str = JS_ToCString(js, v); \
|
||||
if (!str) return 0; \
|
||||
for(int i = 0; i < sizeof(NAME##_mapping)/sizeof(NAME##_mapping[0]); i++) \
|
||||
if(!strcmp(NAME##_mapping[i].name, str)) { \
|
||||
JS_FreeCString(js, str); \
|
||||
return NAME##_mapping[i].value; \
|
||||
} \
|
||||
JS_FreeCString(js, str); \
|
||||
return 0; \
|
||||
} \
|
||||
JSValue NAME##2js(JSContext *js, int enumval) { \
|
||||
for(int i = 0; i < sizeof(NAME##_mapping)/sizeof(NAME##_mapping[0]); i++) \
|
||||
if(NAME##_mapping[i].value == enumval) \
|
||||
return JS_NewString(js, NAME##_mapping[i].name); \
|
||||
return JS_NULL; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "qjs_actor.h"
|
||||
#include "jsffi.h"
|
||||
#include "qjs_macros.h"
|
||||
#include "qjs_wota.h"
|
||||
#include "cell.h"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "cell.h"
|
||||
#include "qjs_macros.h"
|
||||
#include "jsffi.h"
|
||||
|
||||
JSC_CCALL(debug_stack_depth, return number2js(js,js_debugger_stack_depth(js)))
|
||||
JSC_CCALL(debug_build_backtrace, return js_debugger_build_backtrace(js,NULL))
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "cell.h"
|
||||
#include "jsffi.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "jsffi.h"
|
||||
#include "cell.h"
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "jsffi.h"
|
||||
#include "cell.h"
|
||||
|
||||
JSC_CCALL(os_gc, JS_RunGC(JS_GetRuntime(js)) )
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "cell.h"
|
||||
#include "jsffi.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
@@ -158,3 +158,43 @@ JS_SetClassProto(js, js_##TYPE##_id, TYPE##_proto); \
|
||||
#define countof(x) (sizeof(x)/sizeof((x)[0]))
|
||||
|
||||
|
||||
// Common macros for property access
|
||||
#define JS_GETPROP(JS, TARGET, VALUE, PROP, TYPE) {\
|
||||
JSValue __##PROP##__v = JS_GetPropertyStr(JS,VALUE,#PROP); \
|
||||
TARGET = js2##TYPE(JS, __##PROP##__v); \
|
||||
JS_FreeValue(JS,__##PROP##__v); }\
|
||||
|
||||
#define JS_GETATOM(JS, TARGET, VALUE, ATOM, TYPE) {\
|
||||
JSValue __##PROP##__v = JS_GetPropertyStr(JS,VALUE,#ATOM); \
|
||||
TARGET = js2##TYPE(JS, __##PROP##__v); \
|
||||
JS_FreeValue(JS,__##PROP##__v); }\
|
||||
|
||||
// X-macro enum definition system for string<->enum conversion
|
||||
#define ENUM_MAPPING_TABLE(ENUM) \
|
||||
static const struct { int value; const char *name; } ENUM##_mapping[]
|
||||
|
||||
#define JS2ENUM(NAME) \
|
||||
int js2##NAME(JSContext *js, JSValue v) { \
|
||||
if (JS_IsNull(v)) return 0; \
|
||||
const char *str = JS_ToCString(js, v); \
|
||||
if (!str) return 0; \
|
||||
for(int i = 0; i < sizeof(NAME##_mapping)/sizeof(NAME##_mapping[0]); i++) \
|
||||
if(!strcmp(NAME##_mapping[i].name, str)) { \
|
||||
JS_FreeCString(js, str); \
|
||||
return NAME##_mapping[i].value; \
|
||||
} \
|
||||
JS_FreeCString(js, str); \
|
||||
return 0; \
|
||||
} \
|
||||
JSValue NAME##2js(JSContext *js, int enumval) { \
|
||||
for(int i = 0; i < sizeof(NAME##_mapping)/sizeof(NAME##_mapping[0]); i++) \
|
||||
if(NAME##_mapping[i].value == enumval) \
|
||||
return JS_NewString(js, NAME##_mapping[i].name); \
|
||||
return JS_NULL; \
|
||||
}
|
||||
|
||||
#define CELL_USE_FUNCS(FUNCS) \
|
||||
JSValue CELL_USE_NAME(JSContext *js) { \
|
||||
JSValue mod = JS_NewObject(js); \
|
||||
JS_SetPropertyFunctionList(js, mod, FUNCS, countof(FUNCS)); \
|
||||
return mod; }
|
||||
|
||||
@@ -1,491 +0,0 @@
|
||||
#include "jsffi.h"
|
||||
#include "qjs_macros.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include "HandmadeMath.h"
|
||||
#include "cell.h"
|
||||
|
||||
|
||||
// Utility function to get number from array index
|
||||
static double js_getnum_uint32(JSContext *js, JSValue v, unsigned int i)
|
||||
{
|
||||
JSValue val = JS_GetPropertyUint32(js,v,i);
|
||||
double ret = js2number(js, val);
|
||||
JS_FreeValue(js,val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Convert JS array to float array
|
||||
static float *js2floats(JSContext *js, JSValue v, size_t *len)
|
||||
{
|
||||
*len = JS_ArrayLength(js,v);
|
||||
float *arr = malloc(sizeof(float)* *len);
|
||||
for (int i = 0; i < *len; i++)
|
||||
arr[i] = js_getnum_uint32(js,v,i);
|
||||
return arr;
|
||||
}
|
||||
|
||||
// Convert float array to JS array
|
||||
static JSValue floats2array(JSContext *js, float *vals, size_t len) {
|
||||
JSValue arr = JS_NewArray(js);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
JS_SetPropertyUint32(js, arr, i, number2js(js, vals[i]));
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
// Calculate vector length
|
||||
static double arr_vec_length(JSContext *js,JSValue v)
|
||||
{
|
||||
int len = JS_ArrayLength(js,v);
|
||||
switch(len) {
|
||||
case 2: return HMM_LenV2(js2vec2(js,v));
|
||||
case 3: return HMM_LenV3(js2vec3(js,v));
|
||||
case 4: return HMM_LenV4(js2vec4(js,v));
|
||||
}
|
||||
|
||||
double sum = 0;
|
||||
for (int i = 0; i < len; i++)
|
||||
sum += pow(js_getnum_uint32(js, v, i), 2);
|
||||
|
||||
return sqrt(sum);
|
||||
}
|
||||
|
||||
|
||||
// GCD helper function
|
||||
static int gcd(int a, int b) {
|
||||
if (b == 0)
|
||||
return a;
|
||||
return gcd(b, a % b);
|
||||
}
|
||||
|
||||
// MATH FUNCTIONS
|
||||
|
||||
|
||||
|
||||
JSC_CCALL(math_rotate,
|
||||
HMM_Vec2 vec = js2vec2(js,argv[0]);
|
||||
double angle = js2angle(js, argv[1]);
|
||||
HMM_Vec2 pivot = JS_IsNull(argv[2]) ? v2zero : js2vec2(js,argv[2]);
|
||||
vec = HMM_SubV2(vec,pivot);
|
||||
|
||||
float r = HMM_LenV2(vec);
|
||||
angle += atan2f(vec.y, vec.x);
|
||||
|
||||
vec.x = r * cosf(angle);
|
||||
vec.y = r * sinf(angle);
|
||||
|
||||
vec = HMM_AddV2(vec,pivot);
|
||||
|
||||
return vec22js(js, vec);
|
||||
)
|
||||
|
||||
JSC_CCALL(math_norm,
|
||||
int len = JS_ArrayLength(js,argv[0]);
|
||||
|
||||
switch(len) {
|
||||
case 2: return vec22js(js,HMM_NormV2(js2vec2(js,argv[0])));
|
||||
case 3: return vec32js(js, HMM_NormV3(js2vec3(js,argv[0])));
|
||||
case 4: return vec42js(js,HMM_NormV4(js2vec4(js,argv[0])));
|
||||
}
|
||||
|
||||
double length = arr_vec_length(js,argv[0]);
|
||||
JSValue newarr = JS_NewArray(js);
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
JS_SetPropertyUint32(js, newarr, i, number2js(js,js_getnum_uint32(js, argv[0],i)/length));
|
||||
|
||||
ret = newarr;
|
||||
)
|
||||
|
||||
JSC_CCALL(math_angle_between,
|
||||
int len = JS_ArrayLength(js,argv[0]);
|
||||
switch(len) {
|
||||
case 2: return angle2js(js,HMM_AngleV2(js2vec2(js,argv[0]), js2vec2(js,argv[1])));
|
||||
case 3: return angle2js(js,HMM_AngleV3(js2vec3(js,argv[0]), js2vec3(js,argv[1])));
|
||||
case 4: return angle2js(js,HMM_AngleV4(js2vec4(js,argv[0]), js2vec4(js,argv[1])));
|
||||
}
|
||||
return JS_ThrowReferenceError(js, "Input array must have a length between 2 and 4.");
|
||||
)
|
||||
|
||||
JSC_CCALL(math_lerp,
|
||||
double s = js2number(js,argv[0]);
|
||||
double f = js2number(js,argv[1]);
|
||||
double t = js2number(js,argv[2]);
|
||||
|
||||
ret = number2js(js,(f-s)*t+s);
|
||||
)
|
||||
|
||||
JSC_CCALL(math_gcd, ret = number2js(js,gcd(js2number(js,argv[0]), js2number(js,argv[1]))); )
|
||||
|
||||
JSC_CCALL(math_lcm,
|
||||
double a = js2number(js,argv[0]);
|
||||
double b = js2number(js,argv[1]);
|
||||
ret = number2js(js,(a*b)/gcd(a,b));
|
||||
)
|
||||
|
||||
JSC_CCALL(math_clamp,
|
||||
double x = js2number(js,argv[0]);
|
||||
double l = js2number(js,argv[1]);
|
||||
double h = js2number(js,argv[2]);
|
||||
return number2js(js,x > h ? h : x < l ? l : x);
|
||||
)
|
||||
|
||||
JSC_CCALL(math_angledist,
|
||||
double a1 = js2number(js,argv[0]);
|
||||
double a2 = js2number(js,argv[1]);
|
||||
a1 = fmod(a1,1);
|
||||
a2 = fmod(a2,1);
|
||||
double dist = a2-a1;
|
||||
if (dist == 0) return number2js(js,dist);
|
||||
if (dist > 0) {
|
||||
if (dist > 0.5) return number2js(js,dist-1);
|
||||
return number2js(js,dist);
|
||||
}
|
||||
|
||||
if (dist < -0.5) return number2js(js,dist+1);
|
||||
|
||||
return number2js(js,dist);
|
||||
)
|
||||
|
||||
JSC_CCALL(math_jitter,
|
||||
double n = js2number(js,argv[0]);
|
||||
double pct = js2number(js,argv[1]);
|
||||
|
||||
return number2js(js,n + (rand_range(js,-pct,pct)*n));
|
||||
)
|
||||
|
||||
JSC_CCALL(math_mean,
|
||||
double len = JS_ArrayLength(js,argv[0]);
|
||||
double sum = 0;
|
||||
for (int i = 0; i < len; i++)
|
||||
sum += js_getnum_uint32(js, argv[0], i);
|
||||
|
||||
return number2js(js,sum/len);
|
||||
)
|
||||
|
||||
JSC_CCALL(math_sum,
|
||||
double sum = 0.0;
|
||||
int len = JS_ArrayLength(js,argv[0]);
|
||||
for (int i = 0; i < len; i++)
|
||||
sum += js_getnum_uint32(js, argv[0], i);
|
||||
|
||||
return number2js(js,sum);
|
||||
)
|
||||
|
||||
JSC_CCALL(math_sigma,
|
||||
int len = JS_ArrayLength(js,argv[0]);
|
||||
double sum = 0;
|
||||
for (int i = 0; i < len; i++)
|
||||
sum += js_getnum_uint32(js, argv[0], i);
|
||||
|
||||
double mean = sum/(double)len;
|
||||
sum = 0;
|
||||
for (int i = 0; i < len; i++)
|
||||
sum += pow(js_getnum_uint32(js, argv[0], i) - mean, 2);
|
||||
|
||||
return number2js(js,sqrt(sum/len));
|
||||
)
|
||||
|
||||
JSC_CCALL(math_median,
|
||||
int len = JS_ArrayLength(js,argv[0]);
|
||||
double vals[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
vals[i] = js_getnum_uint32(js, argv[0], i);
|
||||
|
||||
// Simple bubble sort for median calculation
|
||||
for (int i = 0; i < len-1; i++) {
|
||||
for (int j = 0; j < len-i-1; j++) {
|
||||
if (vals[j] > vals[j+1]) {
|
||||
double temp = vals[j];
|
||||
vals[j] = vals[j+1];
|
||||
vals[j+1] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (len % 2 == 0)
|
||||
return number2js(js,(vals[len/2-1] + vals[len/2]) / 2.0);
|
||||
else
|
||||
return number2js(js,vals[len/2]);
|
||||
)
|
||||
|
||||
JSC_CCALL(math_length, return number2js(js,arr_vec_length(js,argv[0])); )
|
||||
|
||||
JSC_CCALL(math_from_to,
|
||||
double start = js2number(js,argv[0]);
|
||||
double end = js2number(js,argv[1]);
|
||||
double step = js2number(js,argv[2]);
|
||||
int inclusive = JS_ToBool(js,argv[3]);
|
||||
int arr = JS_ToBool(js,argv[4]);
|
||||
|
||||
JSValue jsarr = JS_NewArray(js);
|
||||
int i = 0;
|
||||
for (double val = start; val <= end; val += step) {
|
||||
if (val == end && !inclusive) break;
|
||||
JS_SetPropertyUint32(js, jsarr, i++, number2js(js, val));
|
||||
}
|
||||
|
||||
return jsarr;
|
||||
)
|
||||
|
||||
|
||||
JSC_CCALL(math_dot,
|
||||
size_t alen, blen;
|
||||
float *a = js2floats(js,argv[0], &alen);
|
||||
float *b = js2floats(js,argv[1], &blen);
|
||||
float dot = 0;
|
||||
size_t len = alen < blen? alen : blen;
|
||||
for (size_t i = 0; i < len; i++)
|
||||
dot += a[i] * b[i];
|
||||
|
||||
free(a);
|
||||
free(b);
|
||||
return number2js(js,dot);
|
||||
)
|
||||
|
||||
JSC_CCALL(math_project,
|
||||
size_t alen, blen;
|
||||
float *a = js2floats(js, argv[0], &alen);
|
||||
float *b = js2floats(js, argv[1], &blen);
|
||||
|
||||
if (!a || !b) {
|
||||
free(a);
|
||||
free(b);
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
// We'll work up to the smaller length
|
||||
size_t len = (alen < blen) ? alen : blen;
|
||||
if (len == 0) {
|
||||
free(a);
|
||||
free(b);
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
// Compute dot products: a·b and b·b
|
||||
float ab = 0, bb = 0;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
ab += a[i] * b[i];
|
||||
bb += b[i] * b[i];
|
||||
}
|
||||
|
||||
// Build the result array
|
||||
float *proj = (float*)malloc(sizeof(float) * len);
|
||||
if (!proj) {
|
||||
free(a);
|
||||
free(b);
|
||||
return JS_EXCEPTION; // or some error
|
||||
}
|
||||
|
||||
float scale = (bb != 0.0f) ? (ab / bb) : 0.0f;
|
||||
for (size_t i = 0; i < len; i++)
|
||||
proj[i] = scale * b[i];
|
||||
|
||||
ret = floats2array(js, proj, len);
|
||||
|
||||
free(a);
|
||||
free(b);
|
||||
free(proj);
|
||||
)
|
||||
|
||||
JSC_CCALL(math_midpoint,
|
||||
size_t alen, blen;
|
||||
float *a = js2floats(js, argv[0], &alen);
|
||||
float *b = js2floats(js, argv[1], &blen);
|
||||
|
||||
if (!a || !b) {
|
||||
free(a);
|
||||
free(b);
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
size_t len = (alen < blen) ? alen : blen;
|
||||
if (len == 0) {
|
||||
free(a);
|
||||
free(b);
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
float *m = (float*)malloc(sizeof(float) * len);
|
||||
if (!m) {
|
||||
free(a);
|
||||
free(b);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < len; i++)
|
||||
m[i] = (a[i] + b[i]) * 0.5f;
|
||||
|
||||
ret = floats2array(js, m, len);
|
||||
|
||||
free(a);
|
||||
free(b);
|
||||
free(m);
|
||||
)
|
||||
|
||||
JSC_CCALL(math_reflect,
|
||||
size_t alen, blen;
|
||||
float *a = js2floats(js, argv[0], &alen);
|
||||
float *b = js2floats(js, argv[1], &blen);
|
||||
|
||||
if (!a || !b) {
|
||||
free(a);
|
||||
free(b);
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
size_t len = (alen < blen) ? alen : blen;
|
||||
if (len == 0) {
|
||||
free(a);
|
||||
free(b);
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
// Reflect vector a across normal b
|
||||
// reflection = a - 2 * (a·b) * b
|
||||
float ab = 0, bb = 0;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
ab += a[i] * b[i];
|
||||
bb += b[i] * b[i];
|
||||
}
|
||||
|
||||
float *result = (float*)malloc(sizeof(float) * len);
|
||||
if (!result) {
|
||||
free(a);
|
||||
free(b);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
float scale = (bb != 0.0f) ? (2.0f * ab / bb) : 0.0f;
|
||||
for (size_t i = 0; i < len; i++)
|
||||
result[i] = a[i] - scale * b[i];
|
||||
|
||||
ret = floats2array(js, result, len);
|
||||
|
||||
free(a);
|
||||
free(b);
|
||||
free(result);
|
||||
)
|
||||
|
||||
JSC_CCALL(math_direction,
|
||||
size_t alen, blen;
|
||||
float *a = js2floats(js, argv[0], &alen);
|
||||
float *b = js2floats(js, argv[1], &blen);
|
||||
|
||||
if (!a || !b) {
|
||||
free(a);
|
||||
free(b);
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
size_t len = (alen < blen) ? alen : blen;
|
||||
if (len == 0) {
|
||||
free(a);
|
||||
free(b);
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
// Direction vector from a to b (normalized)
|
||||
float *dir = (float*)malloc(sizeof(float) * len);
|
||||
if (!dir) {
|
||||
free(a);
|
||||
free(b);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
float mag = 0;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
dir[i] = b[i] - a[i];
|
||||
mag += dir[i] * dir[i];
|
||||
}
|
||||
|
||||
mag = sqrtf(mag);
|
||||
if (mag > 0.0f) {
|
||||
for (size_t i = 0; i < len; i++)
|
||||
dir[i] /= mag;
|
||||
}
|
||||
|
||||
ret = floats2array(js, dir, len);
|
||||
|
||||
free(a);
|
||||
free(b);
|
||||
free(dir);
|
||||
)
|
||||
|
||||
JSC_CCALL(math_angle,
|
||||
size_t len;
|
||||
float *v = js2floats(js, argv[0], &len);
|
||||
|
||||
if (!v || len < 2) {
|
||||
free(v);
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
// Return angle in radians for 2D vector
|
||||
ret = number2js(js, atan2f(v[1], v[0]));
|
||||
|
||||
free(v);
|
||||
)
|
||||
|
||||
JSC_CCALL(math_distance,
|
||||
size_t alen, blen;
|
||||
float *a = js2floats(js, argv[0], &alen);
|
||||
float *b = js2floats(js, argv[1], &blen);
|
||||
|
||||
if (!a || !b) {
|
||||
free(a);
|
||||
free(b);
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
size_t len = (alen < blen) ? alen : blen;
|
||||
if (len == 0) {
|
||||
free(a);
|
||||
free(b);
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
float distSq = 0.0f;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
float diff = b[i] - a[i];
|
||||
distSq += diff * diff;
|
||||
}
|
||||
float dist = sqrtf(distSq);
|
||||
|
||||
free(a);
|
||||
free(b);
|
||||
return number2js(js, dist);
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_math_funcs[] = {
|
||||
MIST_FUNC_DEF(math, dot,2),
|
||||
MIST_FUNC_DEF(math, project,2),
|
||||
MIST_FUNC_DEF(math, rotate, 3),
|
||||
MIST_FUNC_DEF(math, midpoint, 2),
|
||||
MIST_FUNC_DEF(math, reflect, 2),
|
||||
MIST_FUNC_DEF(math, distance, 2),
|
||||
MIST_FUNC_DEF(math, direction, 2),
|
||||
MIST_FUNC_DEF(math, angle, 1),
|
||||
MIST_FUNC_DEF(math, norm, 1),
|
||||
MIST_FUNC_DEF(math, angle_between, 2),
|
||||
MIST_FUNC_DEF(math, lerp, 3),
|
||||
MIST_FUNC_DEF(math, gcd, 2),
|
||||
MIST_FUNC_DEF(math, lcm, 2),
|
||||
MIST_FUNC_DEF(math, clamp, 3),
|
||||
MIST_FUNC_DEF(math, angledist, 2),
|
||||
MIST_FUNC_DEF(math, jitter, 2),
|
||||
MIST_FUNC_DEF(math, mean, 1),
|
||||
MIST_FUNC_DEF(math, sum, 1),
|
||||
MIST_FUNC_DEF(math, sigma, 1),
|
||||
MIST_FUNC_DEF(math, median, 1),
|
||||
MIST_FUNC_DEF(math, length, 1),
|
||||
MIST_FUNC_DEF(math, from_to, 5),
|
||||
};
|
||||
|
||||
JSValue js_math_use(JSContext *js) {
|
||||
JSValue mod = JS_NewObject(js);
|
||||
JS_SetPropertyFunctionList(js,mod,js_math_funcs,countof(js_math_funcs));
|
||||
return mod;
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "cell.h"
|
||||
#include "jsffi.h"
|
||||
#include "qjs_common.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <sys/time.h>
|
||||
@@ -271,6 +269,16 @@ JSC_CCALL(os_trace_message,
|
||||
)
|
||||
#endif
|
||||
|
||||
JSC_SCALL(os_system,
|
||||
int err = system(str);
|
||||
ret = number2js(js,err);
|
||||
)
|
||||
|
||||
JSC_SCALL(os_exit,
|
||||
printf("exit\n");
|
||||
exit(0);
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_os_funcs[] = {
|
||||
MIST_FUNC_DEF(os, platform, 0),
|
||||
MIST_FUNC_DEF(os, arch, 0),
|
||||
@@ -284,6 +292,8 @@ static const JSCFunctionListEntry js_os_funcs[] = {
|
||||
MIST_FUNC_DEF(os, mallinfo, 0),
|
||||
MIST_FUNC_DEF(os, buffer2string, 1),
|
||||
MIST_FUNC_DEF(os, frame, 0),
|
||||
MIST_FUNC_DEF(os, system, 1),
|
||||
MIST_FUNC_DEF(os, exit, 0),
|
||||
};
|
||||
|
||||
JSValue js_os_use(JSContext *js) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "qop.h"
|
||||
#include "cell.h"
|
||||
#include "jsffi.h"
|
||||
|
||||
static JSClassID js_qop_archive_class_id;
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "cell.h"
|
||||
#include "jsffi.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
|
||||
@@ -35,30 +35,6 @@ static JSClassDef js_##TYPE##_class = { \
|
||||
JS_FreeValue(js, tmp); \
|
||||
} \
|
||||
|
||||
static double js2number(JSContext *js, JSValue v)
|
||||
{
|
||||
double ret;
|
||||
JS_ToFloat64(js, &ret, v);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static JSValue number2js(JSContext *js, double num)
|
||||
{
|
||||
return JS_NewFloat64(js, num);
|
||||
}
|
||||
|
||||
static int js2bool(JSContext *js, JSValue v)
|
||||
{
|
||||
int b;
|
||||
JS_ToInt32(js, &b, v);
|
||||
return b;
|
||||
}
|
||||
|
||||
static JSValue bool2js(JSContext *js, int b)
|
||||
{
|
||||
return JS_NewBool(js,b);
|
||||
}
|
||||
|
||||
typedef unsigned int voice;
|
||||
|
||||
static Soloud *soloud;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "cell.h"
|
||||
#include "jsffi.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "cell.h"
|
||||
#include "wildmatch.h"
|
||||
#include "jsffi.h"
|
||||
#include "qjs_macros.h"
|
||||
|
||||
JSC_CCALL(wildstar_match,
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
@echo off
|
||||
"%~dp0cell.exe" accio
|
||||
pause
|
||||
Reference in New Issue
Block a user