- [L System] Improve generation performance.

This commit is contained in:
Tanasart 2023-09-28 11:31:34 +07:00
parent 9e14536790
commit 734601b5d8
12 changed files with 157 additions and 81 deletions

View file

@ -189,6 +189,7 @@
{"name":"blinker","order":30,"path":"folders/shader/generator/blinker.yy",},
{"name":"cell","order":31,"path":"folders/shader/generator/cell.yy",},
{"name":"grid","order":32,"path":"folders/shader/generator/grid.yy",},
{"name":"interpret","order":35,"path":"folders/shader/generator/interpret.yy",},
{"name":"noise","order":33,"path":"folders/shader/generator/noise.yy",},
{"name":"random shape","order":29,"path":"folders/shader/generator/random shape.yy",},
{"name":"region","order":34,"path":"folders/shader/generator/region.yy",},
@ -209,7 +210,6 @@
{"name":"biterator","order":2,"path":"folders/VCT/biterator.yy",},
{"name":"widget","order":3,"path":"folders/VCT/widget.yy",},
{"name":"widgets","order":5,"path":"folders/widgets.yy",},
{"name":"interpret","order":35,"path":"folders/shader/generator/interpret.yy",},
],
"ResourceOrderSettings": [
{"name":"s_node_corner","order":16,"path":"sprites/s_node_corner/s_node_corner.yy",},
@ -669,7 +669,7 @@
{"name":"node_VFX_effect_destroy","order":12,"path":"scripts/node_VFX_effect_destroy/node_VFX_effect_destroy.yy",},
{"name":"node_cache","order":9,"path":"scripts/node_cache/node_cache.yy",},
{"name":"sh_bw","order":3,"path":"shaders/sh_bw/sh_bw.yy",},
{"name":"real_comparison","order":18,"path":"scripts/real_comparison/real_comparison.yy",},
{"name":"var_comparison","order":1,"path":"scripts/var_comparison/var_comparison.yy",},
{"name":"node_array_zip","order":25,"path":"scripts/node_array_zip/node_array_zip.yy",},
{"name":"fd_rectangle_get_collision_mask_sprite_image","order":5,"path":"scripts/fd_rectangle_get_collision_mask_sprite_image/fd_rectangle_get_collision_mask_sprite_image.yy",},
{"name":"s_node_stripe","order":16,"path":"sprites/s_node_stripe/s_node_stripe.yy",},

View file

@ -225,6 +225,7 @@
{"resourceType":"GMFolder","resourceVersion":"1.0","name":"blinker","folderPath":"folders/shader/generator/blinker.yy",},
{"resourceType":"GMFolder","resourceVersion":"1.0","name":"cell","folderPath":"folders/shader/generator/cell.yy",},
{"resourceType":"GMFolder","resourceVersion":"1.0","name":"grid","folderPath":"folders/shader/generator/grid.yy",},
{"resourceType":"GMFolder","resourceVersion":"1.0","name":"interpret","folderPath":"folders/shader/generator/interpret.yy",},
{"resourceType":"GMFolder","resourceVersion":"1.0","name":"noise","folderPath":"folders/shader/generator/noise.yy",},
{"resourceType":"GMFolder","resourceVersion":"1.0","name":"random shape","folderPath":"folders/shader/generator/random shape.yy",},
{"resourceType":"GMFolder","resourceVersion":"1.0","name":"region","folderPath":"folders/shader/generator/region.yy",},
@ -248,7 +249,6 @@
{"resourceType":"GMFolder","resourceVersion":"1.0","name":"biterator","folderPath":"folders/VCT/biterator.yy",},
{"resourceType":"GMFolder","resourceVersion":"1.0","name":"widget","folderPath":"folders/VCT/widget.yy",},
{"resourceType":"GMFolder","resourceVersion":"1.0","name":"widgets","folderPath":"folders/widgets.yy",},
{"resourceType":"GMFolder","resourceVersion":"1.0","name":"interpret","folderPath":"folders/shader/generator/interpret.yy",},
],
"IncludedFiles": [
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"ApolloHelp.html","ConfigValues":{"Itch":{"CopyToMask":"0",},},"CopyToMask":-1,"filePath":"datafiles",},
@ -1272,7 +1272,7 @@
{"id":{"name":"node_VFX_effect_destroy","path":"scripts/node_VFX_effect_destroy/node_VFX_effect_destroy.yy",},},
{"id":{"name":"node_cache","path":"scripts/node_cache/node_cache.yy",},},
{"id":{"name":"sh_bw","path":"shaders/sh_bw/sh_bw.yy",},},
{"id":{"name":"real_comparison","path":"scripts/real_comparison/real_comparison.yy",},},
{"id":{"name":"var_comparison","path":"scripts/var_comparison/var_comparison.yy",},},
{"id":{"name":"sh_sdf_tex","path":"shaders/sh_sdf_tex/sh_sdf_tex.yy",},},
{"id":{"name":"node_array_zip","path":"scripts/node_array_zip/node_array_zip.yy",},},
{"id":{"name":"fd_rectangle_get_collision_mask_sprite_image","path":"scripts/fd_rectangle_get_collision_mask_sprite_image/fd_rectangle_get_collision_mask_sprite_image.yy",},},

