spline fixes

This commit is contained in:
John Alanbrook 2023-12-20 23:20:29 +00:00
parent a8ee53ec33
commit a03143463e
20 changed files with 134 additions and 118 deletions

View file

@ -51,7 +51,7 @@ ifdef NQOA
endif
ifeq ($(DBG),1)
CPPFLAGS += -g -fsanitize=address
CPPFLAGS += -g #-fsanitize=address
INFO += _dbg
else
CPPFLAGS += -DNDEBUG

View file

@ -787,12 +787,9 @@ Object.defineProperty(String.prototype, 'pct', {
});
Object.defineProperty(String.prototype, 'uc', { value: function() { return this.toUpperCase(); } });
Object.defineProperty(String.prototype, 'lc', {value:function() { return this.toLowerCase(); }});
/* ARRAY DEFS */
Object.defineProperty(Array.prototype, 'copy', {
value: function() {
var c = [];
@ -1199,6 +1196,10 @@ Math.grab_from_points = function(pos, points, slop) {
return idx;
};
Math.nearest = function(n, incr)
{
return Math.round(n/incr)*incr;
}
Number.prec = function(num)
{
@ -1426,6 +1427,10 @@ var Vector = {
return vec.sub(p.scale(2*Vector.dot(vec, p)));
},
reflect_point(vec, point) {
return point.add(vec.sub(point).scale(-1));
},
};
/* POINT ASSISTANCE */

View file

@ -97,14 +97,13 @@ component.sprite.impl = {
set layer(x) { cmd(60, this.id, x); },
get layer() { return undefined; },
emissive(x) { cmd(170, this.id, x); },
pick() { return this; },
move(d) { this.pos = this.pos.add(d); },
boundingbox() {
return cwh2bb([0,0],[0,0]);
var dim = this.dimensions();
dim = dim.scale(this.gameobject.scale);
var realpos = this.pos.copy();
realpos.x = realpos.x * dim.x + (dim.x/2);
realpos.y = realpos.y * dim.y + (dim.y/2);
dim = dim.scale(this.gameobject.gscale());
var realpos = dim.scale(0.5).add(this.pos);
return cwh2bb(realpos,dim);
},
@ -123,6 +122,7 @@ component.model = Object.copy(component, {
component.model.impl = {
set path(x) { cmd(149, this.id, x); },
draw() { cmd(150, this.id); },
kill() { cmd(213, this.id); },
};
var sprite = component.sprite;
@ -134,15 +134,15 @@ sprite.doc = {
};
sprite.inputs = {};
sprite.inputs.kp9 = function() { this.pos = [0,0]; };
sprite.inputs.kp8 = function() { this.pos = [-0.5, 0]; };
sprite.inputs.kp7 = function() { this.pos = [-1,0]; };
sprite.inputs.kp6 = function() { this.pos = [0,-0.5]; };
sprite.inputs.kp5 = function() { this.pos = [-0.5,-0.5]; };
sprite.inputs.kp4 = function() { this.pos = [-1,-0.5]; };
sprite.inputs.kp3 = function() { this.pos = [0, -1]; };
sprite.inputs.kp2 = function() { this.pos = [-0.5,-1]; };
sprite.inputs.kp1 = function() { this.pos = [-1,-1]; };
sprite.inputs.kp9 = function() { this.pos = this.dimensions().scale([0,0]); };
sprite.inputs.kp8 = function() { this.pos = this.dimensions().scale([-0.5, 0]); };
sprite.inputs.kp7 = function() { this.pos = this.dimensions().scale([-1,0]); };
sprite.inputs.kp6 = function() { this.pos = this.dimensions().scale([0,-0.5]); };
sprite.inputs.kp5 = function() { this.pos = this.dimensions().scale([-0.5,-0.5]); };
sprite.inputs.kp4 = function() { this.pos = this.dimensions().scale([-1,-0.5]); };
sprite.inputs.kp3 = function() { this.pos = this.dimensions().scale([0, -1]); };
sprite.inputs.kp2 = function() { this.pos = this.dimensions().scale([-0.5,-1]); };
sprite.inputs.kp1 = function() { this.pos = this.dimensions().scale([-1,-1]); };
Object.seal(sprite);
var SpriteAnim = {
@ -535,8 +535,6 @@ polygon2d.inputs['C-b'] = function() {
};
polygon2d.inputs['C-b'].doc = "Freeze mirroring in place.";
//Object.freeze(polygon2d);
component.edge2d = Object.copy(collider2d, {
dimensions:2,
thickness:0,
@ -544,7 +542,7 @@ component.edge2d = Object.copy(collider2d, {
type: Spline.type.catmull,
C: 1, /* when in bezier, continuity required. 0, 1 or 2. */
looped: false,
angle: 3, /* maximum angle between two segments */
angle: 0.5, /* smaller for smoother bezier */
flipx: false,
flipy: false,
@ -559,8 +557,10 @@ component.edge2d = Object.copy(collider2d, {
var spoints = this.cpoints.slice();
if (this.flipx) {
var endcap = Spline.is_bezier(this.type) ? spoints.length-2 : spoints.length-1;
for (var i = endcap; i >= 0; i--) {
if (Spline.is_bezier(this.type))
spoints.push(Vector.reflect_point(spoints.at(-2), spoints.at(-1)));
for (var i = spoints.length-1; i >= 0; i--) {
var newpoint = spoints[i].slice();
newpoint.x = -newpoint.x;
spoints.push(newpoint);
@ -568,6 +568,9 @@ component.edge2d = Object.copy(collider2d, {
}
if (this.flipy) {
if (Spline.is_bezier(this.type))
spoints.push(Vector.reflect(point(spoints.at(-2),spoints.at(-1))));
for (var i = spoints.length-1; i >= 0; i--) {
var newpoint = spoints[i].slice();
newpoint.y = -newpoint.y;
@ -611,6 +614,9 @@ component.edge2d = Object.copy(collider2d, {
return Spline.sample_angle(this.type, spoints,this.angle);
}
if (this.looped && Spline.is_bezier(this.type))
spoints = Spline.bezier_loop(spoints);
return Spline.sample_angle(this.type, spoints, this.angle);
},
@ -875,7 +881,6 @@ component.circle2d = Object.copy(collider2d, {
toString() { return "circle2d"; },
boundingbox() {
var diameter = this.radius*2*this.gameobject.scale;
return cwh2bb(this.offset.scale(this.gameobject.scale), [this.radius,this.radius]);
},

View file

@ -389,8 +389,6 @@ var editor = {
Debug.boundingbox(bb, Color.Editor.select.alpha(0.1));
Shape.line(bb2points(bb).wrapped(1), Color.white);
}
},
gui() {
@ -459,8 +457,8 @@ var editor = {
Object.entries(thiso.objects).forEach(function(x) {
var p = x[1].namestr();
GUI.text(p, x[1].screenpos().add([0,16]),1,editor.color_depths[depth]);
Shape.circle(x[1].screenpos(),10,Color.blue);
Shape.arrow(x[1].screenpos(), x[1].screenpos().add([0,50]), Color.red, 10);
Shape.circle(x[1].screenpos(),10,Color.blue.alpha(0.3));
Shape.arrow(x[1].screenpos(), x[1].screenpos().add(x[1].up().scale(15)), Color.red, 10);
});
var mg = physics.pos_query(Mouse.worldpos,10);
@ -470,6 +468,9 @@ var editor = {
GUI.text(p, Mouse.screenpos(),1,Color.teal);
}
if (this.rotlist.length === 1)
GUI.text(Math.trunc(this.rotlist[0].obj.angle), Mouse.screenpos(), 1, Color.teal);
if (this.selectlist.length === 1) {
var i = 1;
for (var key in this.selectlist[0].components) {
@ -1143,6 +1144,8 @@ editor.inputs.mouse.move = function(pos, dpos)
editor.rotlist?.forEach(function(x) {
var anglediff = Math.atan2(relpos.y, relpos.x) - x.rotoffset;
x.obj.angle = x.angle + Math.rad2deg(anglediff);
if (Keys.shift())
x.obj.angle = Math.nearest(x.obj.angle, 45);
if (x.pos)
x.obj.pos = x.pos.sub(x.offset).add(x.offset.rotate(anglediff));
});
@ -1151,7 +1154,6 @@ editor.inputs.mouse.move = function(pos, dpos)
editor.inputs.mouse.scroll = function(scroll)
{
scroll.y *= -1;
// editor.grabselect?.forEach(x => x.move(Game.camera.dir_view2world(scroll)));
editor.camera.move(Game.camera.dir_view2world(scroll.scale(-3)));
}

View file

@ -234,42 +234,15 @@ register(9, Log.stack, this);
Register.gamepad_playermap[0] = Player.players[0];
var Signal = {
signals: [],
obj_begin(fn, obj, go) {
this.signals.push([fn, obj]);
register_collide(0, fn, obj, go.body);
},
obj_separate(fn, obj, go) {
this.signals.push([fn,obj]);
register_collide(3,fn,obj,go.body);
},
clear_obj(obj) {
this.signals.filter(function(x) { return x[1] !== obj; });
},
c:{},
register(name, fn) {
if (!this.c[name])
this.c[name] = [];
this.c[name].push(fn);
},
call(name, ...args) {
if (this.c[name])
this.c[name].forEach(function(fn) { fn.call(this, ...args); });
},
};
var game_quit = function()
{
Primum.kill();
}
Signal.register("quit", game_quit);
var Event = {
events: {},
@ -282,6 +255,10 @@ var Event = {
this.events[name] = this.events[name].filter(x => x[0] !== obj);
},
rm_obj(obj) {
Object.keys(this.events).forEach(name => Event.unobserve(name,obj));
},
notify(name) {
if (!this.events[name]) return;
this.events[name].forEach(function(x) {
@ -290,6 +267,8 @@ var Event = {
},
};
Event.observe('quit', undefined, function() { Primum.kill(); });
var Window = {
fullscreen(f) { cmd(145, f); },
set width(w) { cmd(125, w); },
@ -337,6 +316,14 @@ Spline.sample_angle = function(type, points, angle) {
return spline_cmd(0, type, points[0].length, points, angle);
}
Spline.bezier_loop = function(cp)
{
cp.push(Vector.reflect_point(cp.at(-2),cp.at(-1)));
cp.push(Vector.reflect_point(cp[1],cp[0]));
cp.push(cp[0].slice());
return cp;
}
Spline.is_bezier = function(t) { return t === Spline.type.bezier; }
Spline.is_catmull = function(t) { return t === Spline.type.catmull; }
@ -448,6 +435,10 @@ var Game = {
edit: true,
object_count() {
return cmd(214);
},
all_objects(fn) {
/* Wind down from Primum */
},
@ -463,7 +454,7 @@ var Game = {
},
/* List of all objects spawned that have a specific tag */
find_tag(tag) {
find_tag(tag){
},

View file

@ -191,7 +191,7 @@ var gameobject = {
set_gravity(x) { cmd(167, this.body, x); },
set timescale(x) { cmd(168,this.body,x); },
get timescale() { return cmd(169,this.body); },
set phys(x) { console.warn(`Setting phys to ${x}`); set_body(1, this.body, x); },
set phys(x) { set_body(1, this.body, x); },
get phys() { return q_body(0,this.body); },
get velocity() { return q_body(3, this.body); },
set velocity(x) { set_body(9, this.body, x); },
@ -411,7 +411,12 @@ var gameobject = {
/* Bounding box of the object in world dimensions */
boundingbox() {
var boxes = [];
boxes.push({t:0, r:0,b:0,l:0});
boxes.push({
t:0,
r:0,
b:0,
l:0
});
for (var key in this.components) {
if ('boundingbox' in this.components[key])
@ -420,23 +425,11 @@ var gameobject = {
for (var key in this.objects)
boxes.push(this.objects[key].boundingbox());
if (boxes.empty) return cwh2bb([0,0], [0,0]);
var bb = boxes.shift();
var bb = boxes[0];
boxes.forEach(function(x) { bb = bb_expand(bb, x); });
boxes.forEach(function(x) {
bb = bb_expand(bb, x);
});
var cwh = bb2cwh(bb);
if (!bb) return;
if (this.flipx) cwh.c.x *= -1;
if (this.flipy) cwh.c.y *= -1;
cwh.c = cwh.c.add(this.pos);
bb = cwh2bb(cwh.c, cwh.wh);
bb = movebb(bb, this.pos);
return bb ? bb : cwh2bb([0,0], [0,0]);
},
@ -519,8 +512,6 @@ var gameobject = {
this.level = undefined;
}
Player.do_uncontrol(this);
Register.unregister_obj(this);
@ -536,6 +527,7 @@ var gameobject = {
this.clear();
this.objects = undefined;
Event.rm_obj(this);
if (typeof this.stop === 'function')
this.stop();
@ -633,16 +625,12 @@ var gameobject = {
},
register_hit(fn, obj) {
if (!obj)
obj = this;
obj ??= this;
Signal.obj_begin(fn, obj, this);
},
register_separate(fn, obj) {
if (!obj)
obj = this;
obj ??= this;
Signal.obj_separate(fn,obj,this);
},
}

View file

@ -4,18 +4,11 @@ function compile_env(str, env, file)
return cmd(123, str, env, file);
}
function fcompile_env(file, env)
{
return compile_env(IO.slurp(file), env, file);
}
function fcompile_env(file, env) { return compile_env(IO.slurp(file), env, file); }
var OS = {
get cwd() { return cmd(144); },
};
OS.exec = function(s)
{
cmd(143, s);
}
var OS = {};
OS.cwd = function() { return cmd(144); }
OS.exec = function(s) { cmd(143, s); }
var Resources = {};
Resources.images = ["png", "jpg", "jpeg", "gif"];

View file

@ -20,6 +20,7 @@
#define CGLTF_IMPLEMENTATION
#include <cgltf.h>
#include <stdlib.h>
#include <string.h>
@ -32,6 +33,8 @@ static struct {
struct model *value;
} *modelhash = NULL;
struct drawmodel **models = NULL;
static void processnode();
static void processmesh();
static void processtexture();
@ -116,6 +119,8 @@ unsigned short pack_short_texcoord(float x, float y)
return (((unsigned short)yc) << 8) | xc;
}
unsigned short pack_short_tex(float c) { return c * USHRT_MAX; }
uint32_t pack_int10_n2(float *norm)
{
uint32_t ni[3];
@ -157,9 +162,10 @@ void mesh_add_material(mesh *mesh, cgltf_material *mat)
sg_buffer texcoord_floats(float *f, int verts, int comp)
{
unsigned short packed[verts];
for (int i = 0, v = 0; v < verts; i+=comp, v++)
packed[v] = pack_short_texcoord(f[i], f[i+1]);
int n = verts*comp;
unsigned short packed[n];
for (int i = 0, v = 0; i < n; i++)
packed[i] = pack_short_tex(f[i]);
return sg_make_buffer(&(sg_buffer_desc){
.data.ptr = packed,
@ -390,9 +396,16 @@ struct drawmodel *make_drawmodel(gameobject *go)
dm->model = NULL;
dm->amodel = HMM_M4D(1.f);
dm->go = go;
arrpush(models,dm);
return dm;
}
void model_draw_all()
{
for (int i = 0; i < arrlen(models); i++)
draw_drawmodel(models[i]);
}
void draw_drawmodel(struct drawmodel *dm)
{
if (!dm->model) return;
@ -401,5 +414,15 @@ void draw_drawmodel(struct drawmodel *dm)
draw_model(dm->model, rst);
}
void free_drawmodel(struct drawmodel *dm) { free(dm); }
void free_drawmodel(struct drawmodel *dm) {
int rm;
for (int i = 0; i < arrlen(models); i++)
if (models[i] == dm) {
rm = i;
break;
}
arrdelswap(models,rm);
free(dm);
}

View file

@ -53,6 +53,7 @@ void model_init();
struct drawmodel *make_drawmodel(gameobject *go);
void draw_drawmodel(struct drawmodel *dm);
void model_draw_all();
void free_drawmodel(struct drawmodel *dm);
#endif

View file

@ -62,7 +62,7 @@ void mYughLog(int category, int priority, int line, const char *file, const char
char *buffer = malloc(len);
sprintf(buffer, logfmt, file, line, logstr[priority], catstr[category], msg);
fprintf(stderr, buffer);
fprintf(stderr, "%s", buffer);
fflush(stderr);
free(msg);

View file

@ -303,7 +303,7 @@ struct boundingbox text_bb(const unsigned char *text, float scale, float lw, flo
while (!isspace(*line) && *line != '\0') {
wordWidth += font->Characters[*line].Advance * tracking * scale;
line++;
line++;
}
if (lw > 0 && (cursor.X + wordWidth) >= lw) {

View file

@ -25,7 +25,7 @@ struct sFont {
int descent;
int linegap;
float emscale;
struct Character Characters[127];
struct Character Characters[255];
sg_image texID;
};

View file

@ -10,6 +10,8 @@
static gameobject **gameobjects;
int go_count() { return arrlen(gameobjects); }
gameobject *body2go(cpBody *body) { return cpBodyGetUserData(body); }
gameobject *shape2go(cpShape *shape) { return ((struct phys2d_shape *)cpShapeGetUserData(shape))->go; }

View file

@ -53,6 +53,7 @@ struct gameobject {
typedef struct gameobject gameobject;
gameobject *MakeGameobject();
int go_count();
void gameobject_apply(gameobject *go);
void gameobject_free(gameobject *go);
void gameobjects_cleanup();

View file

@ -1120,7 +1120,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
case 143:
str = JS_ToCString(js, argv[1]);
// system(str);
system(str);
break;
case 144:
@ -1349,6 +1349,12 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
case 212:
ret = jsdst();
break;
case 213:
free_drawmodel(js2ptr(argv[1]));
break;
case 214:
ret = int2js(go_count());
break;
}
if (str)

View file

@ -509,6 +509,7 @@ void full_2d_pass(struct window *window)
hudproj = HMM_Orthographic_LH_ZO(0, window->rwidth, 0, window->rheight, -1.f, 1.f);
sprite_draw_all();
model_draw_all();
call_draw();
//// DEBUG

View file

@ -249,7 +249,7 @@ char *slurp_text(const char *filename, size_t *size)
int cp(char *p1, char *p2)
{
long len;
size_t len;
void *data = slurp_file(p1, &len);
FILE *f = fopen_mkdir(p2, "w");

View file

@ -72,6 +72,7 @@ void script_startup() {
void script_stop()
{
timers_free();
script_evalf("Event.notify('quit');");
send_signal("quit",0,NULL);
for (int i = 0; i < shlen(jsstrs); i++)

View file

@ -79,12 +79,9 @@ static int sim_play = SIM_PLAY;
int editor_mode = 0;
const char *engine_info()
{
static char str[100];
snprintf(str, 100, "Yugine version %s, %s build.\nCopyright 2022-2023 odplot productions LLC.\n", VER, INFO);
return str;
}
#define ENGINEINFO "Yugine version " VER ", " INFO " build.\nCopyright 2022-2024."
const char *engine_info() { return ENGINEINFO; }
static int argc;
static char **args;

View file

@ -39,14 +39,6 @@ in float radius;
void main()
{
if (segsize<0)
return;
float f = atan(coords.y, coords.x) + PI;
if (mod(f, segsize) < segsize/2)
discard;
float px = 1/radius;
float R1 = 1.f;
float R2 = 1.0 - fill;
@ -57,6 +49,14 @@ void main()
float sm2 = smoothstep(R2-px,R2,dist);
float a = sm*sm2;
color = mix(vec4(0,0,0,0), fcolor, a);
if (segsize<0)
return;
float f = atan(coords.y, coords.x) + PI;
if (mod(f, segsize) < segsize/2)
discard;
}
@end