1646 lines
49 KiB
C
1646 lines
49 KiB
C
#include "jsffi.h"
|
|
#include "font.h"
|
|
#include "datastream.h"
|
|
#include "qjs_sdl.h"
|
|
#include "qjs_io.h"
|
|
#include "qjs_fd.h"
|
|
#include "transform.h"
|
|
#include "stb_ds.h"
|
|
#include "stb_image.h"
|
|
#include "stb_rect_pack.h"
|
|
#define STB_DXT_IMPLEMENTATION
|
|
#include "stb_dxt.h"
|
|
#include "stb_image_write.h"
|
|
#include "string.h"
|
|
#include <assert.h>
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <limits.h>
|
|
#include "render.h"
|
|
#include "model.h"
|
|
#include "HandmadeMath.h"
|
|
#include "par/par_streamlines.h"
|
|
#include "par/par_shapes.h"
|
|
#include <stdint.h>
|
|
#include "cute_aseprite.h"
|
|
#include "cgltf.h"
|
|
#include "prosperon.h"
|
|
|
|
#include "qjs_dmon.h"
|
|
#include "qjs_nota.h"
|
|
#include "qjs_wota.h"
|
|
#include "qjs_enet.h"
|
|
#include "qjs_soloud.h"
|
|
#include "qjs_qr.h"
|
|
#include "qjs_sdl.h"
|
|
#include "qjs_sdl_video.h"
|
|
#include "qjs_math.h"
|
|
#include "qjs_geometry.h"
|
|
#include "qjs_transform.h"
|
|
#include "qjs_sprite.h"
|
|
#include "qjs_io.h"
|
|
#include "qjs_sdl_gpu.h"
|
|
#include "qjs_os.h"
|
|
#include "qjs_actor.h"
|
|
#include "qjs_rtree.h"
|
|
#include "qjs_spline.h"
|
|
#include "qjs_js.h"
|
|
#include "qjs_debug.h"
|
|
#include "qjs_sdl_surface.h"
|
|
#include "qjs_sdl.h"
|
|
#ifndef NSTEAM
|
|
#include "qjs_steam.h"
|
|
#endif
|
|
|
|
#include <signal.h>
|
|
|
|
void gui_input(SDL_Event *e);
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#else
|
|
#include <unistd.h>
|
|
#include <sys/utsname.h>
|
|
#ifdef __linux__
|
|
#include <sys/sysinfo.h>
|
|
#endif
|
|
#endif
|
|
|
|
#include "wildmatch.h"
|
|
|
|
#include "freelist.h"
|
|
|
|
#include "sprite.h"
|
|
|
|
#include <SDL3/SDL.h>
|
|
#include <SDL3/SDL_gpu.h>
|
|
#include <SDL3/SDL_error.h>
|
|
#include <SDL3/SDL_properties.h>
|
|
#include <SDL3/SDL_loadso.h>
|
|
#include <SDL3/SDL_cpuinfo.h>
|
|
|
|
int randombytes(void *buf, size_t n);
|
|
|
|
int trace = 0;
|
|
|
|
// External transform function declarations
|
|
extern JSClassID js_transform_id;
|
|
JSValue transform2js(JSContext *js, transform *t);
|
|
transform *js2transform(JSContext *js, JSValue v);
|
|
|
|
#ifdef __APPLE__
|
|
#include <Accelerate/Accelerate.h>
|
|
//#else
|
|
//#include <cblas.h>
|
|
#endif
|
|
|
|
// Random number generation constants
|
|
#define UPPER_MASK 0x80000000
|
|
#define LOWER_MASK 0x7fffffff
|
|
#define TEMPERING_MASK_B 0x9d2c5680
|
|
#define TEMPERING_MASK_C 0xefc60000
|
|
|
|
// Random number generation functions
|
|
void m_seedRand(MTRand* rand, uint32_t seed) {
|
|
/* set initial seeds to mt[STATE_VECTOR_LENGTH] using the generator
|
|
* from Line 25 of Table 1 in: Donald Knuth, "The Art of Computer
|
|
* Programming," Vol. 2 (2nd Ed.) pp.102.
|
|
*/
|
|
rand->mt[0] = seed & 0xffffffff;
|
|
for(rand->index=1; rand->index<STATE_VECTOR_LENGTH; rand->index++) {
|
|
rand->mt[rand->index] = (6069 * rand->mt[rand->index-1]) & 0xffffffff;
|
|
}
|
|
}
|
|
|
|
uint32_t genRandLong(MTRand* rand) {
|
|
uint32_t y;
|
|
static uint32_t mag[2] = {0x0, 0x9908b0df}; /* mag[x] = x * 0x9908b0df for x = 0,1 */
|
|
if(rand->index >= STATE_VECTOR_LENGTH || rand->index < 0) {
|
|
/* generate STATE_VECTOR_LENGTH words at a time */
|
|
int32_t kk;
|
|
if(rand->index >= STATE_VECTOR_LENGTH+1 || rand->index < 0) {
|
|
m_seedRand(rand, 4357);
|
|
}
|
|
for(kk=0; kk<STATE_VECTOR_LENGTH-STATE_VECTOR_M; kk++) {
|
|
y = (rand->mt[kk] & UPPER_MASK) | (rand->mt[kk+1] & LOWER_MASK);
|
|
rand->mt[kk] = rand->mt[kk+STATE_VECTOR_M] ^ (y >> 1) ^ mag[y & 0x1];
|
|
}
|
|
for(; kk<STATE_VECTOR_LENGTH-1; kk++) {
|
|
y = (rand->mt[kk] & UPPER_MASK) | (rand->mt[kk+1] & LOWER_MASK);
|
|
rand->mt[kk] = rand->mt[kk+(STATE_VECTOR_M-STATE_VECTOR_LENGTH)] ^ (y >> 1) ^ mag[y & 0x1];
|
|
}
|
|
y = (rand->mt[STATE_VECTOR_LENGTH-1] & UPPER_MASK) | (rand->mt[0] & LOWER_MASK);
|
|
rand->mt[STATE_VECTOR_LENGTH-1] = rand->mt[STATE_VECTOR_M-1] ^ (y >> 1) ^ mag[y & 0x1];
|
|
rand->index = 0;
|
|
}
|
|
y = rand->mt[rand->index++];
|
|
y ^= (y >> 11);
|
|
y ^= (y << 7) & TEMPERING_MASK_B;
|
|
y ^= (y << 15) & TEMPERING_MASK_C;
|
|
y ^= (y >> 18);
|
|
return y;
|
|
}
|
|
|
|
double genRand(MTRand* rand) {
|
|
return((double)genRandLong(rand) / (uint32_t)0xffffffff);
|
|
}
|
|
|
|
double rand_range(JSContext *js, double min, double max)
|
|
{
|
|
MTRand *mrand = &((prosperon_rt*)JS_GetContextOpaque(js))->mrand;
|
|
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;
|
|
|
|
|
|
static inline size_t typed_array_bytes(JSTypedArrayEnum type) {
|
|
switch(type) {
|
|
case JS_TYPED_ARRAY_UINT8C:
|
|
case JS_TYPED_ARRAY_INT8:
|
|
case JS_TYPED_ARRAY_UINT8:
|
|
return 1;
|
|
|
|
case JS_TYPED_ARRAY_INT16:
|
|
case JS_TYPED_ARRAY_UINT16:
|
|
return 2;
|
|
|
|
case JS_TYPED_ARRAY_INT32:
|
|
case JS_TYPED_ARRAY_UINT32:
|
|
case JS_TYPED_ARRAY_FLOAT32:
|
|
return 4;
|
|
|
|
case JS_TYPED_ARRAY_BIG_INT64:
|
|
case JS_TYPED_ARRAY_BIG_UINT64:
|
|
case JS_TYPED_ARRAY_FLOAT64:
|
|
return 8;
|
|
|
|
default:
|
|
return 0; // Return 0 for unknown types
|
|
}
|
|
}
|
|
|
|
#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 number2js(JSContext *js, double g) { return JS_NewFloat64(js,g); }
|
|
double js2number(JSContext *js, JSValue v) {
|
|
double g;
|
|
JS_ToFloat64(js, &g, v);
|
|
if (isnan(g)) g = 0;
|
|
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); }\
|
|
|
|
#define JS_SETATOM(JS, TARGET, ATOM, VALUE, TYPE) JS_SetProperty(JS, TARGET, #ATOM, TYPE##2js(JS, VALUE));
|
|
|
|
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);
|
|
JS_FreeValue(js,ret);
|
|
return ret;
|
|
}
|
|
|
|
void free_gpu_buffer(JSRuntime *rt, void *opaque, void *ptr)
|
|
{
|
|
free(ptr);
|
|
}
|
|
|
|
JSValue make_gpu_buffer(JSContext *js, void *data, size_t size, int type, int elements, int copy, int index)
|
|
{
|
|
JSValue tstack[3];
|
|
tstack[1] = JS_UNDEFINED;
|
|
tstack[2] = JS_UNDEFINED;
|
|
if (copy)
|
|
tstack[0] = JS_NewArrayBufferCopy(js,data,size);//, make_gpu_buffer, NULL, 1);
|
|
else
|
|
tstack[0] = JS_NewArrayBuffer(js,data,size,free_gpu_buffer, NULL, 0);
|
|
JSValue ret = JS_NewTypedArray(js, 3, tstack, type);
|
|
JS_SetPropertyStr(js,ret,"stride", number2js(js,typed_array_bytes(type)*elements));
|
|
JS_SetPropertyStr(js,ret,"elen", number2js(js,typed_array_bytes(type)));
|
|
JS_SetPropertyStr(js,ret,"index", JS_NewBool(js,index));
|
|
JS_FreeValue(js,tstack[0]);
|
|
return ret;
|
|
}
|
|
|
|
void *get_gpu_buffer(JSContext *js, JSValue argv, size_t *stride, size_t *size)
|
|
{
|
|
size_t o, len, bytes, msize;
|
|
JSValue buf = JS_GetTypedArrayBuffer(js, argv, &o, &len, &bytes);
|
|
void *data = JS_GetArrayBuffer(js, &msize, buf);
|
|
JS_FreeValue(js,buf);
|
|
if (stride) *stride = js_getnum_str(js, argv, "stride");
|
|
if (size) *size = msize;
|
|
return data;
|
|
}
|
|
|
|
JSValue make_quad_indices_buffer(JSContext *js, int quads)
|
|
{
|
|
prosperon_rt *rt = JS_GetContextOpaque(js);
|
|
int count = quads*6;
|
|
if (!JS_IsUndefined(rt->idx_buffer) && rt->idx_count >= count)
|
|
return JS_DupValue(js,rt->idx_buffer);
|
|
|
|
int verts = quads*4;
|
|
uint16_t *indices = malloc(sizeof(*indices)*count);
|
|
for (int i = 0, v = 0; v < verts; i +=6, v += 4) {
|
|
indices[i] = v;
|
|
indices[i+1] = v+2;
|
|
indices[i+2] = v+1;
|
|
indices[i+3] = v+2;
|
|
indices[i+4] = v+3;
|
|
indices[i+5] = v+1;
|
|
}
|
|
|
|
if (!JS_IsUndefined(rt->idx_buffer))
|
|
JS_FreeValue(js,rt->idx_buffer);
|
|
|
|
rt->idx_buffer = make_gpu_buffer(js,indices, sizeof(*indices)*count, JS_TYPED_ARRAY_UINT16, 1,0,1);
|
|
rt->idx_count = count;
|
|
return JS_DupValue(js,rt->idx_buffer);
|
|
}
|
|
|
|
JSValue quads_to_mesh(JSContext *js, text_vert *buffer)
|
|
{
|
|
size_t verts = arrlen(buffer);
|
|
|
|
HMM_Vec2 *pos = malloc(arrlen(buffer)*sizeof(HMM_Vec2));
|
|
HMM_Vec2 *uv = malloc(arrlen(buffer)*sizeof(HMM_Vec2));
|
|
HMM_Vec4 *color = malloc(arrlen(buffer)*sizeof(HMM_Vec4));
|
|
|
|
for (int i = 0; i < arrlen(buffer); i++) {
|
|
pos[i] = buffer[i].pos;
|
|
uv[i] = buffer[i].uv;
|
|
color[i] = buffer[i].color;
|
|
}
|
|
|
|
JSValue jspos = make_gpu_buffer(js, pos, sizeof(HMM_Vec2)*arrlen(buffer), JS_TYPED_ARRAY_FLOAT32, 2,0,0);
|
|
JSValue jsuv = make_gpu_buffer(js, uv, sizeof(HMM_Vec2)*arrlen(buffer), JS_TYPED_ARRAY_FLOAT32, 2,0,0);
|
|
JSValue jscolor = make_gpu_buffer(js, color, sizeof(HMM_Vec4)*arrlen(buffer), JS_TYPED_ARRAY_FLOAT32, 4,0,0);
|
|
|
|
size_t quads = verts/4;
|
|
size_t count = verts/2*3;
|
|
JSValue jsidx = make_quad_indices_buffer(js, quads);
|
|
|
|
JSValue ret = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, ret, "pos", jspos);
|
|
JS_SetPropertyStr(js, ret, "uv", jsuv);
|
|
JS_SetPropertyStr(js, ret, "color", jscolor);
|
|
JS_SetPropertyStr(js, ret, "indices", jsidx);
|
|
JS_SetPropertyStr(js, ret, "vertices", number2js(js, verts));
|
|
JS_SetPropertyStr(js,ret,"num_indices", number2js(js,count));
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifndef _WIN32
|
|
#include <sys/resource.h>
|
|
#endif
|
|
|
|
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);
|
|
JS_FreeCString(js, str);
|
|
return ret;
|
|
}
|
|
|
|
#include "qjs_macros.h"
|
|
|
|
void SDL_GPUCommandBuffer_free(JSRuntime *rt, SDL_GPUCommandBuffer *c)
|
|
{
|
|
|
|
}
|
|
|
|
QJSCLASS(font,)
|
|
QJSCLASS(datastream,)
|
|
|
|
JSValue angle2js(JSContext *js,double g) {
|
|
return number2js(js,g*HMM_RadToTurn);
|
|
}
|
|
|
|
double js2angle(JSContext *js,JSValue v) {
|
|
double n = js2number(js,v);
|
|
return n * HMM_TurnToRad;
|
|
}
|
|
|
|
typedef HMM_Vec4 colorf;
|
|
|
|
colorf js2color(JSContext *js,JSValue v) {
|
|
if (JS_IsUndefined(v)) return (colorf){1,1,1,1};
|
|
JSValue c[4];
|
|
for (int i = 0; i < 4; i++) c[i] = JS_GetPropertyUint32(js,v,i);
|
|
float a = JS_IsUndefined(c[3]) ? 1.0 : js2number(js,c[3]);
|
|
colorf color = {
|
|
.r = js2number(js,c[0]),
|
|
.g = js2number(js,c[1]),
|
|
.b = js2number(js,c[2]),
|
|
.a = a,
|
|
};
|
|
|
|
for (int i = 0; i < 4; i++) JS_FreeValue(js,c[i]);
|
|
|
|
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;
|
|
v2.X = js_getnum_uint32(js,v,0);
|
|
v2.Y = js_getnum_uint32(js,v,1);
|
|
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_IsUndefined(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_IsUndefined(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;
|
|
}
|
|
|
|
rect transform_rect(SDL_Renderer *ren, rect in, HMM_Mat3 *t)
|
|
{
|
|
HMM_Vec3 bottom_left = (HMM_Vec3){in.x,in.y,1.0};
|
|
HMM_Vec3 transformed_bl = HMM_MulM3V3(*t, bottom_left);
|
|
in.x = transformed_bl.x;
|
|
in.y = transformed_bl.y;
|
|
in.y = in.y - in.h; // should be done for any platform that draws rectangles from top left
|
|
return in;
|
|
}
|
|
|
|
HMM_Vec2 transform_point(SDL_Renderer *ren, HMM_Vec2 in, HMM_Mat3 *t)
|
|
{
|
|
rect logical;
|
|
SDL_GetRenderLogicalPresentationRect(ren, &logical);
|
|
in.y *= -1;
|
|
in.y += logical.h;
|
|
in.x -= t->Columns[2].x;
|
|
in.y -= t->Columns[2].y;
|
|
return in;
|
|
}
|
|
|
|
JSValue rect2js(JSContext *js,rect rect) {
|
|
JSValue obj = JS_NewObject(js);
|
|
JS_SETATOM(js, obj, x, rect.x, number);
|
|
JS_SETATOM(js, obj, y, rect.y, number);
|
|
JS_SETATOM(js, obj, width, rect.w, number);
|
|
JS_SETATOM(js, obj, height, rect.h, number);
|
|
return obj;
|
|
}
|
|
|
|
JSValue ints2js(JSContext *js,int *ints) {
|
|
JSValue arr = JS_NewArray(js);
|
|
for (int i = 0; i < arrlen(ints); i++)
|
|
JS_SetPropertyUint32(js, arr,i, number2js(js,ints[i]));
|
|
|
|
return arr;
|
|
}
|
|
|
|
int vec_between(HMM_Vec2 p, HMM_Vec2 a, HMM_Vec2 b) {
|
|
HMM_Vec2 n;
|
|
n.x = b.x - a.x;
|
|
n.y = b.y - a.y;
|
|
n = HMM_NormV2(n);
|
|
|
|
return HMM_DotV2(n, HMM_SubV2(p,a)) > 0 && HMM_DotV2(HMM_MulV2F(n, -1), HMM_SubV2(p,b)) > 0;
|
|
}
|
|
|
|
/* Determines between which two points in 'segs' point 'p' falls.
|
|
0 indicates 'p' comes before the first point.
|
|
arrlen(segs) indicates it comes after the last point.
|
|
*/
|
|
int point2segindex(HMM_Vec2 p, HMM_Vec2 *segs, double slop) {
|
|
float shortest = slop < 0 ? INFINITY : slop;
|
|
int best = -1;
|
|
|
|
for (int i = 0; i < arrlen(segs) - 1; i++) {
|
|
float a = (segs[i + 1].y - segs[i].y) / (segs[i + 1].x - segs[i].x);
|
|
float c = segs[i].y - (a * segs[i].x);
|
|
float b = -1;
|
|
|
|
float dist = fabsf(a * p.x + b * p.y + c) / sqrt(pow(a, 2) + 1);
|
|
|
|
if (dist > shortest) continue;
|
|
|
|
int between = vec_between(p, segs[i], segs[i + 1]);
|
|
|
|
if (between) {
|
|
shortest = dist;
|
|
best = i + 1;
|
|
} else {
|
|
if (i == 0 && HMM_DistV2(p,segs[0]) < slop) {
|
|
shortest = dist;
|
|
best = i;
|
|
} else if (i == arrlen(segs) - 2 && HMM_DistV2(p,arrlast(segs)) < slop) {
|
|
shortest = dist;
|
|
best = arrlen(segs);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (best == 1) {
|
|
HMM_Vec2 n;
|
|
n.x = segs[1].x - segs[0].x;
|
|
n.y = segs[1].y - segs[0].y;
|
|
n = HMM_NormV2(n);
|
|
if (HMM_DotV2(n, HMM_SubV2(p,segs[0])) < 0 ){
|
|
if (HMM_DistV2(p, segs[0]) >= slop)
|
|
best = -1;
|
|
else
|
|
best = 0;
|
|
}
|
|
}
|
|
|
|
if (best == arrlen(segs) - 1) {
|
|
HMM_Vec2 n;
|
|
n.x = segs[best - 1].x - segs[best].x;
|
|
n.y = segs[best - 1].y - segs[best - 1].y;
|
|
n = HMM_NormV2(n);
|
|
|
|
if (HMM_DotV2(n, HMM_SubV2(p, segs[best])) < 0) {
|
|
if (HMM_DistV2(p, segs[best]) >= slop)
|
|
best = -1;
|
|
else
|
|
best = arrlen(segs);
|
|
}
|
|
}
|
|
|
|
return best;
|
|
}
|
|
|
|
JSC_CCALL(os_make_text_buffer,
|
|
const char *s = JS_ToCString(js, argv[0]);
|
|
rect rectpos = js2rect(js,argv[1]);
|
|
float size = js2number(js,argv[2]);
|
|
font *f = js2font(js,argv[5]);
|
|
if (!size) size = f->height;
|
|
colorf c = js2color(js,argv[3]);
|
|
int wrap = js2number(js,argv[4]);
|
|
HMM_Vec2 startpos = {.x = rectpos.x, .y = rectpos.y };
|
|
text_vert *buffer = renderText(s, startpos, f, size, c, wrap);
|
|
ret = quads_to_mesh(js,buffer);
|
|
JS_FreeCString(js, s);
|
|
arrfree(buffer);
|
|
)
|
|
|
|
JSValue js_util_camera_globals(JSContext *js, JSValue self, int argc, JSValue *argv)
|
|
{
|
|
JSValue camera = argv[0];
|
|
if(JS_IsUndefined(camera)) return JS_UNDEFINED;
|
|
|
|
HMM_Vec2 size; HMM_Vec3 pos; HMM_Quat rotation;
|
|
double fov = 0; int ortho; double near_z = 0; double far_z = 0;
|
|
HMM_Vec2 anchor;
|
|
|
|
JS_GETPROP(js, size, camera, size, vec2)
|
|
JS_GETPROP(js, fov, camera, fov, number)
|
|
JS_GETPROP(js, ortho, camera, ortho, bool)
|
|
JS_GETPROP(js, near_z, camera, near_z, number)
|
|
JS_GETPROP(js, far_z, camera, far_z, number)
|
|
JS_GETPROP(js, anchor, camera, anchor, vec2)
|
|
JS_GETPROP(js, pos, camera, pos, vec3)
|
|
JS_GETPROP(js, rotation, camera, rotation, quat)
|
|
|
|
rotation.w = 1;
|
|
|
|
HMM_Mat4 proj, view;
|
|
|
|
if(ortho) {
|
|
float left = -anchor.x * size.x;
|
|
float bottom = -anchor.y * size.y;
|
|
float right = left + size.x;
|
|
float top = bottom + size.y;
|
|
proj = HMM_Orthographic_RH_NO(left, right, bottom, top, -1.0f, 1.0f);
|
|
} else {
|
|
proj = HMM_Perspective_RH_NO(fov, size.x/size.y, near_z, far_z);
|
|
proj.Columns[1] = HMM_MulV4F(proj.Columns[1], -1.0f);
|
|
}
|
|
|
|
view = HMM_MulM4(
|
|
HMM_InvTranslate(HMM_Translate(pos)),
|
|
HMM_InvRotate (HMM_QToM4(rotation))
|
|
);
|
|
|
|
JSValue data = JS_NewObject(js);
|
|
|
|
HMM_Mat4 world_to_projection = HMM_MulM4(proj, view);
|
|
HMM_Mat4 projection_to_world = HMM_InvGeneralM4(world_to_projection);
|
|
HMM_Vec3 camera_dir_world = HMM_NormV3(
|
|
HMM_QVRot((HMM_Vec3){0,0,-1}, rotation)
|
|
);
|
|
|
|
JS_SetPropertyStr(js, data, "world_to_projection",
|
|
JS_NewArrayBufferCopy(js, world_to_projection.em,
|
|
sizeof(float)*16));
|
|
JS_SetPropertyStr(js, data, "projection_to_world",
|
|
JS_NewArrayBufferCopy(js, projection_to_world.em,
|
|
sizeof(float)*16));
|
|
JS_SetPropertyStr(js, data, "world_to_view",
|
|
JS_NewArrayBufferCopy(js, view.em, sizeof(float)*16));
|
|
JS_SetPropertyStr(js, data, "view_to_projection",
|
|
JS_NewArrayBufferCopy(js, proj.em, sizeof(float)*16));
|
|
|
|
JS_SetPropertyStr(js, data, "camera_pos_world", vec32js(js, pos));
|
|
JS_SetPropertyStr(js, data, "camera_dir_world", vec32js(js, camera_dir_world));
|
|
JS_SetPropertyStr(js, data, "render_size", vec22js(js, size));
|
|
JS_SetPropertyStr(js, data, "viewport_size", vec22js(js, (HMM_Vec2){0.5,0.5}));
|
|
JS_SetPropertyStr(js, data, "viewport_offset", vec22js(js, (HMM_Vec2){0,0}));
|
|
JS_SetPropertyStr(js, data, "viewport_min_z", number2js(js, near_z));
|
|
JS_SetPropertyStr(js, data, "viewport_max_z", number2js(js, far_z));
|
|
|
|
return data;
|
|
}
|
|
|
|
|
|
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_UNDEFINED; }
|
|
|
|
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_UNDEFINED; }
|
|
|
|
JSValue js_array_get_xy(JSContext *js, JSValue self)
|
|
{
|
|
JSValue arr = JS_NewArray(js);
|
|
JS_SetPropertyUint32(js,arr,0,JS_GetPropertyUint32(js,self,0));
|
|
JS_SetPropertyUint32(js,arr,1,JS_GetPropertyUint32(js,self,1));
|
|
return arr;
|
|
}
|
|
|
|
JSValue js_array_set_xy(JSContext *js, JSValue self, JSValue v)
|
|
{
|
|
JS_SetPropertyUint32(js,self,0,JS_GetPropertyUint32(js,v,0));
|
|
JS_SetPropertyUint32(js,self,1,JS_GetPropertyUint32(js,v,1));
|
|
return JS_UNDEFINED;
|
|
}
|
|
|
|
// 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_UNDEFINED; }
|
|
|
|
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_UNDEFINED; }
|
|
|
|
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_UNDEFINED; }
|
|
|
|
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_UNDEFINED; }
|
|
|
|
// Multi-value accessors
|
|
|
|
JSValue js_array_get_rgb(JSContext *js, JSValue self)
|
|
{
|
|
JSValue arr = JS_NewArray(js);
|
|
JS_SetPropertyUint32(js, arr, 0, JS_GetPropertyUint32(js, self, 0));
|
|
JS_SetPropertyUint32(js, arr, 1, JS_GetPropertyUint32(js, self, 1));
|
|
JS_SetPropertyUint32(js, arr, 2, JS_GetPropertyUint32(js, self, 2));
|
|
return arr;
|
|
}
|
|
|
|
JSValue js_array_set_rgb(JSContext *js, JSValue self, JSValue val)
|
|
{
|
|
JS_SetPropertyUint32(js, self, 0, JS_GetPropertyUint32(js, val, 0));
|
|
JS_SetPropertyUint32(js, self, 1, JS_GetPropertyUint32(js, val, 1));
|
|
JS_SetPropertyUint32(js, self, 2, JS_GetPropertyUint32(js, val, 2));
|
|
return JS_UNDEFINED;
|
|
}
|
|
|
|
JSValue js_array_get_rgba(JSContext *js, JSValue self)
|
|
{
|
|
JSValue arr = JS_NewArray(js);
|
|
JS_SetPropertyUint32(js, arr, 0, JS_GetPropertyUint32(js, self, 0));
|
|
JS_SetPropertyUint32(js, arr, 1, JS_GetPropertyUint32(js, self, 1));
|
|
JS_SetPropertyUint32(js, arr, 2, JS_GetPropertyUint32(js, self, 2));
|
|
JS_SetPropertyUint32(js, arr, 3, JS_GetPropertyUint32(js, self, 3));
|
|
return arr;
|
|
}
|
|
|
|
JSValue js_array_set_rgba(JSContext *js, JSValue self, JSValue val)
|
|
{
|
|
JS_SetPropertyUint32(js, self, 0, JS_GetPropertyUint32(js, val, 0));
|
|
JS_SetPropertyUint32(js, self, 1, JS_GetPropertyUint32(js, val, 1));
|
|
JS_SetPropertyUint32(js, self, 2, JS_GetPropertyUint32(js, val, 2));
|
|
JS_SetPropertyUint32(js, self, 3, JS_GetPropertyUint32(js, val, 3));
|
|
return JS_UNDEFINED;
|
|
}
|
|
|
|
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("xy", js_array_get_xy, js_array_set_xy),
|
|
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),
|
|
JS_CGETSET_DEF("rgb", js_array_get_rgb, js_array_set_rgb),
|
|
JS_CGETSET_DEF("rgba", js_array_get_rgba, js_array_set_rgba),
|
|
};
|
|
|
|
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),
|
|
};
|
|
|
|
JSC_CCALL(os_guid,
|
|
SDL_GUID guid;
|
|
randombytes(guid.data, 16);
|
|
|
|
char guid_str[33];
|
|
|
|
SDL_GUIDToString(guid, guid_str, 33);
|
|
|
|
return JS_NewString(js,guid_str);
|
|
)
|
|
|
|
JSC_SCALL(console_print, printf("%s", str); )
|
|
|
|
static const JSCFunctionListEntry js_console_funcs[] = {
|
|
MIST_FUNC_DEF(console,print,1),
|
|
};
|
|
|
|
JSC_CCALL(datastream_time, return number2js(js,plm_get_time(js2datastream(js,self)->plm)); )
|
|
JSC_CCALL(datastream_seek, ds_seek(js2datastream(js,self), js2number(js,argv[0])))
|
|
JSC_CCALL(datastream_advance, ds_advance(js2datastream(js,self), js2number(js,argv[0])))
|
|
JSC_CCALL(datastream_duration, return number2js(js,ds_length(js2datastream(js,self))))
|
|
JSC_CCALL(datastream_framerate, return number2js(js,plm_get_framerate(js2datastream(js,self)->plm)))
|
|
|
|
JSC_GETSET_CALLBACK(datastream, callback)
|
|
|
|
static const JSCFunctionListEntry js_datastream_funcs[] = {
|
|
MIST_FUNC_DEF(datastream, time, 0),
|
|
MIST_FUNC_DEF(datastream, seek, 1),
|
|
MIST_FUNC_DEF(datastream, advance, 1),
|
|
MIST_FUNC_DEF(datastream, duration, 0),
|
|
MIST_FUNC_DEF(datastream, framerate, 0),
|
|
CGETSET_ADD(datastream, callback),
|
|
};
|
|
|
|
JSC_GETSET(font, linegap, number)
|
|
JSC_GET(font, height, number)
|
|
JSC_GET(font, ascent, number)
|
|
JSC_GET(font, descent, number)
|
|
|
|
JSC_SCALL(font_text_size,
|
|
font *f = js2font(js,self);
|
|
float size = js2number(js,argv[0]);
|
|
if (!size) size = f->height;
|
|
float letterSpacing = js2number(js,argv[1]);
|
|
float wrap = js2number(js,argv[2]);
|
|
ret = vec22js(js,measure_text(str, f, size, letterSpacing, wrap));
|
|
)
|
|
|
|
static const JSCFunctionListEntry js_font_funcs[] = {
|
|
CGETSET_ADD(font, linegap),
|
|
MIST_GET(font, height),
|
|
MIST_GET(font, ascent),
|
|
MIST_GET(font, descent),
|
|
MIST_FUNC_DEF(font, text_size, 3),
|
|
};
|
|
|
|
// input: (encoded image data of jpg, png, bmp, tiff)
|
|
JSC_CCALL(os_make_texture,
|
|
size_t len;
|
|
void *raw = JS_GetArrayBuffer(js, &len, argv[0]);
|
|
if (!raw) return JS_ThrowReferenceError(js, "could not load texture with array buffer");
|
|
|
|
int n, width, height;
|
|
void *data = stbi_load_from_memory(raw, len, &width, &height, &n, 4);
|
|
|
|
if (!data)
|
|
return JS_ThrowReferenceError(js, "no known image type from pixel data: %s", stbi_failure_reason());
|
|
|
|
if (width <= 0 || height <= 0) {
|
|
free(data);
|
|
return JS_ThrowReferenceError(js, "decoded image has invalid size: %dx%d", width, height);
|
|
}
|
|
|
|
int pitch = width*4;
|
|
size_t pixels_size = pitch * height;
|
|
|
|
// Create JS object with surface data
|
|
JSValue obj = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, obj, "width", JS_NewInt32(js, width));
|
|
JS_SetPropertyStr(js, obj, "height", JS_NewInt32(js, height));
|
|
JS_SetPropertyStr(js, obj, "format", JS_NewString(js, "rgba32"));
|
|
JS_SetPropertyStr(js, obj, "pitch", JS_NewInt32(js, pitch));
|
|
JS_SetPropertyStr(js, obj, "pixels", JS_NewArrayBufferCopy(js, data, pixels_size));
|
|
|
|
free(data);
|
|
ret = obj;
|
|
)
|
|
|
|
|
|
// input: (gif image data)
|
|
JSC_CCALL(os_make_gif,
|
|
size_t rawlen;
|
|
void *raw = JS_GetArrayBuffer(js, &rawlen, argv[0]);
|
|
if (!raw) return JS_ThrowReferenceError(js, "could not load gif from supplied array buffer");
|
|
|
|
int n;
|
|
int frames;
|
|
int *delays;
|
|
int width;
|
|
int height;
|
|
void *pixels = stbi_load_gif_from_memory(raw, rawlen, &delays, &width, &height, &frames, &n, 4);
|
|
|
|
JSValue gif = JS_NewObject(js);
|
|
ret = gif;
|
|
|
|
if (frames == 1) {
|
|
// still image, so return surface data object
|
|
JSValue surfData = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, surfData, "width", JS_NewInt32(js, width));
|
|
JS_SetPropertyStr(js, surfData, "height", JS_NewInt32(js, height));
|
|
JS_SetPropertyStr(js, surfData, "format", JS_NewString(js, "rgba32"));
|
|
JS_SetPropertyStr(js, surfData, "pitch", JS_NewInt32(js, width*4));
|
|
JS_SetPropertyStr(js, surfData, "pixels", JS_NewArrayBufferCopy(js, pixels, width*height*4));
|
|
JS_SetPropertyStr(js, gif, "surface", surfData);
|
|
return gif;
|
|
}
|
|
|
|
JSValue delay_arr = JS_NewArray(js);
|
|
|
|
for (int i = 0; i < frames; i++) {
|
|
JSValue frame = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, frame, "time", number2js(js,(float)delays[i]/1000.0));
|
|
|
|
// Create surface data object instead of SDL_Surface
|
|
JSValue surfData = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, surfData, "width", JS_NewInt32(js, width));
|
|
JS_SetPropertyStr(js, surfData, "height", JS_NewInt32(js, height));
|
|
JS_SetPropertyStr(js, surfData, "format", JS_NewString(js, "rgba32"));
|
|
JS_SetPropertyStr(js, surfData, "pitch", JS_NewInt32(js, width*4));
|
|
|
|
void *frame_pixels = (unsigned char*)pixels+(width*height*4*i);
|
|
JS_SetPropertyStr(js, surfData, "pixels", JS_NewArrayBufferCopy(js, frame_pixels, width*height*4));
|
|
|
|
JS_SetPropertyStr(js, frame, "surface", surfData);
|
|
JS_SetPropertyUint32(js, delay_arr, i, frame);
|
|
}
|
|
|
|
JS_SetPropertyStr(js, gif, "frames", delay_arr);
|
|
|
|
CLEANUP:
|
|
free(delays);
|
|
free(pixels);
|
|
)
|
|
|
|
JSValue aseframe2js(JSContext *js, ase_frame_t aframe)
|
|
{
|
|
JSValue frame = JS_NewObject(js);
|
|
|
|
// Create surface data object instead of SDL_Surface
|
|
JSValue surfData = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, surfData, "width", JS_NewInt32(js, aframe.ase->w));
|
|
JS_SetPropertyStr(js, surfData, "height", JS_NewInt32(js, aframe.ase->h));
|
|
JS_SetPropertyStr(js, surfData, "format", JS_NewString(js, "rgba32"));
|
|
JS_SetPropertyStr(js, surfData, "pitch", JS_NewInt32(js, aframe.ase->w*4));
|
|
JS_SetPropertyStr(js, surfData, "pixels", JS_NewArrayBufferCopy(js, aframe.pixels, aframe.ase->w*aframe.ase->h*4));
|
|
|
|
JS_SetPropertyStr(js, frame, "surface", surfData);
|
|
JS_SetPropertyStr(js, frame, "time", number2js(js,(float)aframe.duration_milliseconds/1000.0));
|
|
return frame;
|
|
}
|
|
|
|
// input: (aseprite data)
|
|
JSC_CCALL(os_make_aseprite,
|
|
size_t rawlen;
|
|
void *raw = JS_GetArrayBuffer(js,&rawlen,argv[0]);
|
|
|
|
ase_t *ase = cute_aseprite_load_from_memory(raw, rawlen, NULL);
|
|
|
|
if (!ase)
|
|
return JS_ThrowReferenceError(js, "could not load aseprite from supplied array buffer: %s", aseprite_GetError());
|
|
|
|
if (ase->tag_count == 0) {
|
|
// we're dealing with a single frame image, or single animation
|
|
if (ase->frame_count == 1) {
|
|
JSValue obj = aseframe2js(js,ase->frames[0]);
|
|
cute_aseprite_free(ase);
|
|
return obj;
|
|
}
|
|
}
|
|
|
|
JSValue obj = JS_NewObject(js);
|
|
|
|
for (int t = 0; t < ase->tag_count; t++) {
|
|
ase_tag_t tag = ase->tags[t];
|
|
JSValue anim = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, anim, "repeat", number2js(js,tag.repeat));
|
|
switch(tag.loop_animation_direction) {
|
|
case ASE_ANIMATION_DIRECTION_FORWARDS:
|
|
JS_SetPropertyStr(js, anim, "loop", JS_NewString(js,"forward"));
|
|
break;
|
|
case ASE_ANIMATION_DIRECTION_BACKWORDS:
|
|
JS_SetPropertyStr(js, anim, "loop", JS_NewString(js,"backward"));
|
|
break;
|
|
case ASE_ANIMATION_DIRECTION_PINGPONG:
|
|
JS_SetPropertyStr(js, anim, "loop", JS_NewString(js,"pingpong"));
|
|
break;
|
|
}
|
|
|
|
int _frame = 0;
|
|
JSValue frames = JS_NewArray(js);
|
|
for (int f = tag.from_frame; f <= tag.to_frame; f++) {
|
|
JSValue frame = aseframe2js(js,ase->frames[f]);
|
|
JS_SetPropertyUint32(js, frames, _frame, frame);
|
|
_frame++;
|
|
}
|
|
JS_SetPropertyStr(js, anim, "frames", frames);
|
|
JS_SetPropertyStr(js, obj, tag.name, anim);
|
|
}
|
|
|
|
ret = obj;
|
|
|
|
cute_aseprite_free(ase);
|
|
)
|
|
|
|
JSC_CCALL(os_make_font,
|
|
size_t len;
|
|
void *data = JS_GetArrayBuffer(js,&len,argv[0]);
|
|
if (!data) return JS_ThrowReferenceError(js, "could not get array buffer data");
|
|
font *f = MakeFont(data, len, js2number(js,argv[1]));
|
|
if (!f) return JS_ThrowReferenceError(js, "could not create font");
|
|
ret = font2js(js,f);
|
|
|
|
// Create surface data object for the font's atlas
|
|
if (f->surface) {
|
|
JSValue surfData = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, surfData, "width", JS_NewInt32(js, f->surface->w));
|
|
JS_SetPropertyStr(js, surfData, "height", JS_NewInt32(js, f->surface->h));
|
|
JS_SetPropertyStr(js, surfData, "format", pixelformat2js(js, f->surface->format));
|
|
JS_SetPropertyStr(js, surfData, "pitch", JS_NewInt32(js, f->surface->pitch));
|
|
|
|
// Lock surface if needed
|
|
int locked = 0;
|
|
if (SDL_MUSTLOCK(f->surface)) {
|
|
if (SDL_LockSurface(f->surface) < 0)
|
|
return JS_ThrowInternalError(js, "Lock surface failed: %s", SDL_GetError());
|
|
locked = 1;
|
|
}
|
|
|
|
size_t byte_size = f->surface->pitch * f->surface->h;
|
|
JS_SetPropertyStr(js, surfData, "pixels", JS_NewArrayBufferCopy(js, f->surface->pixels, byte_size));
|
|
|
|
if (locked)
|
|
SDL_UnlockSurface(f->surface);
|
|
|
|
JS_SetPropertyStr(js, ret, "surface", surfData);
|
|
}
|
|
)
|
|
|
|
JSC_SCALL(os_system, ret = number2js(js,system(str)); )
|
|
|
|
JSValue make_color_buffer(JSContext *js, colorf c, int verts)
|
|
{
|
|
HMM_Vec4 *colordata = malloc(sizeof(*colordata)*verts);
|
|
for (int i = 0; i < verts; i++)
|
|
colordata[i] = c;
|
|
|
|
return make_gpu_buffer(js, colordata, sizeof(*colordata)*verts, JS_TYPED_ARRAY_FLOAT32, 4, 0, 0);
|
|
}
|
|
|
|
JSC_CCALL(os_make_line_prim,
|
|
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, JS_TYPED_ARRAY_FLOAT32, 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), JS_TYPED_ARRAY_FLOAT32,2,1,0));
|
|
JS_SetPropertyStr(js,prim,"vertices", number2js(js,m->num_vertices));
|
|
JS_SetPropertyStr(js,prim,"color",make_color_buffer(js,js2color(js,argv[4]), 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 void render_frame(plm_t *mpeg, plm_frame_t *frame, datastream *ds) {
|
|
if (JS_IsUndefined(ds->callback)) return;
|
|
uint8_t *rgb = malloc(frame->height*frame->width*4);
|
|
memset(rgb,255,frame->height*frame->width*4);
|
|
plm_frame_to_rgba(frame, rgb, frame->width*4);
|
|
|
|
// Create surface data object instead of SDL_Surface
|
|
JSValue surfData = JS_NewObject(ds->js);
|
|
JS_SetPropertyStr(ds->js, surfData, "width", JS_NewInt32(ds->js, frame->width));
|
|
JS_SetPropertyStr(ds->js, surfData, "height", JS_NewInt32(ds->js, frame->height));
|
|
JS_SetPropertyStr(ds->js, surfData, "format", JS_NewString(ds->js, "rgba32"));
|
|
JS_SetPropertyStr(ds->js, surfData, "pitch", JS_NewInt32(ds->js, frame->width*4));
|
|
JS_SetPropertyStr(ds->js, surfData, "pixels", JS_NewArrayBufferCopy(ds->js, rgb, frame->height*frame->width*4));
|
|
|
|
JSValue s[1];
|
|
s[0] = surfData;
|
|
JSValue cb = JS_DupValue(ds->js,ds->callback);
|
|
JSValue ret = JS_Call(ds->js, cb, JS_UNDEFINED, 1, s);
|
|
JS_FreeValue(ds->js,cb);
|
|
free(rgb);
|
|
uncaught_exception(ds->js,ret);
|
|
}
|
|
|
|
JSC_CCALL(os_make_video,
|
|
size_t len;
|
|
void *data = JS_GetArrayBuffer(js,&len,argv[0]);
|
|
datastream *ds = ds_openvideo(data, len);
|
|
if (!ds) return JS_ThrowReferenceError(js, "Video file was not valid.");
|
|
ds->js = js;
|
|
ds->callback = JS_UNDEFINED;
|
|
plm_set_video_decode_callback(ds->plm, render_frame, ds);
|
|
return datastream2js(js,ds);
|
|
)
|
|
|
|
JSC_CCALL(os_rectpack,
|
|
int width = js2number(js,argv[0]);
|
|
int height = js2number(js,argv[1]);
|
|
int num = JS_ArrayLength(js,argv[2]);
|
|
stbrp_context ctx[1];
|
|
stbrp_rect rects[num];
|
|
|
|
for (int i = 0; i < num; i++) {
|
|
HMM_Vec2 wh = js2vec2(js,js_getpropertyuint32(js, argv[2], i));
|
|
rects[i].w = wh.x;
|
|
rects[i].h = wh.y;
|
|
rects[i].id = i;
|
|
}
|
|
|
|
stbrp_node nodes[width];
|
|
stbrp_init_target(ctx, width, height, nodes, width);
|
|
int packed = stbrp_pack_rects(ctx, rects, num);
|
|
|
|
if (!packed) {
|
|
return JS_UNDEFINED;
|
|
}
|
|
|
|
ret = JS_NewArray(js);
|
|
for (int i = 0; i < num; i++) {
|
|
HMM_Vec2 pos;
|
|
pos.x = rects[i].x;
|
|
pos.y = rects[i].y;
|
|
JS_SetPropertyUint32(js, ret, i, vec22js(js,pos));
|
|
}
|
|
)
|
|
|
|
|
|
JSC_CCALL(os_insertion_sort,
|
|
JSValue arr = argv[0];
|
|
JSValue cmp = argv[1];
|
|
int len = JS_ArrayLength(js, arr);
|
|
|
|
for (int i = 1; i < len; i++) {
|
|
JSValue key = JS_GetPropertyUint32(js, arr, i);
|
|
int j = i - 1;
|
|
|
|
while (j >= 0) {
|
|
JSValue arr_j = JS_GetPropertyUint32(js, arr, j);
|
|
|
|
JSValue ret = JS_Call(js, cmp, JS_UNDEFINED, 2, (JSValue[]){ arr_j, key });
|
|
if (JS_IsException(ret)) {
|
|
JS_FreeValue(js,arr_j);
|
|
JS_FreeValue(js,key);
|
|
return ret;
|
|
}
|
|
double c = js2number(js, ret);
|
|
JS_FreeValue(js, ret);
|
|
|
|
if (c > 0) {
|
|
JS_SetPropertyUint32(js, arr, j + 1, arr_j);
|
|
j--;
|
|
} else {
|
|
JS_FreeValue(js, arr_j);
|
|
break;
|
|
}
|
|
}
|
|
|
|
JS_SetPropertyUint32(js, arr, j + 1, key);
|
|
}
|
|
|
|
ret = JS_DupValue(js,arr);
|
|
)
|
|
|
|
JSC_CCALL(os_power_state,
|
|
SDL_PowerState state = SDL_GetPowerInfo(NULL, NULL);
|
|
switch(state) {
|
|
case SDL_POWERSTATE_ERROR: return JS_ThrowTypeError(js, "Error determining power status");
|
|
case SDL_POWERSTATE_UNKNOWN: return JS_UNDEFINED;
|
|
case SDL_POWERSTATE_ON_BATTERY: return JS_NewString(js, "on battery");
|
|
case SDL_POWERSTATE_NO_BATTERY: return JS_NewString(js, "no battery");
|
|
case SDL_POWERSTATE_CHARGING: return JS_NewString(js, "charging");
|
|
case SDL_POWERSTATE_CHARGED: return JS_NewString(js, "charged");
|
|
}
|
|
return JS_UNDEFINED;
|
|
)
|
|
|
|
JSC_CCALL(os_cull_sprites,
|
|
ret = JS_NewArray(js);
|
|
int n = 0;
|
|
|
|
JSValue sprites = argv[0];
|
|
shader_globals info = {0}; // TODO: get this as a JS object
|
|
rect camera_rect = {0};
|
|
camera_rect.x = info.camera_pos_world.x - info.render_size.x/2.0;
|
|
camera_rect.y = info.camera_pos_world.y - info.render_size.y/2.0;
|
|
camera_rect.w = info.render_size.x;
|
|
camera_rect.h = info.render_size.y;
|
|
|
|
int len = JS_ArrayLength(js,sprites);
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
JSValue sub = JS_GetPropertyUint32(js,sprites,i);
|
|
transform *t;
|
|
JS_GETATOM(js,t,sub,transform,transform)
|
|
|
|
rect sprite = transform2rect(t);
|
|
if (SDL_HasRectIntersectionFloat(&sprite, &camera_rect)) {
|
|
JS_SetPropertyUint32(js,ret,n,JS_DupValue(js,sub));
|
|
n++;
|
|
}
|
|
JS_FreeValue(js,sub);
|
|
}
|
|
)
|
|
|
|
static const JSCFunctionListEntry js_util_funcs[] = {
|
|
MIST_FUNC_DEF(os, guid, 0),
|
|
MIST_FUNC_DEF(os, insertion_sort, 2),
|
|
MIST_FUNC_DEF(util, camera_globals, 1),
|
|
};
|
|
|
|
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});
|
|
)
|
|
|
|
JSC_CCALL(graphics_save_png,
|
|
const char *file = JS_ToCString(js, argv[0]);
|
|
int w, h, comp, pitch;
|
|
JS_ToInt32(js, &w, argv[1]);
|
|
JS_ToInt32(js, &h, argv[2]);
|
|
JS_ToInt32(js, &pitch, argv[4]);
|
|
size_t size;
|
|
void *data = JS_GetArrayBuffer(js, &size, argv[3]);
|
|
|
|
if (!stbi_write_png(file, w, h, 4, data, pitch))
|
|
return JS_ThrowInternalError(js, "Could not write png");
|
|
)
|
|
|
|
JSC_CCALL(graphics_save_jpg,
|
|
const char *file = JS_ToCString(js, argv[0]);
|
|
int w, h, comp, pitch, quality;
|
|
JS_ToInt32(js, &w, argv[1]);
|
|
JS_ToInt32(js, &h, argv[2]);
|
|
JS_ToInt32(js, &pitch, argv[4]);
|
|
JS_ToInt32(js, &quality, argv[5]);
|
|
if (!quality) quality = 80;
|
|
size_t size;
|
|
void *data = JS_GetArrayBuffer(js, &size, argv[3]);
|
|
|
|
if (!stbi_write_jpg(file, w, h, 4, data, quality))
|
|
return JS_ThrowInternalError(js, "Could not write png");
|
|
)
|
|
|
|
static const JSCFunctionListEntry js_graphics_funcs[] = {
|
|
MIST_FUNC_DEF(os, make_text_buffer, 6),
|
|
MIST_FUNC_DEF(os, rectpack, 3),
|
|
MIST_FUNC_DEF(os, make_texture, 1),
|
|
MIST_FUNC_DEF(os, make_gif, 1),
|
|
MIST_FUNC_DEF(os, make_aseprite, 1),
|
|
MIST_FUNC_DEF(os, cull_sprites, 2),
|
|
MIST_FUNC_DEF(os, make_font, 2),
|
|
MIST_FUNC_DEF(os, make_line_prim, 5),
|
|
MIST_FUNC_DEF(graphics, hsl_to_rgb, 3),
|
|
MIST_FUNC_DEF(graphics, save_png, 4),
|
|
MIST_FUNC_DEF(graphics, save_jpg, 4),
|
|
};
|
|
|
|
static const JSCFunctionListEntry js_video_funcs[] = {
|
|
MIST_FUNC_DEF(os, make_video, 1),
|
|
};
|
|
|
|
JSC_SCALL(os_use_embed,
|
|
prosperon_rt *rt = JS_GetContextOpaque(js);
|
|
ModuleEntry *module_registry = rt->module_registry;
|
|
for (int i = 0; i < arrlen(module_registry); i++) {
|
|
if (strcmp(str,module_registry[i].name) == 0) {
|
|
ret = module_registry[i].fn(js);
|
|
break;
|
|
}
|
|
}
|
|
)
|
|
|
|
JSC_SCALL(os_use_dyn,
|
|
SDL_SharedObject *ptr = SDL_LoadObject(str);
|
|
if (!ptr)
|
|
return JS_ThrowReferenceError(js, "Shared library %s could not be loaded", SDL_GetError());
|
|
|
|
JSValue (*js_use)(JSContext*);
|
|
js_use = (JSValue (*)(JSContext*))SDL_LoadFunction(ptr, "use");
|
|
|
|
if (!js_use)
|
|
ret = JS_ThrowReferenceError(js, "Shared library %s has no use function", str);
|
|
else
|
|
ret = js_use(js);
|
|
|
|
SDL_UnloadObject(ptr);
|
|
)
|
|
|
|
#define JSSTATIC(NAME, PARENT) \
|
|
js_##NAME = JS_NewObject(js); \
|
|
JS_SetPropertyFunctionList(js, js_##NAME, js_##NAME##_funcs, countof(js_##NAME##_funcs)); \
|
|
JS_SetPrototype(js, js_##NAME, PARENT); \
|
|
|
|
JSValue js_layout_use(JSContext *js);
|
|
JSValue js_miniz_use(JSContext *js);
|
|
|
|
JSValue js_graphics_use(JSContext *js) {
|
|
JSValue mod = JS_NewObject(js);
|
|
JS_SetPropertyFunctionList(js,mod,js_graphics_funcs,countof(js_graphics_funcs));
|
|
return mod;
|
|
}
|
|
|
|
JSValue js_util_use(JSContext *js) {
|
|
JSValue mod = JS_NewObject(js);
|
|
JS_SetPropertyFunctionList(js,mod,js_util_funcs,countof(js_util_funcs));
|
|
return mod;
|
|
}
|
|
|
|
JSValue js_video_use(JSContext *js) {
|
|
JSValue mod = JS_NewObject(js);
|
|
JS_SetPropertyFunctionList(js,mod,js_video_funcs,countof(js_video_funcs));
|
|
return mod;
|
|
}
|
|
|
|
JSValue js_console_use(JSContext *js) {
|
|
JSValue mod = JS_NewObject(js);
|
|
JS_SetPropertyFunctionList(js,mod,js_console_funcs,countof(js_console_funcs));
|
|
return mod;
|
|
}
|
|
|
|
JSC_CCALL(os_value_id,
|
|
JS_SetPropertyStr(js, argv[0], "id", number2js(js, (uintptr_t)JS_VALUE_GET_PTR(argv[0])));
|
|
return argv[0];
|
|
)
|
|
|
|
#include "qjs_crypto.h"
|
|
#include "qjs_time.h"
|
|
#include "qjs_blob.h"
|
|
#include "qjs_http.h"
|
|
|
|
//JSValue js_imgui_use(JSContext *js);
|
|
#define MISTLINE(NAME) (ModuleEntry){#NAME, js_##NAME##_use}
|
|
|
|
void ffi_load(JSContext *js)
|
|
{
|
|
prosperon_rt *rt = JS_GetContextOpaque(js);
|
|
|
|
m_seedRand(&rt->mrand, time(NULL));
|
|
|
|
// cell modules
|
|
arrput(rt->module_registry, MISTLINE(time));
|
|
arrput(rt->module_registry, ((ModuleEntry){"math", js_math_use}));
|
|
arrput(rt->module_registry, MISTLINE(blob));
|
|
|
|
// extra
|
|
arrput(rt->module_registry, ((ModuleEntry){"io", js_io_use}));
|
|
arrput(rt->module_registry, ((ModuleEntry){"fd", js_fd_use}));
|
|
arrput(rt->module_registry, ((ModuleEntry){"os", js_os_use}));
|
|
arrput(rt->module_registry, MISTLINE(qr));
|
|
arrput(rt->module_registry, MISTLINE(http));
|
|
arrput(rt->module_registry, MISTLINE(crypto));
|
|
arrput(rt->module_registry, MISTLINE(miniz));
|
|
|
|
// power user
|
|
arrput(rt->module_registry, MISTLINE(js));
|
|
arrput(rt->module_registry, MISTLINE(debug));
|
|
arrput(rt->module_registry, MISTLINE(dmon));
|
|
arrput(rt->module_registry, MISTLINE(util));
|
|
|
|
// prosperon
|
|
arrput(rt->module_registry, ((ModuleEntry){"sdl_audio", js_sdl_audio_use}));
|
|
arrput(rt->module_registry, ((ModuleEntry){"sdl_video", js_sdl_video_use}));
|
|
arrput(rt->module_registry, ((ModuleEntry){"input", js_input_use}));
|
|
arrput(rt->module_registry, ((ModuleEntry){"surface", js_sdl_surface_use}));
|
|
arrput(rt->module_registry, MISTLINE(spline));
|
|
arrput(rt->module_registry, ((ModuleEntry){"geometry", js_geometry_use}));
|
|
arrput(rt->module_registry, MISTLINE(graphics));
|
|
arrput(rt->module_registry, MISTLINE(video));
|
|
arrput(rt->module_registry, MISTLINE(soloud));
|
|
arrput(rt->module_registry, MISTLINE(layout));
|
|
|
|
// arrput(rt->module_registry, MISTLINE(imgui));
|
|
arrput(rt->module_registry, ((ModuleEntry){"camera", js_camera_use}));
|
|
|
|
arrput(rt->module_registry, MISTLINE(rtree));
|
|
arrput(rt->module_registry, MISTLINE(sprite));
|
|
arrput(rt->module_registry, MISTLINE(transform));
|
|
|
|
// arrput(rt->module_registry, MISTLINE(wota));
|
|
// arrput(rt->module_registry, MISTLINE(nota));
|
|
|
|
#ifndef NSTEAM
|
|
arrput(rt->module_registry, MISTLINE(steam));
|
|
#endif
|
|
|
|
JSValue globalThis = JS_GetGlobalObject(js);
|
|
|
|
JSValue prosp = JS_NewObject(js);
|
|
JS_SetPropertyStr(js,globalThis,"prosperon", prosp);
|
|
JSValue c_types = JS_NewObject(js);
|
|
JS_SetPropertyStr(js,prosp, "c_types", c_types);
|
|
|
|
QJSCLASSPREP_FUNCS(font);
|
|
QJSCLASSPREP_FUNCS(datastream);
|
|
|
|
// use_dyn and use_embed moved to hidden_fn
|
|
|
|
JSValue jsobject = JS_GetPropertyStr(js,globalThis, "Object");
|
|
JS_SetPropertyStr(js, jsobject, "id", JS_NewCFunction(js, js_os_value_id, "id", 1));
|
|
JS_FreeValue(js,jsobject);
|
|
|
|
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 args = JS_NewArray(js);
|
|
for (int i = 0; i < rt->cmd.argc; i++)
|
|
JS_SetPropertyUint32(js,args, i, JS_NewString(js,rt->cmd.argv[i]));
|
|
|
|
JS_SetPropertyStr(js,prosp,"argv", args);
|
|
//JS_SetPropertyStr(js,prosp, "version", JS_NewString(js,PROSPERON_VERSION));
|
|
//JS_SetPropertyStr(js,prosp,"revision",JS_NewString(js,PROSPERON_COMMIT));
|
|
|
|
JSValue hidden_fn = JS_NewObject(js);
|
|
// add engine.js-only functions to hidden_fn. It should grab them and then remove so nothing else can use them.
|
|
|
|
// Add modules that should only be accessible to engine.js
|
|
JS_SetPropertyStr(js, hidden_fn, "actor", js_actor_use(js));
|
|
JS_SetPropertyStr(js, hidden_fn, "wota", js_wota_use(js));
|
|
JS_SetPropertyStr(js, hidden_fn, "console", js_console_use(js));
|
|
JS_SetPropertyStr(js, hidden_fn, "nota", js_nota_use(js));
|
|
JS_SetPropertyStr(js, hidden_fn, "enet", js_enet_use(js));
|
|
|
|
// Add functions that should only be accessible to engine.js
|
|
JS_SetPropertyStr(js, hidden_fn, "use_dyn", JS_NewCFunction(js, js_os_use_dyn, "use_dyn", 1));
|
|
JS_SetPropertyStr(js, hidden_fn, "use_embed", JS_NewCFunction(js, js_os_use_embed, "use_embed", 1));
|
|
|
|
JS_SetPropertyStr(js, prosp, "hidden", hidden_fn);
|
|
|
|
JS_FreeValue(js,globalThis);
|
|
|
|
/*
|
|
prosperon_rt *actor = JS_GetContextOpaque(js);
|
|
actor->actor_sym = JS_NewSymbol(js, "actor symbol", 0);
|
|
JS_SetPropertyStr(js, hidden_fn, "ACTORDATA", actor->actor_sym);
|
|
*/
|
|
}
|