View file

@ -16,8 +16,9 @@ if(PROJECT.active) {
PROJECT.nodes[| i].triggerCheck();
PROJECT.nodes[| i].step();
}
} catch(e)
} catch(e) {
noti_warning("Step error: " + exception_print(e));
}
#endregion
}

View file

@ -112,7 +112,7 @@ function controlPointBox(_onModify) : widget() constructor {
tbW.draw(_x + lw, yy, _w - lw, TEXTBOX_HEIGHT, _wid, _m);
yy += TEXTBOX_HEIGHT + ui(8);
rot.draw(_x + _w / 2, yy, _fy, _m);
rot.draw(_x + _w / 2, yy, _w, _fy, _m);
yy += ui(94 + 8);
break;
}

View file

@ -31,7 +31,7 @@ function __3dCamera_object() : __3dObject() constructor {
VB = build();
transform.position.set(-5, -5, 5);
transform.rotation.set(0, 30, 135);
transform.rotation.FromEuler(0, 30, 135);
transform.scale.set(1, room_width / room_height, 1);
static submitSel = function(params = {}) {

View file

@ -70,7 +70,7 @@ function __3dObject() constructor {
}
} #endregion
static buildVertex = function(_vertex, _normal, _uv) { #region
static buildVertex = function(_vertex) { #region
var _buffer = vertex_create_buffer();
vertex_begin(_buffer, VF);
for( var i = 0, n = array_length(_vertex); i < n; i++ ) {

View file

@ -162,7 +162,7 @@ function variable_editor(nodeVal) constructor {
draw_set_text(f_p0, fa_left, fa_center, COLORS._main_text_sub);
draw_text(_x + ui(8), _y + wd_h / 2, "Range");
vb_range.draw(_x + lb_w, _y, _w - lb_w, wd_h, slider_range, _m);
vb_range.draw(_x + lb_w, _y, _w - lb_w, wd_h, slider_range, noone, _m);
_h += wd_h + ui(4);
_y += wd_h + ui(4);

View file

@ -77,6 +77,14 @@ function Node_Path_L_System(_x, _y, _group = noone) : Node(_x, _y, _group) const
}
return hh;
}, function(parent = noone) {
for( var i = input_fix_len; i < ds_list_size(inputs); i += data_length ) {
var _name = inputs[| i + 0];
var _rule = inputs[| i + 1];
_name.editWidget.register(parent);
_rule.editWidget.register(parent);
}
}); #endregion
input_display_list = [
@ -89,6 +97,15 @@ function Node_Path_L_System(_x, _y, _group = noone) : Node(_x, _y, _group) const
current_length = 0;
boundary = new BoundingBox();
cache_data = {
start: "",
rules: {},
end_rule: "",
iteration: 0,
seed: 0,
result: ""
}
static refreshDynamicInput = function() { #region
var _l = ds_list_create();
@ -175,97 +192,119 @@ function Node_Path_L_System(_x, _y, _group = noone) : Node(_x, _y, _group) const
return new __vec2( _x, _y );
} #endregion
static getPointDistance = function(_dist, _ind = 0) {
static getPointDistance = function(_dist, _ind = 0) { #region
return getPointRatio(_dist / current_length, _ind);
}
} #endregion
static getBoundary = function() { return boundary; }
static l_system = function(_start, _rules, _end_rule, _iteration, _seed) { #region
if(isEqual(cache_data.rules, _rules, true)
&& cache_data.start == _start
&& cache_data.end_rule == _end_rule
&& cache_data.iteration == _iteration
&& cache_data.seed == _seed) {
return cache_data.result;
}
cache_data.start = _start;
cache_data.rules = _rules;
cache_data.end_rule = _end_rule;
cache_data.iteration = _iteration;
cache_data.seed = _seed;
cache_data.result = _start;
_temp_s = "";
for( var j = 1; j <= _iteration; j++ ) {
_temp_s = "";
string_foreach(cache_data.result, function(_ch, _) {
if(!struct_has(cache_data.rules, _ch)) {
_temp_s += _ch;
return;
}
var _chr = cache_data.rules[$ _ch];
_chr = array_safe_get(_chr, irandom(array_length(_chr) - 1));
_temp_s += _chr;
})
cache_data.result = _temp_s;
if(string_length(cache_data.result) > 10000) break;
}
var _es = string_splice(_end_rule, ",");
for( var i = 0, n = array_length(_es); i < n; i++ ) {
var _sp = string_splice(_es[i], "=");
if(array_length(_sp) == 2)
cache_data.result = string_replace_all(cache_data.result, _sp[0], _sp[1]);
}
return cache_data.result;
} #endregion
static update = function() { #region
var _len = inputs[| 0].getValue();
var _ang = inputs[| 1].getValue();
var _pos = inputs[| 2].getValue();
var _itr = inputs[| 3].getValue();
var _sta = inputs[| 4].getValue();
var _end = inputs[| 5].getValue();
var _san = inputs[| 6].getValue();
var _sad = inputs[| 7].getValue();
lines = [];
lineq = ds_queue_create();
random_set_seed(_sad);
current_length = _len;
if(ds_list_size(inputs) < input_fix_len + 2) return;
var l = inputs[| 4].getValue();
var rules = ds_map_create();
var rules = {};
for( var i = input_fix_len; i < ds_list_size(inputs) - data_length; i += data_length ) {
var _name = inputs[| i + 0].getValue();
var _rule = inputs[| i + 1].getValue();
if(!ds_map_exists(rules, _name))
rules[? _name] = [ _rule ];
if(!struct_has(rules, _name))
rules[$ _name] = [ _rule ];
else
array_push(rules[? _name], _rule);
array_push(rules[$ _name], _rule);
}
for( var j = 1; j <= _itr; j++ ) {
var s = "";
for( var i = 1; i <= string_length(l); i++ ) {
var ch = string_char_at(l, i);
if(!ds_map_exists(rules, ch)) {
s += ch;
continue;
}
var _chr = rules[? ch];
_chr = array_safe_get(_chr, irandom(array_length(_chr) - 1));
s += _chr;
}
l = s;
if(string_length(l) > 10000) break;
}
l_system(_sta, rules, _end, _itr, _sad);
itr = _itr;
ang = _ang;
len = _len;
st = ds_stack_create();
t = new L_Turtle(_pos[0], _pos[1], _san);
ds_map_destroy(rules);
var _end = inputs[| 5].getValue();
var _es = string_splice(_end, ",");
for( var i = 0, n = array_length(_es); i < n; i++ ) {
var _sp = string_splice(_es[i], "=");
if(array_length(_sp) == 2)
l = string_replace_all(l, _sp[0], _sp[1]);
}
var st = ds_stack_create();
var t = new L_Turtle(_pos[0], _pos[1], _san);
for( var i = 1; i <= string_length(l); i++ ) {
var ch = string_char_at(l, i);
switch(ch) {
string_foreach(cache_data.result, function(_ch, _) {
switch(_ch) {
case "F":
var nx = t.x + lengthdir_x(_len, t.ang);
var ny = t.y + lengthdir_y(_len, t.ang);
var nx = t.x + lengthdir_x(len, t.ang);
var ny = t.y + lengthdir_y(len, t.ang);
array_push(lines, [ [t.x, t.y, t.w], [nx, ny, t.w] ]);
ds_queue_enqueue(lineq, [ [t.x, t.y, t.w], [nx, ny, t.w] ]);
t.x = nx;
t.y = ny;
break;
case "G":
t.x = t.x + lengthdir_x(_len, t.ang);
t.y = t.y + lengthdir_y(_len, t.ang);
t.x = t.x + lengthdir_x(len, t.ang);
t.y = t.y + lengthdir_y(len, t.ang);
break;
case "f":
var nx = t.x + lengthdir_x(_len * frac(_itr), t.ang);
var ny = t.y + lengthdir_y(_len * frac(_itr), t.ang);
var nx = t.x + lengthdir_x(len * frac(itr), t.ang);
var ny = t.y + lengthdir_y(len * frac(itr), t.ang);
array_push(lines, [ [t.x, t.y, t.w], [nx, ny, t.w] ]);
ds_queue_enqueue(lineq, [ [t.x, t.y, t.w], [nx, ny, t.w] ]);
t.x = nx;
t.y = ny;
break;
case "+": t.ang += _ang; break;
case "-": t.ang -= _ang; break;
case "+": t.ang += ang; break;
case "-": t.ang -= ang; break;
case "|": t.ang += 180; break;
case "[": ds_stack_push(st, t.clone()); break;
case "]": t = ds_stack_pop(st); break;
@ -273,13 +312,22 @@ function Node_Path_L_System(_x, _y, _group = noone) : Node(_x, _y, _group) const
case ">": t.w += 0.1; break;
case "<": t.w -= 0.1; break;
}
}
});
ds_stack_destroy(st);
boundary = new BoundingBox();
for( var i = 0, n = array_length(lines); i < n; i++ )
boundary.addPoint(lines[i][0][0], lines[i][0][1], lines[i][1][0], lines[i][1][1]);
lines = array_create(ds_queue_size(lineq));
var i = 0;
while(!ds_queue_empty(lineq)) {
var _l = ds_queue_dequeue(lineq);
lines[i++] = _l;
boundary.addPoint(_l[0][0], _l[0][1], _l[1][0], _l[1][1]);
}
ds_queue_destroy(lineq);
outputs[| 0].setValue(self);
} #endregion

View file

@ -1,6 +1,7 @@
function Inspector_Custom_Renderer(drawFn) : widget() constructor {
function Inspector_Custom_Renderer(drawFn, registerFn = noone) : widget() constructor {
h = 64;
self.draw = drawFn;
register = registerFn;
}
function Panel_Inspector() : PanelContent() constructor {
@ -463,7 +464,9 @@ function Panel_Inspector() : PanelContent() constructor {
if(pFOCUS) jun_disp.register(contentPane);
jun_disp.rx = ui(16) + x;
jun_disp.ry = top_bar_h + y;
if(is_callable(jun_disp.register))
jun_disp.register(contentPane);
hh += jun_disp.draw(ui(6), yy, con_w - ui(12), _m, _hover, pFOCUS) + ui(8);
continue;
}

View file

@ -1,11 +0,0 @@
function isEqual(val1, val2) {
if(!is_array(val1) && !is_array(val2)) return val1 == val2;
if(is_array(val1) ^ is_array(val2)) return false;
if(array_length(val1) != array_length(val2)) return false;
for( var i = 0, n = array_length(val1); i < n; i++ ) {
if(val1[i] != val2[i]) return false;
}
return true;
}

View file

@ -0,0 +1,35 @@
function isEqual(val1, val2, struct_expand = false) {
gml_pragma("forceinline");
if(is_array(val1) && is_array(val2)) return array_member_equal(val1, val2);
if(struct_expand && is_struct(val1) && is_struct(val2)) return struct_equal(val1, val2);
return val1 == val2;
}
function array_member_equal(arr1, arr2) {
gml_pragma("forceinline");
if(array_length(arr1) != array_length(arr2)) return false;
for( var i = 0, n = array_length(arr1); i < n; i++ )
if(!isEqual(arr1[i], arr2[i])) return false;
return true;
}
function struct_equal(str1, str2) {
gml_pragma("forceinline");
//return json_stringify(str1) == json_stringify(str2);
var key1 = variable_struct_get_names(str1);
var key2 = variable_struct_get_names(str2);
if(!array_equals(key1, key2)) return false;
for( var i = 0, n = array_length(key1); i < n; i++ )
if(!isEqual(str1[$ key1[i]], str2[$ key1[i]])) return false;
return true;
}

View file

@ -1,11 +1,11 @@
{
"resourceType": "GMScript",
"resourceVersion": "1.0",
"name": "real_comparison",
"name": "var_comparison",
"isCompatibility": false,
"isDnD": false,
"parent": {
"name": "value",
"path": "folders/functions/value.yy",
"name": "variables",
"path": "folders/functions/variables.yy",
},
}