Project cleanup. Update stb libraries. Remove unused files. Enable pedantic warning flag and fix all warnings. Fill out spline file.

This commit is contained in:
2025-02-21 16:38:59 -06:00
parent 387c4364b5
commit 867a18e788
32 changed files with 977 additions and 1236 deletions

View File

@@ -1,13 +1,14 @@
project('prosperon', ['c', 'cpp'], default_options : [ 'cpp_std=c++11'])
project('prosperon', ['c', 'cpp'],
version: '0.9.2',
meson_version: '>=1.4',
default_options : [ 'cpp_std=c++11'])
libtype = get_option('default_library')
link = []
src = []
if not get_option('editor')
# add_project_arguments('-DNEDITOR', language:'c')
endif
add_project_arguments('-pedantic', language: ['c'])
git_tag_cmd = run_command('git', 'describe', '--tags', '--abbrev=0', check: false)
prosperon_version = 'unknown'
@@ -46,12 +47,13 @@ endif
cmake = import('cmake')
sdl3_cmake_options = [
'-DSDL_STATIC=ON',
'-DSDL_SHARED=OFF',
'-DSDL_TEST=OFF',
'-DCMAKE_BUILD_TYPE=Release',
]
sdl3_opts = cmake.subproject_options()
sdl3_opts.add_cmake_defines({
'SDL_STATIC': 'ON',
'SDL_SHARED': 'OFF',
'SDL_TEST': 'OFF',
'CMAKE_BUILD_TYPE': 'Release'
})
cc = meson.get_compiler('c')
@@ -75,7 +77,7 @@ if host_machine.system() == 'windows'
deps += cc.find_library('imm32')
deps += cc.find_library('version')
deps += cc.find_library('cfgmgr32')
sdl3_cmake_options += '-DHAVE_ISINF=1' # TODO: A hack to get this to compile on MSYS2; otherwise it doesn't link correctly
sdl3_opts.add_cmake_defines({'HAVE_ISINF': '1'}) # TODO: A hack to get this to compile on MSYS2; otherwise it doesn't link correctly
link += '-static'
endif
@@ -83,7 +85,7 @@ if host_machine.system() == 'emscripten'
link += '-sUSE_WEBGPU'
endif
sdl3_proj = cmake.subproject('sdl3', cmake_options: sdl3_cmake_options)
sdl3_proj = cmake.subproject('sdl3', options: sdl3_opts)
deps += sdl3_proj.dependency('SDL3-static')
@@ -125,7 +127,7 @@ if get_option('enet')
endif
sources = []
src += ['anim.c', 'config.c', 'datastream.c','font.c','gameobject.c','HandmadeMath.c','jsffi.c','model.c','render.c','script.c','simplex.c','spline.c', 'timer.c', 'transform.c','prosperon.c', 'wildmatch.c', 'sprite.c', 'quadtree.c', 'aabb.c', 'rtree.c']
src += ['anim.c', 'config.c', 'datastream.c','font.c','HandmadeMath.c','jsffi.c','model.c','render.c','script.c','simplex.c','spline.c', 'timer.c', 'transform.c','prosperon.c', 'wildmatch.c', 'sprite.c', 'rtree.c']
imsrc = ['GraphEditor.cpp','ImCurveEdit.cpp','ImGradient.cpp','imgui_draw.cpp','imgui_tables.cpp','imgui_widgets.cpp','imgui.cpp','ImGuizmo.cpp','imnodes.cpp','implot_items.cpp','implot.cpp', 'imgui_impl_sdlrenderer3.cpp', 'imgui_impl_sdl3.cpp', 'imgui_impl_sdlgpu3.cpp']
@@ -167,7 +169,7 @@ core = custom_target('core.zip',
' && echo "Rebuilding core.zip" && rm -f ' + meson.current_build_dir() + '/core.zip && ' +
'zip -r ' + meson.current_build_dir() + '/core.zip scripts fonts icons shaders'
],
build_always: true,
build_always_stale: true,
build_by_default: true
)
@@ -196,7 +198,7 @@ prosperon = custom_target('prosperon',
'@INPUT1@',
'@OUTPUT@'
],
build_always: true,
build_always_stale: true,
build_by_default: true
)
@@ -209,10 +211,10 @@ copy_tests = custom_target(
output: 'tests',
command: [
'cp', '-rf',
join_paths(meson.source_root(), 'tests'),
meson.build_root()
join_paths(meson.project_source_root(), 'tests'),
meson.project_build_root()
],
build_always: true,
build_always_stale: true,
build_by_default: true
)

View File

@@ -322,16 +322,6 @@ imgui.barplot[prosperon.DOC] = `Plot a bar chart in the current ImPlot.
:return: None
`;
imgui.pieplot[prosperon.DOC] = `Plot a pie chart in the current ImPlot.
:param labels: An array of label strings for each slice.
:param values: An array of numeric values corresponding to each slice.
:param x: The x position of the pies center.
:param y: The y position of the pies center.
:param radius: The radius of the pie chart.
:return: None
`;
imgui.textplot[prosperon.DOC] = `Render text at the specified coordinates in plot space.
:param text: The string to render.

View File

@@ -103,8 +103,10 @@ io.basedir[prosperon.DOC] = `Return the application's base directory (where the
:return: A string with the base directory path.
`
io.userdir[prosperon.DOC] = `Return the user's directory, often used for saving data.
io.prefdir[prosperon.DOC] = `Get the user-and-app-specific path where files can be written.
:param org: The name of your organization.
:param app: The name of your application.
:return: A string with the user's directory path.
`

View File

@@ -361,7 +361,6 @@ function make_shader(sh_file) {
num_uniform_buffers: refl.ubos ? refl.ubos.length : 0,
entrypoint: shader_type === "msl" ? "main0" : "main"
}
console.log(`making shader ${sh_file} of format ${shader_type}`)
shader.gpu = render._main.make_shader(shader)
shader.reflection = refl;

View File

@@ -1,34 +0,0 @@
#include <stdlib.h>
#include <math.h>
#include "aabb.h"
aabb*
aabb_new(float x, float y, float hW, float hH) {
aabb* a = malloc(sizeof(aabb));
a->center.x = x;
a->center.y = y;
a->dims.w = hW;
a->dims.h = hH;
return a;
}
void
aabb_free(aabb *a) {
free(a);
}
int
aabb_contains(aabb *a, float x, float y) {
return (x >= a->center.x-a->dims.w &&
x <= a->center.x+a->dims.w) &&
(y >= a->center.y-a->dims.h &&
y <= a->center.y+a->dims.h);
}
int
aabb_intersects(aabb *a, aabb *b) {
return (abs(a->center.x - b->center.x) < (a->dims.w + b->dims.w)) &&
(abs(a->center.y - b->center.y) < (a->dims.h + b->dims.h));
}

View File

@@ -1,48 +0,0 @@
/*
aabb.h
2014 JSK (kutani@projectkutani.com)
Simple (2D) axis-aligned bounding box implementation. Part of the Panic
Panic project.
Released to the public domain. See LICENSE for details.
*/
#ifndef _AABB_H
#define _AABB_H
/** \brief axis-aligned bounding box
Simple struct of four floats, divided into two sub-structs.
center {x, y} - The center point of the bounding box
dims {w, h} - The half-width and half-height of the box
*/
typedef struct aabb {
struct {
float x;
float y;
} center;
struct {
float w;
float h;
} dims;
} aabb;
/// Malloc's a new aabb struct
/*!
Mallocs a new aabb struct and sets center and dims to the passed
x, y, hW, and hH values.
*/
aabb* aabb_new(float x, float y, float hW, float hH);
/// Frees the passed aabb.
void aabb_free(aabb *a);
/// Checks if the point x,y lies within the passed aabb
int aabb_contains(aabb *a, float x, float y);
/// Checks if the two passed aabb's intersect
int aabb_intersects(aabb *a, aabb *b);
#endif

View File

@@ -16,7 +16,10 @@ void animation_run(struct animation *anim, float now)
HMM_Vec4 sample_cubicspline(sampler *sampler, float t, int prev, int next)
{
return (HMM_Vec4)HMM_SLerp(HMM_QV4(sampler->data[prev]), t, HMM_QV4(sampler->data[next]));
HMM_Vec4 ret;
HMM_Quat qv = HMM_SLerp(HMM_QV4(sampler->data[prev]), t, HMM_QV4(sampler->data[next]));
memcpy(ret.e, qv.e, sizeof(ret.e));
return ret;
}
HMM_Vec4 sample_sampler(sampler *sampler, float time)
@@ -37,6 +40,9 @@ HMM_Vec4 sample_sampler(sampler *sampler, float time)
float td = sampler->times[next_time]-sampler->times[previous_time];
float t = (time - sampler->times[previous_time])/td;
HMM_Vec4 ret;
HMM_Quat qv;
switch(sampler->type) {
case LINEAR:
return HMM_LerpV4(sampler->data[previous_time],time,sampler->data[next_time]);
@@ -48,7 +54,9 @@ HMM_Vec4 sample_sampler(sampler *sampler, float time)
return sample_cubicspline(sampler,t, previous_time, next_time);
break;
case SLERP:
return (HMM_Vec4)HMM_SLerp(sampler->data[previous_time].quat, time, sampler->data[next_time].quat);
qv = HMM_SLerp(sampler->data[previous_time].quat, time, sampler->data[next_time].quat);
memcpy(ret.e,qv.e,sizeof(ret.e));
return ret;
break;
}
return sample_cubicspline(sampler,t, previous_time, next_time);

View File

@@ -24,11 +24,12 @@
#define STBI_NO_STDIO
#include "stb_image.h"
#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_BOX
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "stb_image_resize2.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_BOX
#include "stb_image_write.h"
#define PL_MPEG_IMPLEMENTATION

View File

