massively improve rectangle render time

This commit is contained in:
2024-11-20 14:23:07 -06:00
parent 8313a2d33e
commit 94d0a086c6
8 changed files with 459 additions and 36 deletions

View File

@@ -795,7 +795,7 @@ Object.defineProperty(Array.prototype, "forTo", {
});
Object.defineProperty(Array.prototype, "dofilter", {
value: function (fn) {
value: function array_dofilter(fn) {
for (let i = 0; i < this.length; i++) {
if (!fn.call(this, this[i], i, this)) {
this.splice(i, 1);
@@ -807,19 +807,19 @@ Object.defineProperty(Array.prototype, "dofilter", {
});
Object.defineProperty(Array.prototype, "reversed", {
value: function () {
value: function array_reversed() {
var c = this.slice();
return c.reverse();
},
});
Object.defineProperty(Array.prototype, "rotate", {
value: function (a) {
value: function array_rotate(a) {
return Vector.rotate(this, a);
},
});
Array.random = function(arr) {
Array.random = function random(arr) {
if (!Array.isArray(arr)) return;
return arr[Math.floor(Math.random()*arr.length)];
}

View File

@@ -87,7 +87,6 @@ Resources.replstrs = function replstrs(path) {
var stem = path.dir();
if (!console.enabled) script = Resources.rm_fn(/console\.(spam|info|warn|error)/, script);
if (!profile.enabled) script = Resources.rm_fn(/profile\.(cache|frame|endcache|endframe)/, script);
if (!debug.enabled) {
@@ -340,7 +339,7 @@ io.slurp = function slurp(path)
var findpath = Resources.replpath(path);
var ret = tmpslurp(findpath, true); //|| core_db.slurp(findpath, true);
return ret;
}.hashify();
}
io.slurpbytes = function(path)
{

View File

@@ -86,7 +86,7 @@ clay.draw = function draw(size, fn)
function create_view_fn(base_config)
{
var base = Object.assign(Object.create(clay_base), base_config);
return function(config = {}, fn) {
return function view(config = {}, fn) {
config.__proto__ = base;
var item = add_item(config);
@@ -223,12 +223,11 @@ layout.draw_commands = function draw_commands(cmds, pos = [0,0])
{
var mousepos = prosperon.camera.screen2hud(input.mouse.screenpos());
for (var cmd of cmds) {
cmd.boundingbox.x += pos.x;
cmd.boundingbox.y += pos.y;
cmd.content.x += pos.x;
cmd.content.y += pos.y;
var boundingbox = geometry.rect_move(cmd.boundingbox,pos);
var content = geometry.rect_move(cmd.content,pos);
var config = cmd.config;
if (config.hovered && geometry.rect_point_inside(cmd.boundingbox, mousepos)) {
if (config.hovered && geometry.rect_point_inside(boundingbox, mousepos)) {
config.hovered.__proto__ = config;
config = config.hovered;
hovered = config;
@@ -236,25 +235,31 @@ layout.draw_commands = function draw_commands(cmds, pos = [0,0])
if (config.background_image)
if (config.slice)
render.slice9(config.background_image, cmd.boundingbox, config.slice, config.background_color);
render.slice9(config.background_image, boundingbox, config.slice, config.background_color);
else
render.image(config.background_image, cmd.boundingbox, 0, config.color);
render.image(config.background_image, boundingbox, 0, config.color);
else if (config.background_color)
render.rectangle(cmd.boundingbox, config.background_color);
render.rectangle(boundingbox, config.background_color);
if (config.text)
render.text(config.text, cmd.content, config.font, config.font_size, config.color);
render.text(config.text, content, config.font, config.font_size, config.color);
if (config.image)
render.image(config.image, cmd.content, 0, config.color);
render.image(config.image, content, 0, config.color);
}
}
var dbg_colors = {};
layout.debug_colors = dbg_colors;
dbg_colors.content = [1,0,0,0.1];
dbg_colors.boundingbox = [0,1,0,0,0.1];
dbg_colors.margin = [0,0,1,0.1];
layout.draw_debug = function draw_debug(cmds, pos = [0,0])
{
for (var cmd of cmds) {
render.rectangle(cmd.content, [1,0,0,0.1]);
render.rectangle(cmd.boundingbox, [0,1,0,0.1]);
render.rectangle(cmd.marginbox, [0,0,1,0.1]);
for (var i = 0; i < cmds.length; i++) {
var cmd = cmds[i];
render.rectangle(geometry.rect_move(cmd.content,pos), dbg_colors.content);
render.rectangle(geometry.rect_move(cmd.boundingbox,pos), dbg_colors.boundingbox);
// render.rectangle(geometry.rect_move(cmd.marginbox,pos), dbg_colors.margin);
}
}

View File

@@ -8,6 +8,7 @@ global.check_registers = function check_registers(obj) {
fn.layer = obj[reg].layer;
var name = obj.ur ? obj.ur.name : obj.toString();
obj.timers.push(Register.registries[reg].register(fn, name));
if (!obj[reg].name) Object.defineProperty(obj[reg], 'name', {value:`${obj._file}_${reg}`});
}
}
@@ -550,6 +551,7 @@ var Register = {
var dofn = function (...args) {
fn(...args);
};
Object.defineProperty(dofn, 'name', {value:`do_${oname}`});
var left = 0;
var right = fns.length - 1;
@@ -579,7 +581,7 @@ var Register = {
// tracy.fiber_leave(vector.fib);
};
} else
prosperon[name] = function name(...args) {
prosperon[name] = function (...args) {
var layer = undefined;
for (var fn of fns) {
if (layer !== fn.layer) {
@@ -590,6 +592,7 @@ var Register = {
}
};
Object.defineProperty(prosperon[name], 'name', {value:name});
prosperon[name].fns = fns;
n.clear = function () {
fns = [];

View File

@@ -732,8 +732,9 @@ render.sprites = function render_sprites() {
}
*/
render.use_shader(spritessboshader);
var buckets = component.sprite_buckets();
if (buckets.length === 0) return;
render.use_shader(spritessboshader);
for (var l in buckets) {
var layer = buckets[l];
for (var img in layer) {
@@ -790,7 +791,7 @@ function check_flush(flush_fn) {
}
render.flush = check_flush;
render.forceflush = function()
render.forceflush = function forceflush()
{
if (nextflush) nextflush();
nextflush = undefined;
@@ -871,20 +872,15 @@ render.coordinate = function render_coordinate(pos, size, color) {
var queued_shader;
var queued_pipe;
render.rectangle = function render_rectangle(rect, color = Color.white, shader = polyssboshader, pipe = base_pipeline) {
var wh = [rect.width, rect.height];
var poly = poly_e();
var pos = [rect.x,rect.y].add([rect.width,rect.height].scale(0.5));
pos = pos.sub([rect.width,rect.height].scale([rect.anchor_x,rect.anchor_y]));
poly.transform.move(pos);
poly.transform.scale = [wh.x, wh.y, 1];
poly.transform.rect(rect);
poly.color = color;
queued_shader = shader;
queued_pipe = pipe;
check_flush(flush_poly);
};
render.text = function (str, rect, font = cur_font, size = 0, color = Color.white, wrap = -1, ) {
render.text = function text(str, rect, font = cur_font, size = 0, color = Color.white, wrap = -1, ) {
if (typeof font === 'string')
font = render.get_font(font);
@@ -961,7 +957,7 @@ var stencil_writer = function stencil_writer(ref)
render.stencil_writer = stencil_writer;
// objects by default draw where the stencil buffer is 0
render.fillmask = function(ref)
render.fillmask = function fillmask(ref)
{
render.forceflush();
var pipe = stencil_writer(ref);
@@ -1415,7 +1411,7 @@ try{
if (render.draw_sprites) render.sprites();
prosperon.draw();
if (render.draw_particles) draw_emitters();
render.fillmask(0);
// render.fillmask(0);
render.forceflush();
render.set_projection_ortho({
l:0,
@@ -1468,7 +1464,7 @@ try{
}
};
//if (dmon) dmon.watch('.');
if (dmon) dmon.watch('.');
function dmon_cb(e)
{
@@ -1485,7 +1481,7 @@ function dmon_cb(e)
prosperon.process = function process() {
layout.newframe();
// check for hot reloading
// if (dmon) dmon.poll(dmon_cb);
if (dmon) dmon.poll(dmon_cb);
var dt = profile.secs(profile.now()) - frame_t;
frame_t = profile.secs(profile.now());

View File

@@ -2034,6 +2034,14 @@ JSC_CCALL(transform_trs,
t->scale = JS_IsUndefined(argv[2]) ? v3one : js2vec3(js,argv[2]);
)
JSC_CCALL(transform_rect,
transform *t = js2transform(js,self);
rect r = js2rect(js,argv[0]);
t->pos = (HMM_Vec3){r.x,r.y,0};
t->scale = (HMM_Vec3){r.w,r.h,1};
t->rotation = QUAT1;
)
static const JSCFunctionListEntry js_transform_funcs[] = {
CGETSET_ADD(transform, pos),
CGETSET_ADD(transform, scale),
@@ -2046,9 +2054,9 @@ static const JSCFunctionListEntry js_transform_funcs[] = {
MIST_FUNC_DEF(transform, lookat, 1),
MIST_FUNC_DEF(transform, direction, 1),
MIST_FUNC_DEF(transform, unit, 0),
MIST_FUNC_DEF(transform, rect, 1),
};
JSC_CCALL(datastream_time, return number2js(js,plm_get_time(js2datastream(js,self)->plm)); )
JSC_CCALL(datastream_advance_frames, ds_advanceframes(js2datastream(js,self), js2number(js,argv[0])))
@@ -2232,12 +2240,30 @@ JSC_CCALL(geometry_cwh2rect,
return rect2js(js,r);
)
JSC_CCALL(geometry_rect_pos,
rect r = js2rect(js,argv[0]);
return vec22js(js,(HMM_Vec2){
.x = r.x,
.y = r.y
});
)
JSC_CCALL(geometry_rect_move,
rect r = js2rect(js,argv[0]);
HMM_Vec2 move = js2vec2(js,argv[1]);
r.x += move.x;
r.y += move.y;
return rect2js(js,r);
)
static const JSCFunctionListEntry js_geometry_funcs[] = {
MIST_FUNC_DEF(geometry, rect_intersect, 2),
MIST_FUNC_DEF(geometry, rect_inside, 2),
MIST_FUNC_DEF(geometry, rect_random, 1),
MIST_FUNC_DEF(geometry, cwh2rect, 2),
MIST_FUNC_DEF(geometry, rect_point_inside, 2),
MIST_FUNC_DEF(geometry, rect_pos, 1),
MIST_FUNC_DEF(geometry, rect_move, 2),
};
JSValue js_os_cwd(JSContext *js, JSValue self, int argc, JSValue *argv)

314
source/wildmatch.c Normal file
View File

@@ -0,0 +1,314 @@
/*
* Copyright (c), 2016 David Aguilar
* Based on the fnmatch implementation from OpenBSD.
*
* Copyright (c) 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Guido van Rossum.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include "wildmatch.h"
#ifdef __cplusplus
extern "C" {
#endif
#define EOS '\0'
#define RANGE_MATCH 1
#define RANGE_NOMATCH 0
#define RANGE_ERROR -1
#define check_flag(flags, opts) ((flags) & (opts))
static int rangematch(const char *, char, int, const char **);
int wildmatch(const char *pattern, const char *string, int flags)
{
const char *stringstart;
const char *newp;
const char *slash;
char c, test;
char prev;
int wild = 0;
/* WM_WILDSTAR implies WM_PATHNAME. */
if (check_flag(flags, WM_WILDSTAR)) {
flags |= WM_PATHNAME;
}
for (stringstart = string;;) {
switch (c = *pattern++) {
case EOS:
if (check_flag(flags, WM_LEADING_DIR) && *string == '/')
return WM_MATCH;
return (*string == EOS) ? WM_MATCH : WM_NOMATCH;
case '?':
if (*string == EOS)
return WM_NOMATCH;
if (*string == '/' && check_flag(flags, WM_PATHNAME))
return WM_NOMATCH;
if (*string == '.' && check_flag(flags, WM_PERIOD) &&
(string == stringstart ||
(check_flag(flags, WM_PATHNAME) && *(string - 1) == '/')))
return WM_NOMATCH;
++string;
break;
case '*':
c = *pattern;
wild = check_flag(flags, WM_WILDSTAR) && c == '*';
if (wild) {
prev = pattern[-2];
/* Collapse multiple stars and slash-** patterns,
* e.g. "** / *** / **** / **" (without spaces)
* is treated as a single ** wildstar.
*/
while (c == '*') {
c = *++pattern;
}
while (c == '/' && pattern[1] == '*' && pattern[2] == '*') {
prev = c;
c = *++pattern;
while (c == '*') {
c = *++pattern;
}
}
if (c == '/' &&
wildmatch(pattern+1, string, flags) == WM_MATCH) {
return WM_MATCH;
}
} else {
/* Collapse multiple stars. */
while (c == '*') {
c = *++pattern;
}
}
if (!wild && *string == '.' && check_flag(flags, WM_PERIOD) &&
(string == stringstart ||
(check_flag(flags, WM_PATHNAME) && *(string - 1) == '/'))) {
return WM_NOMATCH;
}
/* Optimize for pattern with * or ** at end or before /. */
if (c == EOS) {
if (wild && prev == '/') {
return WM_MATCH;
}
if (check_flag(flags, WM_PATHNAME)) {
return (check_flag(flags, WM_LEADING_DIR) ||
strchr(string, '/') == NULL ? WM_MATCH : WM_NOMATCH);
} else {
return WM_MATCH;
}
} else if (c == '/') {
if (wild) {
slash = strchr(stringstart, '/');
if (!slash) {
return WM_NOMATCH;
}
while (slash) {
if (wildmatch(pattern+1, slash+1, flags) == 0) {
return WM_MATCH;
}
slash = strchr(slash+1, '/');
}
} else {
if (check_flag(flags, WM_PATHNAME)) {
if ((string = strchr(string, '/')) == NULL) {
return WM_NOMATCH;
}
}
}
} else if (wild) {
return WM_NOMATCH;
}
/* General case, use recursion. */
while ((test = *string) != EOS) {
if (!wildmatch(pattern, string, flags & ~WM_PERIOD))
return WM_MATCH;
if (test == '/' && check_flag(flags, WM_PATHNAME))
break;
++string;
}
return WM_NOMATCH;
case '[':
if (*string == EOS)
return WM_NOMATCH;
if (*string == '/' && check_flag(flags, WM_PATHNAME))
return WM_NOMATCH;
if (*string == '.' && check_flag(flags, WM_PERIOD) &&
(string == stringstart ||
(check_flag(flags, WM_PATHNAME) && *(string - 1) == '/')))
return WM_NOMATCH;
switch (rangematch(pattern, *string, flags, &newp)) {
case RANGE_ERROR:
/* not a good range, treat as normal text */
++string;
goto normal;
case RANGE_MATCH:
pattern = newp;
break;
case RANGE_NOMATCH:
return (WM_NOMATCH);
}
++string;
break;
case '\\':
if (!check_flag(flags, WM_NOESCAPE)) {
if ((c = *pattern++) == EOS) {
c = '\\';
--pattern;
if (*(string+1) == EOS) {
return WM_NOMATCH;
}
}
}
/* FALLTHROUGH */
default:
normal:
if (c != *string && !(check_flag(flags, WM_CASEFOLD) &&
(tolower((unsigned char)c) ==
tolower((unsigned char)*string))))
return WM_NOMATCH;
++string;
break;
}
/* NOTREACHED */
}
}
static int
rangematch(const char *pattern, char test, int flags, const char **newp)
{
int negate, ok;
char c, c2;
char tmp;
/*
* A bracket expression starting with an unquoted circumflex
* character produces unspecified results (IEEE 1003.2-1992,
* 3.13.2). This implementation treats it like '!', for
* consistency with the regular expression syntax.
* J.T. Conklin (conklin@ngai.kaleida.com)
*/
if ((negate = (*pattern == '!' || *pattern == '^')))
++pattern;
if (check_flag(flags, WM_CASEFOLD))
test = tolower((unsigned char)test);
/*
* A right bracket shall lose its special meaning and represent
* itself in a bracket expression if it occurs first in the list.
* -- POSIX.2 2.8.3.2
*/
ok = 0;
c = *pattern++;
do {
if (c == '\\' && !check_flag(flags, WM_NOESCAPE))
c = *pattern++;
if (c == EOS)
return RANGE_ERROR;
if (c == '/' && check_flag(flags, WM_PATHNAME))
return RANGE_NOMATCH;
if (*pattern == '-'
&& (c2 = *(pattern+1)) != EOS && c2 != ']') {
pattern += 2;
if (c2 == '\\' && !check_flag(flags, WM_NOESCAPE))
c2 = *pattern++;
if (c2 == EOS)
return RANGE_ERROR;
if (check_flag(flags, WM_CASEFOLD)) {
c = tolower((unsigned char)c);
c2 = tolower((unsigned char)c2);
}
if (c > c2) {
tmp = c2;
c2 = c;
c = tmp;
}
if (c <= test && test <= c2) {
ok = 1;
}
}
if (c == '[' && *pattern == ':' && *(pattern+1) != EOS) {
#define match_pattern(name) \
!strncmp(pattern+1, name, sizeof(name)-1)
#define check_pattern(name, predicate, value) {{ \
if (match_pattern(name ":]")) { \
if (predicate(value)) { \
ok = 1; \
} \
pattern += sizeof(name ":]"); \
continue; \
} \
}}
if (match_pattern(":]")) {
continue;
}
check_pattern("alnum", isalnum, test);
check_pattern("alpha", isalpha, test);
check_pattern("blank", isblank, test);
check_pattern("cntrl", iscntrl, test);
check_pattern("digit", isdigit, test);
check_pattern("graph", isgraph, test);
check_pattern("lower", islower, test);
check_pattern("print", isprint, test);
check_pattern("punct", ispunct, test);
check_pattern("space", isspace, test);
check_pattern("xdigit", isxdigit, test);
c2 = check_flag(flags, WM_CASEFOLD) ? toupper(test) : test;
check_pattern("upper", isupper, c2);
/* fallthrough means match like a normal character */
}
if (c == test) {
ok = 1;
}
} while ((c = *pattern++) != ']');
*newp = (const char *)pattern;
return (ok == negate) ? RANGE_NOMATCH : RANGE_MATCH;
}
#ifdef __cplusplus
}
#endif

80
source/wildmatch.h Normal file
View File

@@ -0,0 +1,80 @@
/*
* Copyright (c), 2016 David Aguilar
* Based on the fnmatch implementation from OpenBSD.
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)fnmatch.h 8.1 (Berkeley) 6/2/93
* $OpenBSD: fnmatch.h,v 1.4 1997/09/22 05:25:32 millert Exp $
*/
#ifndef _WILDMATCH_H_
#define _WILDMATCH_H_
#ifdef __cplusplus
extern "C" {
#endif
#define WM_MATCH 0 /* Match. */
#define WM_NOMATCH 1 /* Match failed. */
#define WM_NOESCAPE 0x01 /* Disable backslash escaping. */
#define WM_PATHNAME 0x02 /* Slash must be matched by slash. */
#define WM_PERIOD 0x04 /* Period must be matched by period. */
#define WM_LEADING_DIR 0x08 /* Ignore /<tail> after Imatch. */
#define WM_CASEFOLD 0x10 /* Case insensitive search. */
#define WM_PREFIX_DIRS 0x20 /* Unused */
#define WM_WILDSTAR 0x40 /* Double-asterisks ** matches slash too. */
#define WM_IGNORECASE WM_CASEFOLD
#define WM_FILE_NAME WM_PATHNAME
/*
* wildmatch is an extension of function fnmatch(3) as specified in
* POSIX 1003.2-1992, section B.6.
*
* Compares a filename or pathname to a pattern.
*
* wildmatch is fnmatch-compatible by default. Its new features are enabled
* by passing WM_WILDSTAR in flags, which makes ** match across path
* boundaries. WM_WILDSTAR implies WM_PATHNAME and WM_PERIOD.
*
* The WM_ flags are the named the same as their FNM_ fnmatch counterparts
* and are compatible in behavior to fnmatch(3) in the absence of WM_WILDSTAR.
*/
int wildmatch(const char *pattern, const char *string, int flags);
#ifdef __cplusplus
}
#endif
#endif