@@ -306,24 +306,7 @@ struct ase_t
void* mem_ctx;
};
#define ASEPRITE_ERROR_MAX 256
static char aseprite_error[ASEPRITE_ERROR_MAX] = {0};
static const char *aseprite_GetError() {
return aseprite_error;
}
static void aseprite_clear_error() {
aseprite_error[0] = 0;
}
static void aseprite_set_error(const char *msg) {
if (msg) {
strncpy(aseprite_error, msg, ASEPRITE_ERROR_MAX-1);
aseprite_error[ASEPRITE_ERROR_MAX-1] = 0;
} else
aseprite_error[0] = 0;
}
const char *aseprite_GetError();
#endif // CUTE_ASEPRITE_H
@@ -331,6 +314,24 @@ static void aseprite_set_error(const char *msg) {
#ifndef CUTE_ASEPRITE_IMPLEMENTATION_ONCE
#define CUTE_ASEPRITE_IMPLEMENTATION_ONCE
#define ASEPRITE_ERROR_MAX 256
char aseprite_error[ASEPRITE_ERROR_MAX] = {0};
const char *aseprite_GetError() {
return aseprite_error;
}
void aseprite_clear_error() {
aseprite_error[0] = 0;
}
void aseprite_set_error(const char *msg) {
if (msg) {
strncpy(aseprite_error, msg, ASEPRITE_ERROR_MAX-1);
aseprite_error[ASEPRITE_ERROR_MAX-1] = 0;
} else
aseprite_error[0] = 0;
}
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS

View File

@@ -15,11 +15,6 @@ void datastream_free(JSRuntime *rt,datastream *ds)
free(ds);
}
static void render_audio(plm_t *mpeg, plm_samples_t *samples, struct datastream *ds) {
// for (int i = 0; i < samples->count * CHANNELS; i++)
// ringpush(ds->ring, samples->interleaved[i]);
}
struct datastream *ds_openvideo(void *raw, size_t rawlen)
{
struct datastream *ds = malloc(sizeof(*ds));

View File

@@ -21,31 +21,6 @@ void font_free(JSRuntime *rt, font *f)
free(f);
}
struct sFont *MakeSDFFont(const char *fontfile, int height)
{
int packsize = 1024;
struct sFont *newfont = calloc(1, sizeof(struct sFont));
newfont->height = height;
char fontpath[256];
snprintf(fontpath, 256, "fonts/%s", fontfile);
// unsigned char *ttf_buffer = slurp_file(fontpath, NULL);
unsigned char *bitmap = malloc(packsize * packsize);
stbtt_fontinfo fontinfo;
// if (!stbtt_InitFont(&fontinfo, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer, 0))) {
// YughError("Failed to make font %s", fontfile);
// }
for (int i = 32; i < 95; i++) {
int w, h, xoff, yoff;
// unsigned char *stbtt_GetGlyphSDF(&fontinfo, height, i, 1, 0, 1, &w, &h, &xoff, &yoff);
}
return newfont;
}
struct sFont *MakeFont(void *ttf_buffer, size_t len, int height) {
if (!ttf_buffer)
return NULL;
@@ -111,29 +86,6 @@ struct sFont *MakeFont(void *ttf_buffer, size_t len, int height) {
return newfont;
}
int text_flush() {
/* if (arrlen(text_buffer) == 0) return 0;
sg_range verts;
verts.ptr = text_buffer;
verts.size = sizeof(struct text_vert) * arrlen(text_buffer);
if (sg_query_buffer_will_overflow(*buf, verts.size)) {
sg_destroy_buffer(*buf);
*buf = sg_make_buffer(&(sg_buffer_desc){
.size = verts.size,
.type = SG_BUFFERTYPE_STORAGEBUFFER,
.usage = SG_USAGE_STREAM,
.label = "text buffer"
});
}
sg_append_buffer(*buf, &verts);
int n = arrlen(text_buffer);
arrsetlen(text_buffer, 0);
return n;
*/
}
void sdrawCharacter(struct text_vert **buffer, stbtt_packedchar c, HMM_Vec2 cursor, float scale, struct rgba color) {
struct text_vert vert;
@@ -185,7 +137,7 @@ const char *esc_color(const char *c, struct rgba *color, struct rgba defc)
{
struct rgba d;
if (!color) color = &d;
if (*c != '\e') return c;
if (*c != '\033') return c;
c++;
if (*c != '[') return c;
c++;
@@ -235,7 +187,7 @@ HMM_Vec2 measure_text(const char *text, font *f, float size, float letterSpacing
continue;
}
float charWidth = f->Characters[*c].advance + letterSpacing;
float charWidth = f->Characters[(unsigned char)*c].advance + letterSpacing;
// Handle wrapping
if (wrap > 0 && lineWidth + charWidth > wrap) {
@@ -283,15 +235,13 @@ HMM_Vec2 measure_text(const char *text, font *f, float size, float letterSpacing
}
/* pos given in screen coordinates */
struct text_vert *renderText(const char *text, HMM_Vec2 pos, font *f, float scale, colorf color, float wrap) {
int wrapAtWord = 1;
text_vert *buffer = NULL;
int len = strlen(text);
HMM_Vec2 cursor = pos;
float lineHeight = f->ascent - f->descent;
float lineWidth = 0;
for (char *c = text; *c != 0; c++) {
for (const char *c = text; *c != 0; c++) {
if (*c == '\n') {
cursor.x = pos.x;
cursor.y -= lineHeight + f->linegap;
@@ -299,7 +249,7 @@ struct text_vert *renderText(const char *text, HMM_Vec2 pos, font *f, float scal
continue;
}
struct character chara = f->Characters[*c];
struct character chara = f->Characters[(unsigned char)*c];
if (wrap > 0 && lineWidth + chara.advance > wrap) {
cursor.x = pos.x;

View File

@@ -60,7 +60,4 @@ struct sFont *MakeFont(void *data, size_t len, int height);
struct text_vert *renderText(const char *text, HMM_Vec2 pos, font *f, float scale, colorf color, float wrap);
HMM_Vec2 measure_text(const char *text, font *f, float scale, float letterSpacing, float wrap);
// Flushes all letters from renderText calls into the provided buffer
int text_flush();
#endif

View File

@@ -1,33 +0,0 @@
#include "gameobject.h"
#include "math.h"
#include <chipmunk/chipmunk.h>
#include "stb_ds.h"
static void velocityFn(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt)
{
/* gameobject *go = body2go(body);
gameobject_apply(go);
cpVect pos = cpBodyGetPosition(body);
HMM_Vec2 g = warp_force((HMM_Vec3){pos.x, pos.y, 0}, go->warp_mask).xy;
if (!go) {
cpBodyUpdateVelocity(body,g.cp,damping,dt);
return;
}
// cpFloat d = isfinite(go->damping) ? go->damping : damping;
cpFloat d = damping;
cpBodyUpdateVelocity(body,g.cp,d,dt*go->timescale);
if (isfinite(go->maxvelocity))
cpBodySetVelocity(body, cpvclamp(cpBodyGetVelocity(body), go->maxvelocity));
if (isfinite(go->maxangularvelocity)) {
float av = cpBodyGetAngularVelocity(body);
if (fabs(av) > go->maxangularvelocity)
cpBodySetAngularVelocity(body, copysignf(go->maxangularvelocity, av));
}
*/
}

View File

@@ -1,49 +0,0 @@
#ifndef GAMEOBJECT_H
#define GAMEOBJECT_H
#define dag_rm(p,c) do{\
for (int i = arrlen(p->children)-1; i--; i >=0) {\
if (p->children[i] == c) { \
arrdelswap(p->children,i);\
c->parent=NULL;\
break;\
}}}while(0)
#define dag_set(p,c) do{\
arrpush(p->children,c);\
if(c->parent) dag_rm(c->parent,c);\
c->parent=p;\
}while(0)
#define dag_clip(p) do{\
if (p->parent)\
dag_rm(p->parent,p);\
}while(0)
struct gameobject {
float damping;
float timescale;
float maxvelocity;
float maxangularvelocity;
unsigned int layer;
unsigned int warp_mask;
};
/*
Friction uses coulomb model. When shapes collide, their friction is multiplied. Some example values:
Steel on steel: 0.0005
Wood on steel: 0.0012
Wood on wood: 0.0015
=> steel = 0.025
=> wood = 0.04
=> hardrubber = 0.31
=> concrete = 0.05
=> rubber = 0.5
Hardrubber on steel: 0.0077
Hardrubber on concrete: 0.015
Rubber on concrete: 0.025
*/
typedef struct gameobject gameobject;
#endif

View File

@@ -62,8 +62,6 @@ typedef struct rtree rtree;
//#include <cblas.h>
#endif
#define STATE_VECTOR_LENGTH 624
#define STATE_VECTOR_M 397 /* changes to STATE_VECTOR_LENGTH also require changes to this */
@@ -1038,7 +1036,7 @@ static const char *vals_SDL_GPUTextureFormat[] = {
"astc 12x12 float"
};
JS2ENUM(SDL_GPUTextureFormat, rets_SDL_GPUTextureFormat, vals_SDL_GPUTextureFormat);
JS2ENUM(SDL_GPUTextureFormat, rets_SDL_GPUTextureFormat, vals_SDL_GPUTextureFormat)
SDL_GPUColorTargetBlendState js2SDL_GPUColorTargetBlendState(JSContext *js, JSValue v)
{
@@ -1606,7 +1604,7 @@ int point2segindex(HMM_Vec2 p, HMM_Vec2 *segs, double slop) {
return best;
}
static JSValue idx_buffer = JS_UNDEFINED;
static JSValue idx_buffer;
static int idx_count = 0;
JSValue make_quad_indices_buffer(JSContext *js, int quads)
@@ -1828,7 +1826,7 @@ JSValue js_math_dot(JSContext *js, JSValue self, int argc, JSValue *argv) {
free(a);
free(b);
return number2js(js,dot);
};
}
JSValue js_math_project(JSContext *js, JSValue self, int argc, JSValue *argv) {
size_t alen, blen;
@@ -2572,10 +2570,10 @@ JSC_CCALL(os_engine_start,
JS_SDL_PROP(js, p, SDL_PROP_APP_METADATA_URL_STRING, url)
JS_SDL_PROP(js, p, SDL_PROP_APP_METADATA_TYPE_STRING, type)
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_CAMERA) < 0)
return JS_ThrowReferenceError(js, "Couldn't initialize SDL: %s\n", SDL_GetError());
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_CAMERA))
return JS_ThrowReferenceError(js, "Couldn't initialize SDL: %s\n", SDL_GetError());
char *title;
const char *title;
JS_GETPROP(js,title,argv[0],title,cstring)
SDL_Window *new = SDL_CreateWindow(title, js2number(js, js_getproperty(js,argv[0], width_atom)), js2number(js,js_getproperty(js,argv[0], height_atom)), SDL_WINDOW_RESIZABLE);
@@ -3533,7 +3531,6 @@ JSC_CCALL(renderer_make_sprite_mesh,
for (int i = 0; i < quads; i++) {
JSValue sub = JS_GetPropertyUint32(js,sprites,i);
JSValue jstransform = JS_GetProperty(js,sub,transform_atom);
transform *tr = js2transform(js,jstransform);
JSValue jssrc = JS_GetProperty(js,sub,src_atom);
JSValue jscolor = JS_GetProperty(js,sub,color_atom);
@@ -3553,23 +3550,11 @@ JSC_CCALL(renderer_make_sprite_mesh,
// Calculate the base index for the current quad
size_t base = i * 4;
// HMM_Mat3 trmat = transform2mat3_global(tr);
HMM_Vec3 base_quad[4] = {
{0.0,0.0,1.0},
{1.0,0.0,1.0},
{0.0,1.0,1.0},
{1.0,1.0,1.0}
};
// for (int j = 0; j < 4; j++)
// posdata[base+j] = HMM_MulM3V3(trmat, base_quad[j]).xy;
// Define the UV coordinates based on the source rectangle
uvdata[base + 0] = (HMM_Vec2){ src.x, src.y + src.h };
uvdata[base + 1] = (HMM_Vec2){ src.x + src.w, src.y + src.h };
uvdata[base + 2] = (HMM_Vec2){ src.x, src.y };
uvdata[base + 3] = (HMM_Vec2){ src.x + src.w, src.y };
uvdata[base + 0] = (HMM_Vec2){ src.x, src.y + src.h };
uvdata[base + 1] = (HMM_Vec2){ src.x + src.w, src.y + src.h };
uvdata[base + 2] = (HMM_Vec2){ src.x, src.y };
uvdata[base + 3] = (HMM_Vec2){ src.x + src.w, src.y };
colordata[base] = color;
colordata[base+1] = color;
@@ -4156,18 +4141,12 @@ JSC_CCALL(gpu_texture,
return jstex;
)
static HMM_Vec3 base_quad[4] = {
{0.0,0.0,1.0},
{1.0,0.0,1.0},
{0.0,1.0,1.0},
{1.0,1.0,1.0}
};
static HMM_Vec4 base_quad_4[4] = {
{ 0.0,0.0, 1.0f, 1.0f },
{ 1,0,0.0, 1.0f, 1.0f },
{ 0.0,1.0, 1.0f, 1.0f },
{ 1.0,1.0, 1.0f, 1.0f }
};
static HMM_Vec3 base_quad[4] = {
{0.0,0.0,1.0},
{1.0,0.0,1.0},
{0.0,1.0,1.0},
{1.0,1.0,1.0}
};
static inline void add_quad(text_vert **verts, rect *restrict src, rect *restrict dst)
{
@@ -4644,7 +4623,6 @@ JSC_CCALL(gpu_acquire_cmd_buffer,
2: an optional transfer buffer to use; if undefined a temporary one is used
*/
JSC_CCALL(gpu_upload,
Uint64 ss = SDL_GetTicksNS();
JSValue js_cmd = argv[0];
JSValue js_buffers = argv[1];
JSValue js_transfer = argv[2];
@@ -4724,16 +4702,14 @@ JSC_CCALL(gpu_upload,
return JS_ThrowReferenceError(js, "Failed to map transfer buffer: %s", SDL_GetError());
}
Uint64 sy = SDL_GetTicksNS();
// Copy all data into the mapped transfer buffer
size_t current_offset = 0;
for (size_t i = 0; i < len; i++) {
memcpy(mapped_data + current_offset, items[i].data, items[i].size);
memcpy((char*)mapped_data + current_offset, items[i].data, items[i].size);
current_offset += items[i].size;
}
SDL_UnmapGPUTransferBuffer(gpu, transfer);
// Issue uploads for each item
current_offset = 0;
for (size_t i = 0; i < len; i++) {
@@ -5120,14 +5096,6 @@ JSC_CCALL(gpu_tile,
arrfree(verts);
)
static const JSCFunctionListEntry js_SDL_GPUCopyPass_funcs[] = {};
static const JSCFunctionListEntry js_SDL_GPUFence_funcs[] = {};
static const JSCFunctionListEntry js_SDL_GPUTransferBuffer_funcs[] = {};
static const JSCFunctionListEntry js_SDL_GPUShader_funcs[] = {};
static const JSCFunctionListEntry js_SDL_GPUSampler_funcs[] = {};
static const JSCFunctionListEntry js_SDL_GPUGraphicsPipeline_funcs[] = {};
static const JSCFunctionListEntry js_SDL_GPUComputePipeline_funcs[] = {};
static const JSCFunctionListEntry js_SDL_GPUDevice_funcs[] = {
MIST_FUNC_DEF(gpu, claim_window, 1),
MIST_FUNC_DEF(gpu, make_pipeline, 1), // loads pipeline state into an object
@@ -5707,8 +5675,6 @@ static const JSCFunctionListEntry js_SDL_Camera_funcs[] =
MIST_FUNC_DEF(camera, release_frame, 1),
};
static const JSCFunctionListEntry js_SDL_Cursor_funcs[] = {};
JSC_CCALL(texture_mode,
SDL_Texture *tex = js2SDL_Texture(js,self);
SDL_SetTextureScaleMode(tex,js2number(js,argv[0]));
@@ -5832,42 +5798,14 @@ static const JSCFunctionListEntry js_console_funcs[] = {
MIST_FUNC_DEF(console,print,1),
};
JSC_CCALL(profile_gather_rate,
JS_SetInterruptRate(js2number(js,argv[0]));
)
JSC_CCALL(profile_gather_stop,
JS_SetInterruptHandler(JS_GetRuntime(js),NULL,NULL);
)
JSC_CCALL(profile_best_t,
char* result[50];
double seconds = js2number(js,argv[0]);
if (seconds < 1e-6)
snprintf(result, 50, "%.2f ns", seconds * 1e9);
else if (seconds < 1e-3)
snprintf(result, 50, "%.2f µs", seconds * 1e6);
else if (seconds < 1)
snprintf(result, 50, "%.2f ms", seconds * 1e3);
else
snprintf(result, 50, "%.2f s", seconds);
return JS_NewString(js,result);
)
static const JSCFunctionListEntry js_profile_funcs[] = {
MIST_FUNC_DEF(profile,best_t, 1),
MIST_FUNC_DEF(profile,gather_rate,1),
MIST_FUNC_DEF(profile,gather_stop,0),
};
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))
JSC_CCALL(debug_closure_vars, return js_debugger_closure_variables(js,argv[0]))
JSC_CCALL(debug_local_vars, return js_debugger_local_variables(js, js2number(js,argv[0])))
JSC_CCALL(debug_fn_info, return js_debugger_fn_info(js, argv[0]));
JSC_CCALL(debug_backtrace_fns, return js_debugger_backtrace_fns(js,NULL));
JSC_CCALL(debug_dump_obj, return js_dump_value(js, argv[0]));
JSC_CCALL(debug_fn_info, return js_debugger_fn_info(js, argv[0]))
JSC_CCALL(debug_backtrace_fns, return js_debugger_backtrace_fns(js,NULL))
JSC_CCALL(debug_dump_obj, return js_dump_value(js, argv[0]))
static const JSCFunctionListEntry js_debug_funcs[] = {
MIST_FUNC_DEF(debug, stack_depth, 0),
MIST_FUNC_DEF(debug, build_backtrace, 0),
@@ -5932,22 +5870,33 @@ JSC_SCALL(io_slurp,
END:
)
size_t js_physfs_write(JSContext *js, PHYSFS_File *f, JSValue val)
{
size_t len;
size_t wrote;
if (JS_IsString(val)) {
const char *data = JS_ToCStringLen(js,&len,val);
wrote = PHYSFS_writeBytes(f,data,len);
JS_FreeCString(js,data);
} else {
unsigned char *data = JS_GetArrayBuffer(js,&len,val);
wrote = PHYSFS_writeBytes(f,data,len);
}
if (wrote < len) wrote = -1;
return wrote;
}
JSC_SCALL(io_slurpwrite,
PHYSFS_File *f = PHYSFS_openWrite(str);
if (!f) {
ret = JS_ThrowReferenceError(js,"could not write to %s: %s", str, PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
goto END;
}
size_t len;
unsigned char *data;
if (JS_IsString(argv[1]))
data = JS_ToCStringLen(js,&len,argv[1]);
else
data = JS_GetArrayBuffer(js,&len, argv[1]);
size_t wrote = js_physfs_write(js,f,argv[1]);
size_t wrote = PHYSFS_writeBytes(f,data, len);
PHYSFS_close(f);
if (wrote == -1 || wrote < len)
if (wrote == -1)
ret = JS_ThrowReferenceError(js,"%s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
END:
@@ -5989,10 +5938,11 @@ int globfs_cb(struct globdata *data, char *dir, char *file)
}
char **glob = data->globs;
while (*glob != NULL) {
if (wildmatch(*glob, path, WM_WILDSTAR) == WM_MATCH)
goto END;
*glob++;
glob++;
}
PHYSFS_Stat stat;
@@ -6023,18 +5973,18 @@ JSC_CCALL(io_globfs,
data.arr = ret;
data.idx = 0;
int globs_len = js_arrlen(js,argv[0]);
char *globs[globs_len+1];
const char *globs[globs_len+1];
for (int i = 0; i < globs_len; i++) {
JSValue g = JS_GetPropertyUint32(js,argv[0],i);
globs[i] = JS_ToCString(js,g);
JS_FreeValue(js,g);
}
globs[globs_len] = NULL;
data.globs = globs;
const char *path = NULL;
if (!JS_IsUndefined(argv[1])) path = JS_ToCString(js,argv[1]);
printf("LOOKING INTO %s\n", path);
PHYSFS_enumerate(path, globfs_cb, &data);
for (int i = 0; i < globs_len; i++)
@@ -6100,7 +6050,7 @@ JSC_SCALL(io_enumerate,
)
JSC_CCALL(io_basedir, return JS_NewString(js,PHYSFS_getBaseDir()))
JSC_CCALL(io_userdir, return JS_NewString(js,PHYSFS_getUserDir()))
JSC_SSCALL(io_prefdir, return JS_NewString(js,PHYSFS_getPrefDir(str, str2)))
JSC_SCALL(io_open,
PHYSFS_File *f = PHYSFS_openWrite(str);
@@ -6158,7 +6108,7 @@ static const JSCFunctionListEntry js_io_funcs[] = {
MIST_FUNC_DEF(io,slurpwrite,2),
MIST_FUNC_DEF(io,writepath, 1),
MIST_FUNC_DEF(io,basedir, 0),
MIST_FUNC_DEF(io, userdir, 0),
MIST_FUNC_DEF(io, prefdir, 2),
MIST_FUNC_DEF(io, realdir, 1),
MIST_FUNC_DEF(io, open, 1),
MIST_FUNC_DEF(io, searchpath, 0),
@@ -6174,15 +6124,8 @@ JSC_CCALL(file_close,
JSC_CCALL(file_write,
PHYSFS_File *f = js2PHYSFS_File(js,self);
size_t len;
unsigned char *data;
if (JS_IsString(argv[0]))
data = JS_ToCStringLen(js,&len,argv[0]);
else
data = JS_GetArrayBuffer(js,&len, argv[0]);
size_t wrote = PHYSFS_writeBytes(f,data,len);
if (wrote == -1 || wrote < len)
size_t wrote = js_physfs_write(js,f,argv[0]);
if (wrote == -1)
return JS_ThrowReferenceError(js,"%s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
)
@@ -6309,6 +6252,7 @@ static JSValue js_transform_set_change_hook(JSContext *js, JSValueConst self, JS
if (!JS_IsUndefined(v) && !JS_IsFunction(js,v)) return JS_ThrowReferenceError(js, "Hook must be a function.");
JS_FreeValue(js,t->change_hook);
t->change_hook = JS_DupValue(js,v);
return JS_UNDEFINED;
}
static JSValue js_transform_get_parent(JSContext *js, JSValueConst self)
@@ -6590,17 +6534,6 @@ JSC_CCALL(os_gc_threshold, JS_SetGCThreshold(JS_GetRuntime(js), js2number(js,arg
JSC_CCALL(os_max_stacksize, JS_SetMaxStackSize(JS_GetRuntime(js), js2number(js,argv[0])))
JSC_CCALL(os_rt_info, return JS_GetRTInfo(JS_GetRuntime(js),js))
static JSValue tmp2js(JSContext *js,FILE *tmp)
{
size_t size = ftell(tmp);
rewind(tmp);
char *buffer = calloc(size+1, sizeof(char));
fread(buffer, sizeof(char),size, tmp);
JSValue ret = JS_NewString(js,buffer);
free(buffer);
return ret;
}
JSC_CCALL(os_dump_atoms,
return js_dump_atoms(js);
)
@@ -6641,8 +6574,8 @@ JSC_CCALL(os_mallinfo,
JSJMEMRET(keepcost);*/
)
JSC_CCALL(os_rusage,
ret = JS_NewObject(js);
JSValue js_os_rusage(JSContext *js, JSValue self, int argc, JSValue *argv) {
JSValue ret = JS_NewObject(js);
#ifndef _WIN32
struct rusage jsmem;
@@ -6662,7 +6595,9 @@ JSC_CCALL(os_rusage,
JSJMEMRET(ru_nvcsw);
JSJMEMRET(ru_nivcsw);
#endif
)
return ret;
}
JSC_CCALL(os_mem, return js_get_memory_usage(js))
JSC_CCALL(os_value_id,
@@ -7135,7 +7070,7 @@ JSC_CCALL(os_hostname,
return JS_NewString(js,"");
)
JSC_CCALL(os_freemem,
JSValue js_os_freemem(JSContext *js, JSValue self, int argc, JSValue *argv) {
#ifdef _WIN32
MEMORYSTATUSEX statex;
statex.dwLength = sizeof(statex);
@@ -7158,9 +7093,9 @@ JSC_CCALL(os_freemem,
// Fallback: unknown
return JS_NewInt64(js,0);
#endif
)
}
JSC_CCALL(os_arch,
JSValue js_os_arch(JSContext *js, JSValue self, int argc, JSValue *argv) {
#if defined(__x86_64__) || defined(_M_X64)
return JS_NewString(js,"x64");
#elif defined(__aarch64__) || defined(_M_ARM64)
@@ -7184,9 +7119,9 @@ JSC_CCALL(os_arch,
#else
return JS_NewString(js,"unknown");
#endif
)
}
JSC_CCALL(os_version,
JSValue js_os_version(JSContext *js, JSValue self, int argc, JSValue *argv) {
#ifdef _WIN32
typedef LONG (WINAPI *RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
HMODULE h = GetModuleHandleA("ntdll.dll");
@@ -7225,7 +7160,9 @@ JSC_CCALL(os_version,
if (!uname(&info)) return JS_NewString(js, info.release);
return JS_NewString(js, "");
#endif
)
return JS_UNDEFINED;
}
static const JSCFunctionListEntry js_os_funcs[] = {
MIST_FUNC_DEF(os, make_transform, 0),
@@ -7269,7 +7206,7 @@ JSC_CCALL(js_dump_class, return js_get_object_class_distribution(js))
JSC_CCALL(js_dump_type_overheads, return js_get_object_type_overheads(js))
JSC_CCALL(js_dump_objects, return js_dump_objects(js))
JSValue cycle_fn = JS_UNDEFINED;
static JSValue cycle_fn;
void cycle_hook_call(JSContext *js, JSValue v)
{
@@ -7336,7 +7273,7 @@ static const JSCFunctionListEntry js_video_funcs[] = {
void gui_input(SDL_Event *e);
// Polls and handles all input events
JSC_CCALL(os_engine_input,
JSValue js_os_engine_input(JSContext *js, JSValue self, int argc, JSValue *argv) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
#ifndef NEDITOR
@@ -7346,7 +7283,8 @@ JSC_CCALL(os_engine_input,
JSValue ret = JS_Call(js,argv[0], JS_UNDEFINED, 1, &e);
uncaught_exception(js,ret);
}
)
return JS_UNDEFINED;
}
JSC_CCALL(os_push_event,
SDL_UserEvent e;
@@ -7714,19 +7652,21 @@ void ffi_load(JSContext *js, int argc, char **argv) {
QJSCLASSPREP_FUNCS(SDL_Texture)
QJSCLASSPREP_FUNCS(SDL_Renderer)
QJSCLASSPREP_FUNCS(SDL_Camera)
QJSCLASSPREP_FUNCS(SDL_Cursor)
QJSCLASSPREP_FUNCS(SDL_GPUDevice)
QJSCLASSPREP_FUNCS(SDL_GPUTexture)
QJSCLASSPREP_FUNCS(SDL_GPUCommandBuffer)
QJSCLASSPREP_FUNCS(SDL_GPURenderPass)
QJSCLASSPREP_FUNCS(SDL_GPUComputePass)
QJSCLASSPREP_FUNCS(SDL_GPUCopyPass)
QJSCLASSPREP_FUNCS(SDL_GPUFence)
QJSCLASSPREP_FUNCS(SDL_GPUTransferBuffer)
QJSCLASSPREP_FUNCS(SDL_GPUShader)
QJSCLASSPREP_FUNCS(SDL_GPUSampler)
QJSCLASSPREP_FUNCS(SDL_GPUGraphicsPipeline)
QJSCLASSPREP_FUNCS(SDL_GPUComputePipeline)
QJSCLASSPREP_NO_FUNCS(SDL_Cursor)
QJSCLASSPREP_NO_FUNCS(SDL_GPUCopyPass)
QJSCLASSPREP_NO_FUNCS(SDL_GPUFence)
QJSCLASSPREP_NO_FUNCS(SDL_GPUTransferBuffer)
QJSCLASSPREP_NO_FUNCS(SDL_GPUShader)
QJSCLASSPREP_NO_FUNCS(SDL_GPUSampler)
QJSCLASSPREP_NO_FUNCS(SDL_GPUGraphicsPipeline)
QJSCLASSPREP_NO_FUNCS(SDL_GPUComputePipeline)
QJSCLASSPREP_FUNCS(sprite)
// QJSCLASSPREP_FUNCS(SDL_GPUGraphicsPipeline)
// QJSCLASSPREP_FUNCS(SDL_GPUSampler)
@@ -7874,5 +7814,8 @@ void ffi_load(JSContext *js, int argc, char **argv) {
JS_SetPropertyStr(js,globalThis,"prosperon", prosp);
idx_buffer = JS_UNDEFINED;
cycle_fn = JS_UNDEFINED;
JS_FreeValue(js,globalThis);
}

View File

@@ -1,7 +1,6 @@
#include "model.h"
#include "stb_ds.h"
#include "gameobject.h"
#include "render.h"
@@ -18,59 +17,19 @@
#include "jsffi.h"
unsigned short pack_short_tex(float c) { return c * USHRT_MAX; }
SDL_GPUBuffer *texcoord_floats(float *f, int n)
{
unsigned short packed[n];
for (int i = 0; i < n; i++) {
float v = f[i];
if (v < 0) v = 0;
if (v > 1) v = 1;
packed[i] = pack_short_tex(v);
}
/* return sg_make_buffer(&(sg_buffer_desc){
.data = SG_RANGE(packed),
.label = "tex coord vert buffer",
});*/
return NULL;
}
SDL_GPUBuffer *par_idx_buffer(uint32_t *p, int v)
{
uint16_t idx[v];
for (int i = 0; i < v; i++) idx[i] = p[i];
/* return sg_make_buffer(&(sg_buffer_desc){
.data = SG_RANGE(idx),
.type = SG_BUFFERTYPE_INDEXBUFFER
});*/
return NULL;
}
SDL_GPUBuffer *float_buffer(float *f, int v)
{
return NULL;
/* return sg_make_buffer(&(sg_buffer_desc){
.data = (sg_range){
.ptr = f,
.size = sizeof(*f)*v
}
});*/
}
SDL_GPUBuffer *index_buffer(float *f, int verts)
{
return NULL;
/* uint16_t idxs[verts];
for (int i = 0; i < verts; i++)
idxs[i] = f[i];
return sg_make_buffer(&(sg_buffer_desc){
.data = SG_RANGE(idxs),
.type = SG_BUFFERTYPE_INDEXBUFFER,
});*/
}
uint32_t pack_int10_n2(float *norm)
@@ -87,71 +46,21 @@ uint32_t pack_int10_n2(float *norm)
SDL_GPUBuffer *normal_floats(float *f, int n)
{
return float_buffer(f, n);
/* uint32_t packed_norms[n/3];
for (int v = 0, i = 0; v < n/3; v++, i+= 3)
packed_norms[v] = pack_int10_n2(f+i);
return sg_make_buffer(&(sg_buffer_desc){
.data = SG_RANGE(packed_norms),
.label = "normal vert buffer",
});*/
}
SDL_GPUBuffer *ubyten_buffer(float *f, int v)
{
return NULL;
/* unsigned char b[v];
for (int i = 0; i < (v); i++)
b[i] = f[i]*255;
return sg_make_buffer(&(sg_buffer_desc){.data=SG_RANGE(b)});*/
}
SDL_GPUBuffer *ubyte_buffer(float *f, int v)
{
return NULL;
/* unsigned char b[v];
for (int i = 0; i < (v); i++)
b[i] = f[i];
return sg_make_buffer(&(sg_buffer_desc){.data=SG_RANGE(b)});
*/
}
SDL_GPUBuffer *accessor2buffer(cgltf_accessor *a, int type)
{
return NULL;
/* int n = cgltf_accessor_unpack_floats(a, NULL, 0);
float vs[n];
cgltf_accessor_unpack_floats(a, vs, n);
switch(type) {
case MAT_POS:
return sg_make_buffer(&(sg_buffer_desc){
.data.ptr = vs,
.data.size = sizeof(float)*n
});
case MAT_NORM:
return normal_floats(vs,n);
case MAT_TAN:
return normal_floats(vs,n); // TODO: MAKE A TANGENT READER
case MAT_COLOR:
return ubyten_buffer(vs,n);
case MAT_WEIGHT:
return ubyten_buffer(vs,n);
case MAT_BONE:
return ubyte_buffer(vs,n);
case MAT_UV:
return texcoord_floats(vs,n);
case MAT_INDEX:
return index_buffer(vs,n);
}
return sg_make_buffer(&(sg_buffer_desc) {
.data.size = 4,
.usage = SG_USAGE_STREAM
});
*/
}
void packFloats(float *src, float *dest, int srcLength) {

View File

@@ -3,7 +3,6 @@
#include "HandmadeMath.h"
#include "transform.h"
#include "gameobject.h"
#include "anim.h"
#include "cgltf.h"

View File

@@ -96,7 +96,7 @@ int main(int argc, char **argv) {
prosperon = argv[0];
PHYSFS_init(argv[0]);
char *base = PHYSFS_getBaseDir();
const char *base = PHYSFS_getBaseDir();
PHYSFS_setWriteDir(base);
PHYSFS_mount(base, "/", 0);

View File

@@ -3,6 +3,8 @@
#include "imnodes.h"
#include "quickjs.h"
#include <stb_ds.h>
#include <SDL3/SDL.h>
#include <SDL3/SDL_gpu.h>
#include "imgui_impl_sdl3.h"
@@ -163,11 +165,10 @@ JSC_SCALL(imgui_plot,
fill_plotdata(js, argv[1], argv[3]); \
bool shaded = JS_ToBool(js,argv[2]);\
int flag = 0; \
if (shaded) flag = SHADED; \
ImPlot::FN(str, &plotdata[0].x, &plotdata[0].y, arrlen(plotdata), ADD flag, 0, sizeof(ImVec2)); \
) \
//if (shaded) flag = SHADED;
// ImPlot::FN(str, &plotdata[0].x, &plotdata[0].y, arrlen(plotdata), ADD flag, 0, sizeof(ImVec2));
static ImVec2 *plotdata = NULL;
void fill_plotdata(JSContext *js, JSValue v, JSValue last)
@@ -204,40 +205,19 @@ PLOT_FN(digitalplot, PlotDigital,,0)
JSC_SCALL(imgui_barplot,
fill_plotdata(js, argv[1], JS_UNDEFINED);
// ImPlot::PlotBars(str, &plotdata[0].x, &plotdata[0].y, js_arrlen(js, argv[1]), js2number(js, argv[2]), 0, 0, sizeof(ImVec2));
ImPlot::PlotBars(str, &plotdata[0].x, &plotdata[0].y, js_arrlen(js, argv[1]), js2number(js, argv[2]), 0, 0, sizeof(ImVec2));
)
JSC_SCALL(imgui_histogramplot,
size_t offset, len, per_e;
JSValue typed = JS_GetTypedArrayBuffer(js, argv[1], &offset, &len, &per_e);
// ImPlot::PlotHistogram(str, JS_GetArrayBuffer(js, NULL, typed), js_arrlen(js, argv[1]));
ImPlot::PlotHistogram(str, JS_GetArrayBuffer(js, NULL, typed), js_arrlen(js, argv[1]));
JS_FreeValue(js, typed);
)
JSC_SCALL(imgui_heatplot,
int rows = js2number(js, argv[2]);
int cols = js2number(js, argv[3]);
// if (rows*cols == (int)js_arrlen(js, argv[1]))
// ImPlot::PlotHeatmap(str, histodata, rows, cols);
)
JSC_CCALL(imgui_pieplot,
/* if (js_arrlen(js, argv[0]) != js_arrlen(js, argv[1])) return JS_UNDEFINED;
const char *labels[js_arrlen(js, argv[0])];
for (int i = 0; i < js_arrlen(js, argv[0]); i++)
labels[i] = JS_ToCString(js, js_getpropidx(argv[0], i));
fill_histodata(argv[1]);
ImPlot::PlotPieChart(labels, histodata, js_arrlen(js, argv[1]), js2number(js, argv[2]), js2number(js, argv[3]), js2number(js, argv[4]));
for (int i = 0; i < js_arrlen(js, argv[0]); i++)
JS_FreeCString(js,labels[i]);*/
)
JSC_SCALL(imgui_textplot,
ImVec2 c = js2vec2(js, argv[1]);
// ImPlot::PlotText(str, c.x, c.y);
ImPlot::PlotText(str, c.x, c.y);
)
JSC_CCALL(imgui_inplot,
@@ -275,7 +255,7 @@ JSC_SSCALL(imgui_textinput,
if (JS_IsUndefined(argv[1]))
buffer[0] = 0;
else
strncpy(buffer, str2, 512);
strncpy(buffer, str2, sizeof(buffer)-1);
ImGui::InputText(str, buffer, sizeof(buffer));
if (strcmp(buffer, str2))
@@ -289,7 +269,7 @@ JSC_SSCALL(imgui_textbox,
if (JS_IsUndefined(argv[1]))
buffer[0] = 0;
else
strncpy(buffer, str2, 512);
strncpy(buffer, str2, sizeof(buffer)-1);
ImGui::InputTextMultiline(str, buffer, sizeof(buffer));
if (strcmp(buffer, str2))
@@ -834,7 +814,6 @@ const JSCFunctionListEntry js_imgui_funcs[] = {
MIST_FUNC_DEF(imgui, stairplot, 4),
MIST_FUNC_DEF(imgui, digitalplot, 4),
MIST_FUNC_DEF(imgui, barplot, 3),
MIST_FUNC_DEF(imgui, pieplot, 5),
MIST_FUNC_DEF(imgui, textplot, 2),
MIST_FUNC_DEF(imgui, histogramplot, 2),
MIST_FUNC_DEF(imgui, plotaxes, 2),

View File

@@ -134,10 +134,13 @@ JS_SetPropertyStr(js, globalThis, #NAME, NAME); \
/* Defines a class and uses its function list as its prototype */
#define QJSCLASSPREP_FUNCS(TYPE) \
QJSCLASSPREP_NO_FUNCS(TYPE) \
JS_SetPropertyFunctionList(js, TYPE##_proto, js_##TYPE##_funcs, countof(js_##TYPE##_funcs)); \
#define QJSCLASSPREP_NO_FUNCS(TYPE) \
JS_NewClassID(&js_##TYPE##_id);\
JS_NewClass(JS_GetRuntime(js), js_##TYPE##_id, &js_##TYPE##_class);\
JSValue TYPE##_proto = JS_NewObject(js); \
JS_SetPropertyFunctionList(js, TYPE##_proto, js_##TYPE##_funcs, countof(js_##TYPE##_funcs)); \
JS_SetClassProto(js, js_##TYPE##_id, TYPE##_proto); \
JS_SetPropertyStr(js, c_types, #TYPE, JS_DupValue(js,TYPE##_proto)); \
@@ -147,8 +150,6 @@ JSValue js_##NAME##_use(JSContext *js) { \
JS_SetPropertyFunctionList(js,mod,js_##NAME##_funcs,countof(js_##NAME##_funcs)); \
return mod; } \
#define MISTLINE(NAME) (ModuleEntry){ #NAME, js_##NAME##_funcs, countof(js_##NAME##_funcs) }
#define countof(x) (sizeof(x)/sizeof((x)[0]))

View File

@@ -37,6 +37,7 @@ static JSValue js_tracy_fiber_leave(JSContext *js, JSValue self, int argc, JSVal
const char *str = JS_AtomToCString(js, atom);
TracyCFiberLeave(str);
JS_FreeAtom(js,atom);
return JS_UNDEFINED;
}
static JSValue js_tracy_plot(JSContext *js, JSValue self, int argc, JSValue *argv)
@@ -61,7 +62,15 @@ static JSValue js_tracy_plot_config(JSContext *js, JSValue self, int argc, JSVal
return JS_UNDEFINED;
#endif
// TracyCPlotConfig(str, js2number(js,argv[1]), JS_ToBool(js,argv[2]), JS_ToBool(js,argv[3]), js2number(js,argv[4]))
const char *str = JS_ToCString(js,argv[0]);
uint32_t type, color;
JS_ToUint32(js,&type, argv[1]);
JS_ToUint32(js,&color,argv[4]);
TracyCPlotConfig(str, type, JS_ToBool(js,argv[2]), JS_ToBool(js,argv[3]), color);
JS_FreeCString(js,str);
return JS_UNDEFINED;
}
@@ -73,6 +82,8 @@ static JSValue js_tracy_frame_mark(JSContext *js, JSValue self, int argc, JSValu
#endif
TracyCFrameMark
return JS_UNDEFINED;
}
static JSValue js_tracy_message(JSContext *js, JSValue self, int argc, JSValue *argv)
@@ -86,6 +97,7 @@ static JSValue js_tracy_message(JSContext *js, JSValue self, int argc, JSValue *
const char *str = JS_ToCStringLen(js, &len, argv[0]);
TracyCMessage(str,len);
JS_FreeCString(js,str);
return JS_UNDEFINED;
}
static JSValue js_tracy_thread_name(JSContext *js, JSValue self, int argc, JSValue *argv)
@@ -98,6 +110,7 @@ static JSValue js_tracy_thread_name(JSContext *js, JSValue self, int argc, JSVal
const char *str = JS_ToCString(js, argv[0]);
TracyCSetThreadName(str);
JS_FreeCString(js,str);
return JS_UNDEFINED;
}
static JSValue js_tracy_zone_begin(JSContext *js, JSValue self, int argc, JSValue *argv)
@@ -121,6 +134,7 @@ static JSValue js_tracy_zone_begin(JSContext *js, JSValue self, int argc, JSValu
JS_Call(js, argv[0], JS_UNDEFINED, 0, NULL);
TracyCZoneEnd(TCTX);
return JS_UNDEFINED;
}
#ifdef SOKOL_GLCORE
@@ -190,7 +204,6 @@ static JSValue js_tracy_gpu_zone_begin(JSContext *js, JSValue self, int argc, JS
___tracy_emit_gpu_zone_end(enddata);
qhead = (qhead+1)%query_count;
return ret;
}
@@ -477,8 +490,8 @@ static JSValue js_tracy_image(JSContext *js, JSValue self, int argc, JSValue *ar
/* SDL_Surface *img = js2SDL_Surface(js,argv[0]);
SDL_Surface *scaled = SDL_ScaleSurface(img, 320,180,SDL_SCALEMODE_LINEAR);
___tracy_emit_frame_image(scaled->pixels, scaled->w,scaled->h, 0,0);
SDL_DestroySurface(scaled);
return JS_UNDEFINED;*/
SDL_DestroySurface(scaled);*/
return JS_UNDEFINED;
}
#endif
@@ -513,6 +526,8 @@ JSValue js_tracy_level(JSContext *js, JSValue selff, int argc, JSValue *argv)
js_debug_sethook(js, tracy_call_hook, JS_HOOK_CALL);
js_debug_sethook(js, tracy_end_hook, JS_HOOK_RET);
}
return JS_UNDEFINED;
}
static const JSCFunctionListEntry js_tracy_funcs[] = {
@@ -523,11 +538,13 @@ static const JSCFunctionListEntry js_tracy_funcs[] = {
JS_CFUNC_DEF("gpu_init", 0, js_tracy_gpu_init),
JS_CFUNC_DEF("gpu_sync", 0, js_tracy_gpu_sync),
JS_CFUNC_DEF("end_frame", 0, js_tracy_frame_mark),
JS_CFUNC_DEF("thread_name", 1, js_tracy_thread_name),
JS_CFUNC_DEF("zone", 1, js_tracy_zone_begin),
JS_CFUNC_DEF("message", 1, js_tracy_message),
JS_CFUNC_DEF("plot", 2, js_tracy_plot),
JS_CFUNC_DEF("image", 3, js_tracy_image),
JS_CFUNC_DEF("level", 1, js_tracy_level),
JS_CFUNC_DEF("plot_config", 5, js_tracy_plot_config),
};
JSValue js_tracy_use(JSContext *js)

View File

@@ -1,246 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "aabb.h"
/// Default node size cap
#define QTREE_STDCAP 4
/// A function pointer def for determining if an element exists in a range
typedef int (*qtree_fnc)(void *ptr, aabb *range);
typedef int (*qtree_rm)(void *ptr, void *cmp);
/// Quadtree node
typedef struct qnode {
uint16_t cnt; ///< Number of elements in this node
aabb bound; ///< Area this node covers
void **elist; ///< List of element pointers
struct qnode *nw; ///< NW quadrant of this node
struct qnode *ne; ///< NE quadrant of this node
struct qnode *sw; ///< SW quadrant of this node
struct qnode *se; ///< SE quadrant of this node
} qnode;
/// Quadtree container
typedef struct _qtree {
uint16_t maxnodecap; ///< Maximum element count per node
qnode *root; ///< Root node
qtree_fnc cmpfnc; ///< Element range compare function pointer
qtree_rm rmfnc;
} _qtree;
typedef struct _qtree* qtree;
/// Simple container for returning found elements
typedef struct retlist {
uint32_t cnt; ///< Number of elements found
aabb range; ///< Range to use for searching
void **list; ///< Array of pointers to found elements
} retlist;
static void retlist_add(retlist *r, void *p) {
r->list = realloc(r->list, sizeof(void*)*(r->cnt+1));
r->list[r->cnt] = p;
r->cnt++;
}
static uint16_t qtree_getMaxNodeCnt(qtree q) {
uint16_t r;
r = q->maxnodecap;
return r;
}
static qnode* qnode_new(qtree p, float x, float y, float hW, float hH) {
qnode *q = malloc(sizeof(qnode));
memset(q, 0, sizeof(qnode));
q->bound.center.x = x;
q->bound.center.y = y;
q->bound.dims.w = hW;
q->bound.dims.h = hH;
return q;
}
static void qnode_free(qtree q, qnode *qn) {
if(qn->cnt)
free(qn->elist);
qn->cnt = 0;
if(qn->nw) {
qnode_free(q, qn->nw);
qnode_free(q, qn->ne);
qnode_free(q, qn->sw);
qnode_free(q, qn->se);
}
free(qn);
}
static void add(qnode *q, void *p) {
q->elist = realloc(q->elist, sizeof(void*)*(q->cnt+1));
q->elist[q->cnt] = p;
q->cnt++;
}
static void drop(qnode *q, uint16_t idx) {
void **narry = malloc(sizeof(void*)*(q->cnt-1));
// This is a little (lot) ugly; a pair of memcpy's would be
// better, but I had some problems with it
for(uint16_t i=0,skip=0; i<q->cnt; i++) {
if(i == idx) { skip++; continue; }
narry[i-skip] = q->elist[i];
}
void **old = q->elist;
q->elist = narry;
free(old);
q->cnt--;
}
static void subdivide(qtree p, qnode *q) {
float cx = q->bound.center.x;
float cy = q->bound.center.y;
float hw = q->bound.dims.w/2;
float hh = q->bound.dims.h/2;
q->nw = qnode_new(p, cx-hw, cy-hh, hw, hh);
q->ne = qnode_new(p, cx+hw, cy-hh, hw, hh);
q->sw = qnode_new(p, cx-hw, cy+hh, hw, hh);
q->se = qnode_new(p, cx+hw, cy+hh, hw, hh);
}
static int qnode_insert(qtree q, qnode *qn, void *ptr) {
int ret = 0;
if(! (q->cmpfnc)(ptr, &qn->bound)) return 0;
if(qn->cnt < qtree_getMaxNodeCnt(q)) {
add(qn, ptr);
return 1;
}
if(! qn->nw)
subdivide(q, qn);
if(qnode_insert(q,qn->nw,ptr))
return 1;
else if(qnode_insert(q,qn->ne,ptr))
return 1;
else if(qnode_insert(q,qn->sw,ptr))
return 1;
else if(qnode_insert(q,qn->se,ptr))
return 1;
}
static void* qnode_remove(qtree q, qnode *qn, void *ptr) {
if(qn->cnt) {
for(uint16_t i=0; i<qn->cnt; i++) {
if(q->rmfnc(qn->elist[i], ptr)) {
drop(qn, i);
ptr = NULL;
goto QN_REM_EXIT;
}
}
}
if(! qn->nw)
return NULL;
if(qnode_remove(q, qn->nw, ptr)) return ptr;
if(qnode_remove(q, qn->ne, ptr)) return ptr;
if(qnode_remove(q, qn->sw, ptr)) return ptr;
if(qnode_remove(q, qn->se, ptr)) return ptr;
return NULL;
QN_REM_EXIT:
return ptr;
}
static void qnode_getInRange(qtree q, qnode *qn, retlist *r) {
if(qn->cnt) {
if(! aabb_intersects(&qn->bound, &r->range))
goto QN_GET_EXIT;
for(uint16_t i=0; i<qn->cnt; i++)
if((q->cmpfnc)(qn->elist[i], &r->range))
retlist_add(r, qn->elist[i]);
}
if(! qn->nw)
goto QN_GET_EXIT;
qnode_getInRange(q, qn->nw, r);
qnode_getInRange(q, qn->ne, r);
qnode_getInRange(q, qn->sw, r);
qnode_getInRange(q, qn->se, r);
QN_GET_EXIT:
return;
}
qtree qtree_new(float x, float y, float w, float h, qtree_fnc fnc, qtree_rm rm) {
qtree q = malloc(sizeof(_qtree));
memset(q, 0, sizeof(_qtree));
q->maxnodecap = QTREE_STDCAP;
q->cmpfnc = fnc;
q->rmfnc = rm;
q->root = qnode_new(q, x+(w/2),y+(h/2),w/2,h/2);
return q;
}
void qtree_destroy(qtree q) {
void *m;
if(q->root) qnode_free(q, q->root);
memset(q, 0, sizeof(_qtree));
free(q);
}
void qtree_insert(qtree q, void *ptr) {
qnode_insert(q, q->root, ptr);
}
void qtree_remove(qtree q, void *ptr) {
qnode_remove(q, q->root, ptr);
}
void qtree_setMaxNodeCnt(qtree q, uint16_t cnt) {
q->maxnodecap = cnt || 1;
}
void qtree_clear(qtree q) {
float x = q->root->bound.center.x;
float y = q->root->bound.center.y;
float w = q->root->bound.dims.w;
float h = q->root->bound.dims.h;
qnode *qn = q->root;
q->root = qnode_new(q, x, y, w, h);
qnode_free(q, qn);
}
void** qtree_findInArea(qtree q, float x, float y, float w, float h, uint32_t *cnt) {
float hw = w/2;
float hh = h/2;
retlist ret;
memset(&ret, 0, sizeof(retlist));
ret.range.center.x = x+hw;
ret.range.center.y = y+hh;
ret.range.dims.w = hw;
ret.range.dims.h = hh;
qnode_getInRange(q, q->root, &ret);
*cnt = ret.cnt;
return ret.list;
}

View File

@@ -1,78 +0,0 @@
/*
quadtree.h
2014 JSK (kutani@projectkutani.com)
Part of the Panic Panic project.
Released to the public domain. See LICENSE for details.
*/
#ifndef _QUADTREE_H
#define _QUADTREE_H
#ifndef _AABB_H
#include "aabb.h"
#endif
/// Opaque pointer to a quadtree data structure
typedef struct _qtree* qtree;
/// A function pointer def for determining if an element exists in a range
typedef int (*qtree_fnc)(void *ptr, aabb *range);
typedef int (*qtree_rm)(void *ptr, void *cmp);
/// Create a new qtree
/*!
Creates a new qtree with a bound of w,h size, centered at x,y.
Uses the passed function pointer fnc to test elements against nodes
for insertion, and finding.
Returns a new qtree pointer.
*/
qtree qtree_new(float x, float y, float w, float h, qtree_fnc fnc, qtree_rm rm);
void qtree_destroy(qtree q);
/// Insert an element
/*!
Inserts the passed element into quadtree q.
Uses the function passed to qtree_new() to determine where the
element should go.
*/
void qtree_insert(qtree q, void *ptr);
/// Removes an element from the quadtree
/*!
Performs a selective removal of the passed element.
Performs a naive pointer comparison and a depth-first search of the
tree, so this isn't very fast.
*/
void qtree_remove(qtree q, void *ptr);
/// Set the maximum number of elements per node
/*!
Sets the maximum elements per quadtree node.
The default is 4.
*/
void qtree_setMaxNodeCnt(qtree q, uint16_t cnt);
/// Resets a quadtree
/*!
Clears all nodes held by the quadtree and creates a fresh root node
with no elements assigned.
*/
void qtree_clear(qtree q);
/// Find all elements within a rectangular bound
/*!
Performs a search for any elements within the given x,y + w,h
bound. Returns an array of pointers to any elements (which should be
freed by the user), and places the number of elements in cnt.
*/
void** qtree_findInArea(qtree q, float x, float y, float w, float h, uint32_t *cnt);
#endif

View File

@@ -27,7 +27,7 @@ static JSRuntime *rt = NULL;
JSContext *global_js = NULL;
JSValue on_exception = JS_UNDEFINED;
JSValue on_exception;
#define ENGINE "scripts/core/engine.js"
@@ -158,6 +158,8 @@ void script_startup(int argc, char **argv) {
JS_AddIntrinsicBigDecimal(js);
JS_AddIntrinsicOperators(js);
on_exception = JS_UNDEFINED;
ffi_load(js, argc, argv);
PHYSFS_File *eng = PHYSFS_openRead(ENGINE);

View File

@@ -3,318 +3,447 @@
#include "transform.h"
#include "math.h"
/* -------------------------------------------------------------------------
Cubic Spline Basis Matrices
------------------------------------------------------------------------- */
static const HMM_Mat4 cubic_hermite_m = {
2, -2, 1, 1,
-3, 3, -2, -1,
0, 0, 1, 0,
1, 0, 0, 0
2, -2, 1, 1,
-3, 3, -2, -1,
0, 0, 1, 0,
1, 0, 0, 0
};
static const HMM_Mat4 cubic_hermite_dm = {
0, 0, 0, 0,
6, -6, 3, 3,
-6, 6, -4, -2,
0, 0, 1, 0
0, 0, 0, 0,
6, -6, 3, 3,
-6, 6, -4, -2,
0, 0, 1, 0
};
static const HMM_Mat4 cubic_hermite_ddm = {
0, 0, 0, 0,
0, 0, 0, 0,
12, -12, 6, 6,
-6, 6, -4, -2
0, 0, 0, 0,
0, 0, 0, 0,
12, -12, 6, 6,
-6, 6, -4, -2
};
static const HMM_Mat4 cubic_hermite_dddm = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
12, -12, 6, 6
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
12, -12, 6, 6
};
static const HMM_Mat4 b_spline_m = {
-1/6, 3/6, -3/6, 1,
3/6, -6/6, 3/6, 0,
-3/6, 0, 3/6, 0,
1/6, 4/6, 1/6, 0
-1.0f/6, 3.0f/6, -3.0f/6, 1.0f,
3.0f/6, -6.0f/6, 3.0f/6, 0.0f,
-3.0f/6, 0.0f, 3.0f/6, 0.0f,
1.0f/6, 4.0f/6, 1.0f/6, 0.0f
};
static const HMM_Mat4 b_spline_dm = {
0, 0, 0, 0,
-3/6, 9/6, -9/6, 3,
6/6, -12/6, 6/6, 0,
-3/6, 0, 3/6, 0
0, 0, 0, 0,
-3.0f/6, 9.0f/6, -9.0f/6, 3.0f,
6.0f/6, -12.0f/6, 6.0f/6, 0.0f,
-3.0f/6, 0.0f, 3.0f/6, 0.0f
};
static const HMM_Mat4 b_spline_ddm = {
0, 0, 0, 0,
0, 0, 0, 0,
-6/6, 18/6, -18/6, 6,
6/6, -12/6, 6/6, 0
0, 0, 0, 0,
0, 0, 0, 0,
-6.0f/6, 18.0f/6, -18.0f/6, 6.0f,
6.0f/6, -12.0f/6, 6.0f/6, 0.0f
};
static const HMM_Mat4 b_spline_dddm = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
-6/6, 18/6, -18/6, 6
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
-6.0f/6, 18.0f/6, -18.0f/6, 6.0f
};
static const HMM_Mat4 bezier_m = {
-1, 3, -3, 1,
3, -6, 3, 0,
-3, 3, 0, 0,
1, 0, 0, 0
-1, 3, -3, 1,
3, -6, 3, 0,
-3, 3, 0, 0,
1, 0, 0, 0
};
static const HMM_Mat4 bezier_dm = {
0, 0, 0, 0,
-3, 9, -9, 3,
6, -12, 6, 0,
-3, 3, 0, 0,
0, 0, 0, 0,
-3, 9, -9, 3,
6, -12, 6, 0,
-3, 3, 0, 0
};
static const HMM_Mat4 bezier_ddm = {
0, 0, 0, 0,
0, 0, 0, 0,
-6, 18, -18, 6,
6, -12, 6, 0
0, 0, 0, 0,
0, 0, 0, 0,
-6, 18, -18, 6,
6, -12, 6, 0
};
static const HMM_Mat4 bezier_dddm = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
-6, 18, -18, 6
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
-6, 18, -18, 6
};
#define CAT_S 0.5
/* CatmullRom (with tension = 0.5 by default) */
#define CAT_S 0.5f
/* Position */
static const HMM_Mat4 catmull_rom_m = {
-CAT_S, 2-CAT_S, CAT_S-2, CAT_S,
2*CAT_S, CAT_S-3, 3-2*CAT_S, -CAT_S,
-CAT_S, 0, CAT_S, 0,
0, 1, 0, 0
-CAT_S, 2-CAT_S, CAT_S-2, CAT_S,
2*CAT_S, CAT_S-3, 3-2*CAT_S, -CAT_S,
-CAT_S, 0, CAT_S, 0,
0, 1, 0, 0
};
/* Tangent */
static const HMM_Mat4 catmull_rom_dm = {
0, 0, 0, 0,
-3*CAT_S, 9*CAT_S, -9*CAT_S, 3*CAT_S,
4*CAT_S, -10*CAT_S, 8*CAT_S, -2*CAT_S,
-CAT_S, 0, CAT_S, 0,
0, 0, 0, 0,
-3*CAT_S, 9*CAT_S, -9*CAT_S, 3*CAT_S,
4*CAT_S, -10*CAT_S, 8*CAT_S, -2*CAT_S,
-CAT_S, 0, CAT_S, 0
};
/* Curvature */
static const HMM_Mat4 catmull_rom_ddm = {
0, 0, 0, 0,
0, 0, 0, 0,
-9*CAT_S, 18*CAT_S, -18*CAT_S, 6*CAT_S,
4*CAT_S, -10*CAT_S, 8*CAT_S, -2*CAT_S
0, 0, 0, 0,
0, 0, 0, 0,
-9*CAT_S, 18*CAT_S, -18*CAT_S, 6*CAT_S,
4*CAT_S, -10*CAT_S, 8*CAT_S, -2*CAT_S
};
/* Wiggle */
static const HMM_Mat4 catmull_rom_dddm = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
-9*CAT_S, 18*CAT_S, -18*CAT_S, 6*CAT_S
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
-9*CAT_S, 18*CAT_S, -18*CAT_S, 6*CAT_S
};
/*
[t3 t2 t1 1] B [p1
p2 that is, point 1, tangent at point 1, point 2, tan and point 2
t1
t2]
*/
/* -------------------------------------------------------------------------
Core “C·T” multiplication: [ t^3, t^2, t, 1 ] * C
------------------------------------------------------------------------- */
HMM_Vec4 spline_CT(HMM_Mat4 *C, float t)
{
float t2 = t*t;
float t3 = t2*t;
HMM_Vec4 T = {t3, t2, t, 1};
return HMM_MulM4V4(*C, T);
float t2 = t * t;
float t3 = t2 * t;
HMM_Vec4 T = { t3, t2, t, 1.0f };
return HMM_MulM4V4(*C, T);
}
/* Construct the “geometry matrix” G from four 2D points, then multiply by B */
HMM_Mat4 make_C(const HMM_Vec2 *p, const HMM_Mat4 *B)
{
HMM_Mat4 G;
G.Columns[0].xy = p[0];
G.Columns[1].xy = p[1];
G.Columns[2].xy = p[2];
G.Columns[3].xy = p[3];
return HMM_MulM4(G, *B);
HMM_Mat4 G = HMM_M4(); // Zeroed out
// Only fill XY of each column; if you are storing 3D in HMM_Vec4, adapt as needed
G.Columns[0].XY = p[0];
G.Columns[1].XY = p[1];
G.Columns[2].XY = p[2];
G.Columns[3].XY = p[3];
return HMM_MulM4(G, *B);
}
/* Evaluate a single-segment cubic spline at parameter d in [0,1].
p must be 4 control points, m is the cubic basis matrix. */
HMM_Vec2 cubic_spline_d(HMM_Vec2 *p, HMM_Mat4 *m, float d)
{
HMM_Mat4 C = make_C(p, m);
return spline_CT(&C, d).xy;
HMM_Mat4 C = make_C(p, m);
HMM_Vec4 v4 = spline_CT(&C, d);
return v4.XY;
}
/* -------------------------------------------------------------------------
Convenience single-segment functions for each basis
(pos / tan / curv / wig all require the appropriate matrix)
Typically you pass p[0..3] as the 4 relevant control points.
------------------------------------------------------------------------- */
HMM_Vec2 cubic_hermite_pos(HMM_Vec2 *p, float d) { return cubic_spline_d(p, (HMM_Mat4 *)&cubic_hermite_m, d); }
HMM_Vec2 cubic_hermite_tan(HMM_Vec2 *p, float d) { return cubic_spline_d(p, (HMM_Mat4 *)&cubic_hermite_dm, d); }
HMM_Vec2 cubic_hermite_curv(HMM_Vec2 *p, float d){ return cubic_spline_d(p, (HMM_Mat4 *)&cubic_hermite_ddm, d); }
HMM_Vec2 cubic_hermite_wig(HMM_Vec2 *p, float d) { return cubic_spline_d(p, (HMM_Mat4 *)&cubic_hermite_dddm, d); }
HMM_Vec2 b_spline_pos(HMM_Vec2 *p, float d) { return cubic_spline_d(p, (HMM_Mat4 *)&b_spline_m, d); }
HMM_Vec2 b_spline_tan(HMM_Vec2 *p, float d) { return cubic_spline_d(p, (HMM_Mat4 *)&b_spline_dm, d); }
HMM_Vec2 b_spline_curv(HMM_Vec2 *p, float d){ return cubic_spline_d(p, (HMM_Mat4 *)&b_spline_ddm, d); }
HMM_Vec2 b_spline_wig(HMM_Vec2 *p, float d) { return cubic_spline_d(p, (HMM_Mat4 *)&b_spline_dddm, d); }
HMM_Vec2 bezier_pos(HMM_Vec2 *p, float d) { return cubic_spline_d(p, (HMM_Mat4 *)&bezier_m, d); }
HMM_Vec2 bezier_tan(HMM_Vec2 *p, float d) { return cubic_spline_d(p, (HMM_Mat4 *)&bezier_dm, d); }
HMM_Vec2 bezier_curv(HMM_Vec2 *p, float d){ return cubic_spline_d(p, (HMM_Mat4 *)&bezier_ddm, d); }
HMM_Vec2 bezier_wig(HMM_Vec2 *p, float d) { return cubic_spline_d(p, (HMM_Mat4 *)&bezier_dddm, d); }
/* -------------------------------------------------------------------------
Multi-segment sampling (“spline_v2”) for uniform division
------------------------------------------------------------------------- */
HMM_Vec2 *spline_v2(HMM_Vec2 *p, HMM_Mat4 *m, int segs)
{
HMM_Vec2 *ret = NULL;
if (segs < 2) return NULL;
// For a single 4-point segment, produce 'segs' points along [0..1).
// If you want the final 1.0 also, you can do <= 1.0 in the loop, etc.
HMM_Vec2 *ret = NULL;
if (segs < 2) return NULL;
HMM_Mat4 C = make_C(p, m);
float s = (float)1/segs;
for (float t = 0; t < 1; t += s)
arrput(ret, spline_CT(&C, t).xy);
return ret;
HMM_Mat4 C = make_C(p, m);
float s = 1.0f / (float)segs;
for (int i = 0; i <= segs; i++)
{
float t = s * i;
arrput(ret, spline_CT(&C, t).XY);
}
return ret;
}
/* -------------------------------------------------------------------------
Adaptive subdivision by min segment length
(spline2d_min_seg) for a single 4-point segment
------------------------------------------------------------------------- */
HMM_Vec2 *spline2d_min_seg(float u0, float u1, float min_seg, HMM_Mat4 *C, HMM_Vec2 *ret)
{
HMM_Vec2 a = spline_CT(C, u0).xy;
HMM_Vec2 b = spline_CT(C, u1).xy;
if (HMM_DistV2(a,b) > min_seg) {
float umid = (u0+u1)/2;
spline2d_min_seg(u0, umid, min_seg, C, ret);
spline2d_min_seg(umid, u1, min_seg, C, ret);
}
else
arrput(ret, b);
return ret;
HMM_Vec2 a = spline_CT(C, u0).XY;
HMM_Vec2 b = spline_CT(C, u1).XY;
if (HMM_DistV2(a, b) > min_seg)
{
float umid = 0.5f * (u0 + u1);
spline2d_min_seg(u0, umid, min_seg, C, ret);
spline2d_min_seg(umid, u1, min_seg, C, ret);
}
else
{
// We push 'b' so that we don't double-push 'a'
arrput(ret, b);
}
return ret;
}
/* Example: catmull_rom_min_seg -> subdiv for catmullrom over one segment
You would decide how to pick the 4 points from a,b,c,d, then run. */
HMM_Vec2 *catmull_rom_min_seg(HMM_Vec2 *a, HMM_Vec2 *b, HMM_Vec2 *c, HMM_Vec2 *d, float min_seg)
{
HMM_Vec2 *ret = NULL;
arrsetcap(ret, 1000);
arrput(ret, *b);
// spline2d_min_seg(0, 1, min_seg, &C, ret);
return ret;
HMM_Vec2 *ret = NULL;
arrsetcap(ret, 1000);
// Build the matrix for these four points
HMM_Vec2 p[4] = { *a, *b, *c, *d };
HMM_Mat4 C = make_C(p, &catmull_rom_m);
// Always push the starting point (b in your original code was the second ctrl point, etc.)
// But usually we want the first actual point in the segment:
arrput(ret, cubic_spline_d(p, (HMM_Mat4*)&catmull_rom_m, 0.0f));
// Actually subdiv
spline2d_min_seg(0.0f, 1.0f, min_seg, &C, ret);
return ret;
}
/* -------------------------------------------------------------------------
Adaptive subdivision by “max angle” proxy
(spline2d_min_angle_2) for single 4-point segment
------------------------------------------------------------------------- */
HMM_Vec2 *spline2d_min_angle_2(float u0, float u1, float max_angle, HMM_Mat4 *C, HMM_Vec2 *arr)
{
float ustep = (u1-u0)/4;
float um0 = u0+ustep;
float um1 = u0+(ustep*2);
float um2 = u0+(ustep*3);
// Heuristic approach: sample midpoints, check “chord vs polyline” difference
float ustep = (u1 - u0) / 4.0f;
float um0 = u0 + ustep;
float um1 = u0 + 2.0f * ustep;
float um2 = u0 + 3.0f * ustep;
HMM_Vec2 m0 = spline_CT(C, um0)._2;
HMM_Vec2 m1 = spline_CT(C, um1)._2;
HMM_Vec2 m2 = spline_CT(C,um2)._2;
HMM_Vec2 m0 = spline_CT(C, um0).XY;
HMM_Vec2 m1 = spline_CT(C, um1).XY;
HMM_Vec2 m2 = spline_CT(C, um2).XY;
HMM_Vec2 a = spline_CT(C,u0)._2;
HMM_Vec2 b = spline_CT(C,u1)._2;
HMM_Vec2 a = spline_CT(C, u0).XY;
HMM_Vec2 b = spline_CT(C, u1).XY;
float ab = HMM_DistV2(a,b);
float cdist = HMM_DistV2(a,m0) + HMM_DistV2(m0,m1) + HMM_DistV2(m1,m2) + HMM_DistV2(m2,b);
// Chord = distance from a to b
float chord = HMM_DistV2(a, b);
// Polyline = a->m0->m1->m2->b
float cdist = HMM_DistV2(a, m0)
+ HMM_DistV2(m0, m1)
+ HMM_DistV2(m1, m2)
+ HMM_DistV2(m2, b);
if (cdist-ab > max_angle) {
arr = spline2d_min_angle_2(u0,um1,max_angle,C,arr);
arr = spline2d_min_angle_2(um1,u1,max_angle,C,arr);
} else
arrput(arr,b);
return arr;
// If the difference is bigger than some threshold (max_angle),
// subdivide. Otherwise, keep it.
if ((cdist - chord) > max_angle)
{
arr = spline2d_min_angle_2(u0, um1, max_angle, C, arr);
arr = spline2d_min_angle_2(um1, u1, max_angle, C, arr);
}
else
{
// We accept “b” as a new point
arrput(arr, b);
}
return arr;
}
HMM_Vec2 *spline_min_angle(HMM_Vec2 *p, const HMM_Mat4 *B, float min_angle, HMM_Vec2 *arr)
{
HMM_Mat4 C = make_C(p, B);
arr = spline2d_min_angle_2(0,1,min_angle, &C, arr);
return arr;
HMM_Mat4 C = make_C(p, B);
// Subdivide from 0..1
float u0 = 0.0f, u1 = 1.0f;
// Usually we want to ensure the start point is in arr:
HMM_Vec2 startPt = spline_CT(&C, u0).XY;
if (arrlen(arr) == 0) {
arrput(arr, startPt);
}
// Now subdiv for angle
arr = spline2d_min_angle_2(u0, u1, min_angle, &C, arr);
return arr;
}
/* Example: catmull_rom_ma_v2 uses “min_angle” over multiple segments
Each 4 consecutive points is one segment. We do this for all segments. */
HMM_Vec2 *catmull_rom_ma_v2(HMM_Vec2 *cp, float ma)
{
if (arrlen(cp) < 4) return NULL;
HMM_Vec2 *ret = NULL;
int n = arrlen(cp);
if (n < 4) return NULL;
int segments = arrlen(cp)-3;
arrsetcap(ret,segments*(ma>=2 ? 3 : 7));
arrput(ret, cp[1]);
for (int i = 0; i < arrlen(cp)-3; i++)
ret = spline_min_angle(&cp[i], &catmull_rom_m, ma, ret);
HMM_Vec2 *ret = NULL;
// Pre-allocate some capacity
arrsetcap(ret, (n-3) * 8);
return ret;
// For convenience, let's always ensure we push the very first point:
arrput(ret, cp[0]);
// For each segment [i, i+1, i+2, i+3], adaptively sample
// Then move i by 1 each time if you want CatmullRom in “overlapped” fashion
for (int i = 0; i < n - 3; i++)
{
// p[i..i+3]
ret = spline_min_angle(&cp[i], &catmull_rom_m, ma, ret);
}
return ret;
}
/* Example: do the same with Bezier in “cubic-bezier” style (control points in groups of 3 “handles”) */
HMM_Vec2 *bezier_cb_ma_v2(HMM_Vec2 *cp, float ma)
{
if (arrlen(cp) < 4) return NULL;
HMM_Vec2 *ret = NULL;
int segments = arrlen(cp)-3;
arrsetcap(ret,segments*(ma>=2?3:7));
arrput(ret,cp[0]);
for (int i = 0; i < arrlen(cp)-3; i+=3)
ret = spline_min_angle(&cp[i], &bezier_m, ma, ret);
int n = arrlen(cp);
// Typically a Bezier “chain” would use control points in multiples of 3 + 1, etc.
// E.g. p[0] is start, p[1..3] are control handles for first segment, then p[3..6] for second, etc.
// Adjust logic to your liking.
if (n < 4) return NULL;
return ret;
HMM_Vec2 *ret = NULL;
arrsetcap(ret, (n/3) * 8);
// First point
arrput(ret, cp[0]);
// For each cubic Bezier segment: i += 3
for (int i = 0; i < n - 3; i += 3)
{
ret = spline_min_angle(&cp[i], &bezier_m, ma, ret);
}
return ret;
}
HMM_Vec2 catmull_rom_query(HMM_Vec2 *cp, float d, const HMM_Mat4 *G)
static HMM_Vec2 catmull_rom_query_internal(HMM_Vec2 *cp, float d, const HMM_Mat4 *M)
{
if (arrlen(cp) < 4 || d < 0 || d > 1) return HMM_V2(0,0);
int n = arrlen(cp);
if (n < 4) return HMM_V2(0,0);
int segs = arrlen(cp)-3;
float d_per_seg = (float)1/segs;
float maxi = d_per_seg;
int p1 = 2;
while (maxi < d) {
maxi += d_per_seg;
p1++;
}
// Number of segments:
int seg_count = n - 3;
// Scale d in [0..1] -> which segment?
float segf = d * seg_count;
int seg_idx = (int) floorf(segf);
if (seg_idx >= seg_count) seg_idx = seg_count - 1;
if (seg_idx < 0) seg_idx = 0;
return cp[0];
// return cubic_spline_d(p0, cp[p1], cp[p1+1], p3, G, d);
// Local parameter in [0..1]
float u = segf - seg_idx;
// The control points for that segment are cp[ seg_idx .. seg_idx+3 ]
return cubic_spline_d(cp + seg_idx, (HMM_Mat4 *)M, u);
}
float spline_seglen(float t0, float t1, float max_angle, HMM_Mat4 *Cd, HMM_Mat4 *C)
HMM_Vec2 catmull_rom_pos(HMM_Vec2 *cp, float d)
{
float total = 0;
float step = 0.1;
for (float i = t0; i < t1; i += step)
total += HMM_LenV2(spline_CT(Cd, i).xy) * step;
return total;
/* Estimation via max angle */
/* float total = 0.0;
float tmid = (t0+t1)/2;
HMM_Vec2 a = spline_CT(C, t0).xy;
HMM_Vec2 b = spline_CT(C, t1).xy;
HMM_Vec2 m = spline_CT(C, tmid).xy;
if (HMM_AngleV2(m,b) > max_angle) {
total += spline_seglen(t0, tmid, max_angle, Cd, C);
total += spline_seglen(tmid, t1, max_angle, Cd, C);
} else
return HMM_LenV2(spline_CT(Cd, t0).xy)*(t1-t0);
return total;
*/
return catmull_rom_query_internal(cp, d, &catmull_rom_m);
}
HMM_Vec2 catmull_rom_tan(HMM_Vec2 *cp, float d)
{
return catmull_rom_query_internal(cp, d, &catmull_rom_dm);
}
HMM_Vec2 catmull_rom_curv(HMM_Vec2 *cp, float d)
{
return catmull_rom_query_internal(cp, d, &catmull_rom_ddm);
}
HMM_Vec2 catmull_rom_wig(HMM_Vec2 *cp, float d)
{
return catmull_rom_query_internal(cp, d, &catmull_rom_dddm);
}
/* -------------------------------------------------------------------------
Approximate length of a single 4-point cubic spline segment by
numeric integration (or sampling) of the velocity magnitude.
“spline_seglen” below does a quick sampling approach.
------------------------------------------------------------------------- */
float spline_seglen(float t0, float t1, int steps, HMM_Mat4 *Cd, HMM_Mat4 *C)
{
// Simple uniform sampling of the tangent magnitude
float total = 0.0f;
float dt = (t1 - t0) / (float) steps;
for (int i = 0; i < steps; i++)
{
float t = t0 + (i + 0.5f) * dt; // midpoint rule
// derivative at t
HMM_Vec2 vel = spline_CT(Cd, t).XY;
float speed = HMM_LenV2(vel);
total += speed * dt;
}
return total;
}
/* Summation of lengths across all CatmullRom segments. */
float catmull_rom_len(HMM_Vec2 *cp)
{
float len = 0.0;
int segs = arrlen(cp)-3;
float d_per_seg = (float)1/segs;
float maxi = d_per_seg;
for (int i = 0; i < arrlen(cp)-3; i++) {
HMM_Mat4 C = make_C(&cp[i], &catmull_rom_m);
HMM_Mat4 Cd = make_C(&cp[i], &catmull_rom_dm);
len += spline_seglen(0, 1, 0.1, &Cd, &C);
}
return len;
}
int stepsPerSegment = 64;
float len = 0.0f;
int n = arrlen(cp);
if (n < 4) return 0.0f;
/* d is from 0 to 1 for the entire spline */
HMM_Vec2 catmull_rom_pos(HMM_Vec2 *cp, float d) { return catmull_rom_query(cp,d,&catmull_rom_m); }
HMM_Vec2 catmull_rom_tan(HMM_Vec2 *cp, float d) { return catmull_rom_query(cp,d,&catmull_rom_dm); }
HMM_Vec2 catmull_rom_curv(HMM_Vec2 *cp, float d) { return catmull_rom_query(cp,d,&catmull_rom_ddm); }
HMM_Vec2 catmull_rom_wig(HMM_Vec2 *cp, float d) { return catmull_rom_query(cp,d,&catmull_rom_dddm); }
for (int i = 0; i < n - 3; i++)
{
// Build the position matrix & derivative matrix for this segment
HMM_Mat4 C = make_C(&cp[i], &catmull_rom_m);
HMM_Mat4 Cd = make_C(&cp[i], &catmull_rom_dm);
// integrate from 0..1
len += spline_seglen(0.0f, 1.0f, stepsPerSegment, &Cd, &C);
}
return len;
}
HMM_Vec2 catmull_rom_closest(HMM_Vec2 *cp, HMM_Vec2 p)
{
return p;
int n = arrlen(cp);
if (n < 4) return p;
float bestDist = FLT_MAX;
HMM_Vec2 bestPt = p;
int steps = 64; // more steps => more accurate
for (int seg = 0; seg < n - 3; seg++)
{
// Build a single-segment matrix
HMM_Vec2 segCP[4] = { cp[seg], cp[seg+1], cp[seg+2], cp[seg+3] };
HMM_Mat4 C = make_C(segCP, &catmull_rom_m);
for (int i = 0; i <= steps; i++)
{
float t = (float)i / steps;
HMM_Vec2 pt = spline_CT(&C, t).XY;
float dist = HMM_DistV2(p, pt);
if (dist < bestDist)
{
bestDist = dist;
bestPt = pt;
}
}
}
return bestPt;
}

View File

@@ -3,21 +3,83 @@
#include "HandmadeMath.h"
HMM_Vec2 *catmull_rom_ma_v2(HMM_Vec2 *cp, float ma);
HMM_Vec3 *catmull_rom_ma_v3(HMM_Vec3 *cp, float ma);
HMM_Vec4 *catmull_rom_ma_v4(HMM_Vec4 *cp, float ma);
#ifdef __cplusplus
extern "C" {
#endif
/*
These were already in your original header:
*/
// Adaptive CatmullRom in 2D / 3D / 4D (by minimum angle):
HMM_Vec2 *catmull_rom_ma_v2(HMM_Vec2 *cp, float ma);
HMM_Vec3 *catmull_rom_ma_v3(HMM_Vec3 *cp, float ma); /* not yet implemented in .c, placeholder */
HMM_Vec4 *catmull_rom_ma_v4(HMM_Vec4 *cp, float ma); /* not yet implemented in .c, placeholder */
// Adaptive Bezier in 2D (by minimum angle):
HMM_Vec2 *bezier_cb_ma_v2(HMM_Vec2 *cp, float ma);
// Generic “single-segment” query for 2D control points + basis matrix:
HMM_Vec2 spline_query(HMM_Vec2 *cp, float d, HMM_Mat4 *basis);
HMM_Vec2 catmull_rom_pos(HMM_Vec2 *cp, float d);
HMM_Vec2 catmull_rom_tan(HMM_Vec2 *cp, float d);
HMM_Vec2 catmull_rom_curv(HMM_Vec2 *cp, float d);
HMM_Vec2 catmull_rom_wig(HMM_Vec2 *cp, float d);
// CatmullRom “entire spline” queries:
HMM_Vec2 catmull_rom_pos(HMM_Vec2 *cp, float d); // position
HMM_Vec2 catmull_rom_tan(HMM_Vec2 *cp, float d); // tangent
HMM_Vec2 catmull_rom_curv(HMM_Vec2 *cp, float d); // curvature
HMM_Vec2 catmull_rom_wig(HMM_Vec2 *cp, float d); // 3rd derivative (“wiggle”)
// Computes approximate length of a 2D CatmullRom spline:
float catmull_rom_len(HMM_Vec2 *cp);
/* Returns closest point on a curve given a point p */
// Returns closest point on a 2D CatmullRom curve given an external 2D point `p`:
HMM_Vec2 catmull_rom_closest(HMM_Vec2 *cp, HMM_Vec2 p);
/*
Additional convenience functions for *single-segment* cubic splines:
Each of these expects exactly 4 control points in `p[0..3]`,
and a parameter t in [0..1]. They pick the appropriate matrix internally.
*/
// Hermite:
HMM_Vec2 cubic_hermite_pos(HMM_Vec2 *p, float d);
HMM_Vec2 cubic_hermite_tan(HMM_Vec2 *p, float d);
HMM_Vec2 cubic_hermite_curv(HMM_Vec2 *p, float d);
HMM_Vec2 cubic_hermite_wig(HMM_Vec2 *p, float d);
// B-spline:
HMM_Vec2 b_spline_pos(HMM_Vec2 *p, float d);
HMM_Vec2 b_spline_tan(HMM_Vec2 *p, float d);
HMM_Vec2 b_spline_curv(HMM_Vec2 *p, float d);
HMM_Vec2 b_spline_wig(HMM_Vec2 *p, float d);
// Bezier:
HMM_Vec2 bezier_pos(HMM_Vec2 *p, float d);
HMM_Vec2 bezier_tan(HMM_Vec2 *p, float d);
HMM_Vec2 bezier_curv(HMM_Vec2 *p, float d);
HMM_Vec2 bezier_wig(HMM_Vec2 *p, float d);
/*
Uniform sampling of a *single* 4-point segment in 2D:
Returns an array of points (stb_ds dynamic array).
*/
HMM_Vec2 *spline_v2(HMM_Vec2 *p, HMM_Mat4 *m, int segs);
/*
Adaptive subdivision routines (single-segment) in 2D:
- Subdivide by min segment length
- Subdivide by “max angle” proxy
*/
HMM_Vec2 *spline2d_min_seg(float u0, float u1, float min_seg, HMM_Mat4 *C, HMM_Vec2 *ret);
HMM_Vec2 *catmull_rom_min_seg(HMM_Vec2 *a, HMM_Vec2 *b, HMM_Vec2 *c, HMM_Vec2 *d, float min_seg);
HMM_Vec2 *spline2d_min_angle_2(float u0, float u1, float max_angle, HMM_Mat4 *C, HMM_Vec2 *arr);
HMM_Vec2 *spline_min_angle(HMM_Vec2 *p, const HMM_Mat4 *B, float min_angle, HMM_Vec2 *arr);
#ifdef __cplusplus
}
#endif
#endif /* SPLINE_H */

View File

@@ -1,17 +1,18 @@
#include "sprite.h"
static sprite model = {
.affine = {x:0,y:0,w:0,h:0},
.image = JS_UNDEFINED,
.affine = {.x = 0, .y = 0, .w = 0, .h = 0},
.tex = NULL,
.uv = {x:0,y:0,w:1,h:1},
.uv = {.x = 0, .y = 0, .w = 1, .h = 1},
.layer = 0,
.color = {1,1,1,1}
.color = {1, 1, 1, 1}
};
sprite *make_sprite()
{
sprite *sprite = malloc(sizeof(*sprite));
*sprite = model;
sprite->image = JS_UNDEFINED;
return sprite;
}

View File

@@ -38,6 +38,7 @@
// Contributors:
// Arpad Goretity (bugfix)
// Alan Hickman (hex floats)
// github:mundusnine (bugfix)
//
// LICENSE
//
@@ -562,7 +563,6 @@ int stb_c_lexer_get_token(stb_lexer *lexer)
{
int n = 0;
lexer->string = lexer->string_storage;
lexer->string_len = n;
do {
if (n+1 >= lexer->string_storage_len)
return stb__clex_token(lexer, CLEX_parse_error, p, p+n);
@@ -576,6 +576,7 @@ int stb_c_lexer_get_token(stb_lexer *lexer)
STB_C_LEX_DOLLAR_IDENTIFIER( || p[n] == '$' )
);
lexer->string[n] = 0;
lexer->string_len = n;
return stb__clex_token(lexer, CLEX_id, p, p+n-1);
}

View File

@@ -1,4 +1,4 @@
/* stb_image - v2.29 - public domain image loader - http://nothings.org/stb
/* stb_image - v2.30 - public domain image loader - http://nothings.org/stb
no warranty implied; use at your own risk
Do this:
@@ -48,6 +48,7 @@ LICENSE
RECENT REVISION HISTORY:
2.30 (2024-05-31) avoid erroneous gcc warning
2.29 (2023-05-xx) optimizations
2.28 (2023-01-29) many error fixes, security errors, just tons of stuff
2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes
@@ -5159,9 +5160,11 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
// non-paletted with tRNS = constant alpha. if header-scanning, we can stop now.
if (scan == STBI__SCAN_header) { ++s->img_n; return 1; }
if (z->depth == 16) {
for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is
for (k = 0; k < s->img_n && k < 3; ++k) // extra loop test to suppress false GCC warning
tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is
} else {
for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger
for (k = 0; k < s->img_n && k < 3; ++k)
tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger
}
}
break;

File diff suppressed because it is too large Load Diff

View File

@@ -54,7 +54,7 @@
// Hou Qiming Derek Vinyard
// Rob Loach Cort Stratton
// Kenney Phillis Jr. Brian Costabile
// Ken Voskuil (kaesve)
// Ken Voskuil (kaesve) Yakov Galka
//
// VERSION HISTORY
//
@@ -4604,6 +4604,8 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
scale_y = -scale_y;
{
// distance from singular values (in the same units as the pixel grid)
const float eps = 1./1024, eps2 = eps*eps;
int x,y,i,j;
float *precompute;
stbtt_vertex *verts;
@@ -4616,15 +4618,15 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y;
float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0));
precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist;
precompute[i] = (dist < eps) ? 0.0f : 1.0f / dist;
} else if (verts[i].type == STBTT_vcurve) {
float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y;
float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y;
float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y;
float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
float len2 = bx*bx + by*by;
if (len2 != 0.0f)
precompute[i] = 1.0f / (bx*bx + by*by);
if (len2 >= eps2)
precompute[i] = 1.0f / len2;
else
precompute[i] = 0.0f;
} else
@@ -4689,8 +4691,8 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
float a = 3*(ax*bx + ay*by);
float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by);
float c = mx*ax+my*ay;
if (a == 0.0) { // if a is 0, it's linear
if (b != 0.0) {
if (STBTT_fabs(a) < eps2) { // if a is 0, it's linear
if (STBTT_fabs(b) >= eps2) {
res[num++] = -c/b;
}
} else {

View File

@@ -13,14 +13,14 @@ static transform model = {
.cache = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1},
.gcache = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1},
.dirty = 0,
.jsparent = JS_UNDEFINED,
.change_hook = JS_UNDEFINED
};
transform *make_transform()
{
transform *t = malloc(sizeof(transform));
*t = model;
t->jsparent = JS_UNDEFINED;
t->change_hook = JS_UNDEFINED;
return t;
}