Compare commits
56 commits
33d4ebf14a
...
a3f68316ca
Author | SHA1 | Date | |
---|---|---|---|
John Alanbrook | a3f68316ca | ||
John Alanbrook | 640c8389f3 | ||
John Alanbrook | 79c5e7f3a4 | ||
John Alanbrook | 2a8dae2bf6 | ||
John Alanbrook | 01905a26a2 | ||
John Alanbrook | ad6b82ded1 | ||
John Alanbrook | 41c76e1a70 | ||
John Alanbrook | e3029994f9 | ||
John Alanbrook | 0d5ce8f62c | ||
John Alanbrook | 8da89f1032 | ||
John Alanbrook | a1cd43bcfd | ||
John Alanbrook | 188c55a8e0 | ||
John Alanbrook | ec5e9249f0 | ||
John Alanbrook | 67fe729d8c | ||
John Alanbrook | af79dba48a | ||
John Alanbrook | fd8b1b8006 | ||
John Alanbrook | 6d2696437c | ||
John Alanbrook | d33c1af92c | ||
John Alanbrook | 5ddf3558ef | ||
John Alanbrook | 99bd0091f9 | ||
John Alanbrook | ef0a59f489 | ||
John Alanbrook | 794e581336 | ||
John Alanbrook | 1305a762e9 | ||
John Alanbrook | dc59f0642c | ||
John Alanbrook | 2c1f34177b | ||
John Alanbrook | dc25e23aa8 | ||
John Alanbrook | bc313d6f8c | ||
John Alanbrook | fce8ff6081 | ||
John Alanbrook | 603d9a5406 | ||
John Alanbrook | 6c6593c3d9 | ||
John Alanbrook | 31a47b5b7d | ||
John Alanbrook | 2ad2d18af7 | ||
John Alanbrook | 8abb0ae10f | ||
John Alanbrook | 88de7fb547 | ||
John Alanbrook | 94d4d86944 | ||
John Alanbrook | 76497fb600 | ||
John Alanbrook | 05aeb62242 | ||
John Alanbrook | 9fd958f414 | ||
John Alanbrook | 39cbd92bfb | ||
John Alanbrook | ed7d65523a | ||
John Alanbrook | 27fa286625 | ||
John Alanbrook | b589a742cf | ||
John Alanbrook | b31069fe91 | ||
John Alanbrook | 285a227691 | ||
John Alanbrook | 5690ee7fba | ||
John Alanbrook | 05acefd683 | ||
John Alanbrook | 849c85cd7a | ||
John Alanbrook | daad058225 | ||
John Alanbrook | a29ce7e8d0 | ||
John Alanbrook | f5a89915eb | ||
John Alanbrook | 57c2285019 | ||
John Alanbrook | ceccd032c2 | ||
John Alanbrook | 515eb65b22 | ||
John Alanbrook | a28230a647 | ||
John Alanbrook | 432d8200f3 | ||
John Alanbrook | ceb728b1a7 |
3
Makefile
3
Makefile
|
@ -75,7 +75,7 @@ else
|
|||
CPPFLAGS += -O2
|
||||
endif
|
||||
|
||||
CPPFLAGS += -DHAVE_CEIL -DCP_USE_CGTYPES=0 -DCP_USE_DOUBLES=0 -DHAVE_FLOOR -DHAVE_FMOD -DHAVE_LRINT -DHAVE_LRINTF $(includeflag) $(WARNING_FLAGS) -I. -DVER=\"$(SEM)\" -DCOM=\"$(COM)\" -DINFO=\"$(INFO)\" -Wno-narrowing #-DENABLE_SINC_MEDIUM_CONVERTER -DENABLE_SINC_FAST_CONVERTER -DCP_COLLISION_TYPE_TYPE=uintptr_t -DCP_BITMASK_TYPE=uintptr_t
|
||||
CPPFLAGS += -DHAVE_CEIL -DCP_USE_CGTYPES=0 -DCP_USE_DOUBLES=0 -DHAVE_FLOOR -DHAVE_FMOD -DHAVE_LRINT -DHAVE_LRINTF $(includeflag) $(WARNING_FLAGS) -I. -DVER=\"$(SEM)\" -DCOM=\"$(COM)\" -DDATE=\"$(DATE)\" -DINFO=\"$(INFO)\" -Wno-narrowing #-DENABLE_SINC_MEDIUM_CONVERTER -DENABLE_SINC_FAST_CONVERTER -DCP_COLLISION_TYPE_TYPE=uintptr_t -DCP_BITMASK_TYPE=uintptr_t
|
||||
CPPFLAGS += -DCONFIG_VERSION=\"2024-02-14\" -DCONFIG_BIGNUM #for quickjs
|
||||
|
||||
# ENABLE_SINC_[BEST|FAST|MEDIUM]_CONVERTER
|
||||
|
@ -166,6 +166,7 @@ APP = prosperon
|
|||
NAME = $(APP)$(INFO)$(EXT)
|
||||
SEM != git describe --tags --abbrev=0
|
||||
COM != git rev-parse --short HEAD
|
||||
DATE != date +%s
|
||||
|
||||
LDLIBS += $(STEAMAPI)
|
||||
LDLIBS := $(addprefix -l, $(LDLIBS))
|
||||
|
|
|
@ -1,20 +1,89 @@
|
|||
var actor = {};
|
||||
|
||||
actor.spawn = function(script, config, callback){
|
||||
if (typeof script !== 'string') return undefined;
|
||||
var padawan = Object.create(actor);
|
||||
use(script, padawan);
|
||||
var actor_urs = {};
|
||||
var script_times = {};
|
||||
|
||||
var actor_spawns = {};
|
||||
|
||||
globalThis.class_use = function(script, config, base, callback)
|
||||
{
|
||||
var file = Resources.find_script(script);
|
||||
|
||||
if (!file) {
|
||||
var ret = Object.create(base);
|
||||
if (callback) callback(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!actor_urs[file]) {
|
||||
var newur = Object.create(base);
|
||||
actor_urs[file] = newur;
|
||||
script_times[file] = io.mod(file);
|
||||
actor_spawns[file] = [];
|
||||
}
|
||||
|
||||
var padawan = Object.create(actor_urs[file]);
|
||||
actor_spawns[file].push(padawan);
|
||||
padawan._file = file;
|
||||
padawan._root = file.dir();
|
||||
|
||||
if (callback) callback(padawan);
|
||||
|
||||
var script = Resources.replstrs(file);
|
||||
script = `(function() { var self = this; var $ = this.__proto__; ${script}; })`;
|
||||
|
||||
var fn = os.eval(file,script);
|
||||
fn.call(padawan);
|
||||
|
||||
if (typeof config === 'object')
|
||||
Object.merge(padawan,config);
|
||||
|
||||
return padawan;
|
||||
}
|
||||
|
||||
actor.hotreload = function()
|
||||
{
|
||||
profile.cache("hotreload", "check");
|
||||
for (var i in script_times) {
|
||||
if (io.mod(i) > script_times[i]) {
|
||||
say(`HOT RELAODING ${i}`);
|
||||
script_times[i] = io.mod(i);
|
||||
var script = Resources.replstrs(i);
|
||||
script = `(function() {
|
||||
var self = this;
|
||||
var $ = this.__proto__;
|
||||
${script};
|
||||
})`;
|
||||
var fn = os.eval(i,script);
|
||||
|
||||
for (var obj of actor_spawns[i]) {
|
||||
var a = obj;
|
||||
for (var t of a.timers)
|
||||
t();
|
||||
a.timers = [];
|
||||
var save = json.decode(json.encode(a));
|
||||
fn.call(a);
|
||||
Object.merge(a,save);
|
||||
check_registers(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
profile.endcache();
|
||||
}
|
||||
|
||||
actor.spawn = function(script, config){
|
||||
if (typeof script !== 'string') return undefined;
|
||||
|
||||
var padawan = class_use(script, config, actor);
|
||||
|
||||
padawan.padawans = [];
|
||||
padawan.timers = [];
|
||||
padawan.master = this;
|
||||
Object.hide(padawan, "master", "timers", "padawans");
|
||||
Object.hide(padawan, "master","padawans");
|
||||
padawan.toString = function() { return script; }
|
||||
check_registers(padawan);
|
||||
this.padawans.push(padawan);
|
||||
if (padawan.awake) padawan.awake();
|
||||
return padawan;
|
||||
};
|
||||
|
||||
|
@ -41,9 +110,11 @@ actor.kill = function(){
|
|||
this.padawans.forEach(p => p.kill());
|
||||
this.padawans = [];
|
||||
this.__dead__ = true;
|
||||
actor_spawns[this._file].remove(this);
|
||||
if (typeof this.die === 'function') this.die();
|
||||
if (typeof this.stop === 'function') this.stop();
|
||||
if (typeof this.garbage === 'function') this.garbage();
|
||||
if (typeof this.then === 'function') this.then();
|
||||
};
|
||||
|
||||
actor.kill.doc = `Remove this actor and all its padawans from existence.`;
|
||||
|
@ -52,12 +123,13 @@ actor.delay = function(fn, seconds) {
|
|||
var timers = this.timers;
|
||||
var stop = function() {
|
||||
timers.remove(stop);
|
||||
stop = undefined;
|
||||
rm();
|
||||
}
|
||||
|
||||
function execute() {
|
||||
if (fn) fn();
|
||||
if (stop.then) stop.then();
|
||||
if (stop && stop.then) stop.then();
|
||||
stop();
|
||||
}
|
||||
|
||||
|
@ -77,9 +149,21 @@ actor.delay = function(fn, seconds) {
|
|||
timers.push(stop);
|
||||
return stop;
|
||||
};
|
||||
|
||||
actor.delay.doc = `Call 'fn' after 'seconds' with 'this' set to the actor.`;
|
||||
|
||||
actor.interval = function(fn, seconds)
|
||||
{
|
||||
var self = this;
|
||||
var stop;
|
||||
var usefn = function() {
|
||||
fn();
|
||||
stop = self.delay(usefn, seconds);
|
||||
}
|
||||
stop = self.delay(usefn, seconds);
|
||||
|
||||
return stop;
|
||||
}
|
||||
|
||||
actor.padawans = [];
|
||||
|
||||
global.app = Object.create(actor);
|
||||
|
|
|
@ -522,21 +522,27 @@ Object.hide = function(obj,...props)
|
|||
{
|
||||
for (var prop of props) {
|
||||
var p = Object.getOwnPropertyDescriptor(obj,prop);
|
||||
if (!p) {
|
||||
console.error(`No property of name ${prop}.`);
|
||||
continue;
|
||||
}
|
||||
if (!p) continue;
|
||||
p.enumerable = false;
|
||||
Object.defineProperty(obj, prop, p);
|
||||
}
|
||||
}
|
||||
|
||||
Object.enumerable = function(obj, val, ...props)
|
||||
{
|
||||
for (var prop of props) {
|
||||
p = Object.getOwnPropertyDescriptor(obj,prop);
|
||||
if (!p) continue;
|
||||
p.enumerable = val;
|
||||
Object.defineProperty(obj, prop, p);
|
||||
}
|
||||
}
|
||||
|
||||
Object.unhide = function(obj, ...props)
|
||||
{
|
||||
for (var prop of props) {
|
||||
var p = Object.getOwnPropertyDescriptor(obj,prop);
|
||||
if (!p)
|
||||
continue;
|
||||
if (!p) continue;
|
||||
p.enumerable = true;
|
||||
Object.defineProperty(obj, prop, p);
|
||||
}
|
||||
|
@ -551,7 +557,7 @@ Object.defineProperty(Object.prototype, 'obscure', {
|
|||
Object.defineProperty(Object.prototype, 'mixin', {
|
||||
value: function(obj) {
|
||||
if (typeof obj === 'string')
|
||||
obj = use(obj, this);
|
||||
obj = use(obj);
|
||||
|
||||
if (obj)
|
||||
Object.mixin(this, obj);
|
||||
|
@ -785,7 +791,7 @@ Object.defineProperty(String.prototype, 'name', {
|
|||
Object.defineProperty(String.prototype, 'set_name', {
|
||||
value: function(name) {
|
||||
var dir = this.dir();
|
||||
return this.dir() + name + "." + this.ext();
|
||||
return this.dir() + "/" + name + "." + this.ext();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -976,11 +982,7 @@ swizz.forEach(function(x) {
|
|||
make_swizz();
|
||||
|
||||
Object.defineProperty(Array.prototype, 'normalized', {
|
||||
value: function() {
|
||||
var c = this.slice();
|
||||
var len = Vector.length(c);
|
||||
return c.map(v => v/len);
|
||||
}
|
||||
value: function() { return vector.norm(this); }
|
||||
});
|
||||
|
||||
Object.defineProperty(Array.prototype, 'newfirst', {
|
||||
|
@ -1081,15 +1083,6 @@ Object.defineProperty(Array.prototype, 'flat', {
|
|||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Array.prototype, 'anyjs', {
|
||||
value: function(fn) {
|
||||
var ev = this.every(function(x) {
|
||||
return !fn(x);
|
||||
});
|
||||
return !ev;
|
||||
}
|
||||
});
|
||||
|
||||
/* Return true if array contains x */
|
||||
Object.defineProperty(Array.prototype, 'empty', {
|
||||
get: function() { return this.length === 0; },
|
||||
|
@ -1264,7 +1257,7 @@ Object.defineProperty(Number.prototype, 'clamp', {
|
|||
Math.clamp = vector.clamp;
|
||||
|
||||
Math.random_range = vector.random_range;
|
||||
Math.rand_int = function(max) { return Math.floor(Math.random()*max); };
|
||||
Math.rand_int = function(max = 9007199254740991) { return Math.floor(Math.random()*max); };
|
||||
|
||||
Math.snap = function(val, grid) {
|
||||
if (!grid || grid === 1) return Math.round(val);
|
||||
|
@ -1418,8 +1411,7 @@ bbox.fromobjs = function(objs)
|
|||
|
||||
/* VECTORS */
|
||||
var Vector = {};
|
||||
Vector.length = function(v) { return Math.hypot(...v); }
|
||||
|
||||
Vector.length = vector.length;
|
||||
Vector.norm = vector.norm;
|
||||
Vector.project = vector.project;
|
||||
Vector.dot = vector.dot;
|
||||
|
@ -1431,6 +1423,11 @@ Vector.random = function() {
|
|||
Vector.angle_between = vector.angle_between;
|
||||
Vector.rotate = vector.rotate;
|
||||
|
||||
vector.direction = function(from,to)
|
||||
{
|
||||
return vector.norm(to.sub(from));
|
||||
}
|
||||
|
||||
Vector.equal = function(v1, v2, tol) {
|
||||
if (!tol)
|
||||
return v1.equal(v2);
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
var Color = {
|
||||
white: [255,255,255],
|
||||
black: [0,0,0],
|
||||
blue: [84,110,255],
|
||||
green: [120,255,10],
|
||||
yellow: [251,255,43],
|
||||
red: [255,36,20],
|
||||
teal: [96, 252, 237],
|
||||
blue: [0,0,255],
|
||||
green: [0,255,0],
|
||||
yellow: [255,255,0],
|
||||
red: [255,0,0],
|
||||
gray: [181,181,181],
|
||||
cyan: [0,255,255],
|
||||
purple: [162,93,227],
|
||||
orange: [255,144,64],
|
||||
magenta: [255,0,255],
|
||||
};
|
||||
|
||||
Color.editor = {};
|
||||
|
|
|
@ -35,7 +35,8 @@ var sprite = {
|
|||
rect: fullrect,
|
||||
anim:{},
|
||||
playing: 0,
|
||||
play(str = 0) {
|
||||
anim_speed: 1,
|
||||
play(str = 0, fn, loop = true, reverse = false) {
|
||||
this.del_anim?.();
|
||||
var self = this;
|
||||
var stop;
|
||||
|
@ -48,44 +49,43 @@ var sprite = {
|
|||
var playing = self.anim[str];
|
||||
if (!playing) return;
|
||||
var f = 0;
|
||||
if (reverse)
|
||||
f = playing.frames.length-1;
|
||||
|
||||
self.path = playing.path;
|
||||
|
||||
function advance() {
|
||||
if (!self) return;
|
||||
if (!self.gameobject) return;
|
||||
//self.path = playing.path;
|
||||
self.frame = playing.frames[f].rect;
|
||||
self.rect = [self.frame.x, self.frame.y, self.frame.w, self.frame.h];
|
||||
self.update_dimensions();
|
||||
f = (f+1)%playing.frames.length;
|
||||
if (f === 0) {
|
||||
self.anim_done?.();
|
||||
if (!self.loop) { self.stop(); return; }
|
||||
var done = false;
|
||||
if (reverse) {
|
||||
f = (((f-1)%playing.frames.length)+playing.frames.length)%playing.frames.length;
|
||||
if (f === playing.frames.length-1) done = true;
|
||||
}
|
||||
stop = self.gameobject.delay(advance, playing.frames[f].time);
|
||||
else {
|
||||
f = (f+1)%playing.frames.length;
|
||||
if (f === 0) done = true;
|
||||
}
|
||||
|
||||
if (done) {
|
||||
fn?.();
|
||||
if (!loop) { self?.stop(); return; }
|
||||
// self?.anim_done?.();
|
||||
// if (!self.loop) { self.stop(); return; }
|
||||
}
|
||||
if (self)
|
||||
stop = self.gameobject.delay(advance, playing.frames[f].time/self.anim_speed);
|
||||
}
|
||||
|
||||
advance();
|
||||
},
|
||||
stop() {
|
||||
this.del_anim?.();
|
||||
},
|
||||
set path(p) {
|
||||
p = Resources.find_image(p);
|
||||
if (!p) {
|
||||
console.warn(`Could not find image ${p}.`);
|
||||
return;
|
||||
}
|
||||
if (p === this.path) return;
|
||||
this._p = p;
|
||||
|
||||
this.del_anim?.();
|
||||
this.texture = game.texture(p);
|
||||
|
||||
this.diffuse = this.texture;
|
||||
tex_sync() {
|
||||
if (this.anim) this.stop();
|
||||
this.rect = fullrect;
|
||||
|
||||
var anim = SpriteAnim.make(p);
|
||||
var anim = SpriteAnim.make(this.path);
|
||||
this.update_dimensions();
|
||||
this.sync();
|
||||
|
||||
|
@ -95,6 +95,26 @@ var sprite = {
|
|||
|
||||
this.pos = this.dimensions().scale(this.anchor);
|
||||
},
|
||||
stop() {
|
||||
this.del_anim?.();
|
||||
},
|
||||
set path(p) {
|
||||
p = Resources.find_image(p, this.gameobject._root);
|
||||
if (!p) {
|
||||
console.warn(`Could not find image ${p}.`);
|
||||
return;
|
||||
}
|
||||
if (p === this.path) return;
|
||||
|
||||
this._p = p;
|
||||
|
||||
this.del_anim?.();
|
||||
this.texture = game.texture(p);
|
||||
|
||||
this.diffuse = this.texture;
|
||||
|
||||
this.tex_sync();
|
||||
},
|
||||
get path() {
|
||||
return this._p;
|
||||
},
|
||||
|
@ -200,7 +220,6 @@ Object.mixin(os.make_seg2d(), {
|
|||
var animcache = {};
|
||||
var SpriteAnim = {};
|
||||
SpriteAnim.make = function(path) {
|
||||
if (path in animcache) return animcache[path];
|
||||
var anim;
|
||||
if (io.exists(path.set_ext(".ase")))
|
||||
anim = SpriteAnim.aseprite(path.set_ext(".ase"));
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
debug.build = function(fn) { fn(); }
|
||||
debug.build = function(fn) { if (!debug.show) return; fn(); }
|
||||
debug.show = true;
|
||||
debug.urnames = false;
|
||||
debug.termout = true;
|
||||
debug.console = false;
|
||||
debug.cheat = false;
|
||||
debug.meta = false;
|
||||
debug.showprofiler = false;
|
||||
|
||||
debug.fn_break = function(fn,obj = globalThis) {
|
||||
if (typeof fn !== 'function') return;
|
||||
|
@ -14,6 +21,7 @@ debug.draw_phys = false;
|
|||
debug.draw_bb = false;
|
||||
debug.draw_gizmos = false;
|
||||
debug.draw_names = false;
|
||||
debug.sprite_nums = false;
|
||||
debug.draw = function() {
|
||||
if (this.draw_phys) game.all_objects(function(x) { debug.draw_gameobject(x); });
|
||||
|
||||
|
@ -74,7 +82,7 @@ debug.inputs.f4 = function() {
|
|||
};
|
||||
debug.inputs.f4.doc = "Toggle drawing gizmos and names of objects.";
|
||||
|
||||
debug.gif = {
|
||||
var gif = {
|
||||
w: 640, /* Max width */
|
||||
h: 480, /* Max height */
|
||||
stretch: false, /* True if you want to stretch */
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
"use math";
|
||||
|
||||
os.mem_limit.doc = "Set the memory limit of the runtime in bytes.";
|
||||
os.gc_threshold.doc = "Set the threshold before a GC pass is triggered in bytes. This is set to malloc_size + malloc_size>>1 after a GC pass.";
|
||||
os.max_stacksize.doc = "Set the max stack size in bytes.";
|
||||
|
||||
Object.defineProperty(String.prototype, 'rm', {
|
||||
value: function(index, endidx = index+1) { return this.slice(0,index) + this.slice(endidx); }
|
||||
});
|
||||
|
@ -62,7 +66,6 @@ Resources.replpath = function replpath(str, path) {
|
|||
if (io.exists(tr)) return tr;
|
||||
stem = stem.updir();
|
||||
}
|
||||
|
||||
return str;
|
||||
};
|
||||
|
||||
|
@ -70,9 +73,9 @@ Resources.replstrs = function replstrs(path) {
|
|||
if (!path) return;
|
||||
var script = io.slurp(path);
|
||||
var regexp = /"[^"\s]*?\.[^"\s]+?"/g;
|
||||
|
||||
var stem = path.dir();
|
||||
|
||||
// remove console statements
|
||||
if (!console.enabled)
|
||||
script = Resources.rm_fn(/console\.(spam|info|warn|error)/, script);
|
||||
|
||||
|
@ -92,6 +95,24 @@ Resources.replstrs = function replstrs(path) {
|
|||
return script;
|
||||
};
|
||||
|
||||
Resources.is_sound = function(path) {
|
||||
var ext = path.ext();
|
||||
return Resources.sounds.any(x => x === ext);
|
||||
}
|
||||
|
||||
Resources.is_animation = function(path)
|
||||
{
|
||||
if (path.ext() === 'gif' && Resources.gif.frames(path) > 1) return true;
|
||||
if (path.ext() === 'ase') return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Resources.is_path = function(str)
|
||||
{
|
||||
return !/[\\\/:*?"<>|]/.test(str);
|
||||
}
|
||||
|
||||
globalThis.json = {};
|
||||
json.encode = function (value, replacer, space = 1) {
|
||||
return JSON.stringify(value, replacer, space);
|
||||
|
@ -123,32 +144,69 @@ Resources.images = ["png", "gif", "jpg", "jpeg"];
|
|||
Resources.sounds = ["wav", "flac", "mp3", "qoa"];
|
||||
Resources.is_image = function (path) {
|
||||
var ext = path.ext();
|
||||
return Resources.images.any((x) => x === ext);
|
||||
return Resources.images.some(x => x === ext);
|
||||
};
|
||||
|
||||
function find_ext(file, ext) {
|
||||
if (io.exists(file)) return file;
|
||||
function find_ext(file, ext, root = "") {
|
||||
if (!file) return;
|
||||
|
||||
var file_ext = file.ext();
|
||||
if (ext.some(x => x === file_ext)) return file;
|
||||
for (var e of ext) {
|
||||
var nf = `${file}.${e}`;
|
||||
if (io.exists(nf)) return nf;
|
||||
}
|
||||
return;
|
||||
if (io.exists(nf))
|
||||
return nf;
|
||||
}
|
||||
|
||||
Resources.find_image = function (file) {
|
||||
return find_ext(file, Resources.images);
|
||||
};
|
||||
Resources.find_sound = function (file) {
|
||||
return find_ext(file, Resources.sounds);
|
||||
};
|
||||
Resources.find_script = function (file) {
|
||||
return find_ext(file, Resources.scripts);
|
||||
};
|
||||
var all_files = io.glob(`**/${file}.*`);
|
||||
var find = undefined;
|
||||
for (var e of ext) {
|
||||
var finds = all_files.filter(x => x.ext() === e);
|
||||
if (finds.length > 1)
|
||||
console.warn(`Found conflicting files when searching for '${file}': ${json.encode(finds)}. Returning the first one.`);
|
||||
if (finds.length > 0) {
|
||||
find = finds[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return find;
|
||||
}
|
||||
|
||||
var hashhit = 0;
|
||||
var hashmiss = 0;
|
||||
|
||||
Object.defineProperty(Function.prototype, 'hashify', {
|
||||
value: function() {
|
||||
var hash = new Map();
|
||||
var fn = this;
|
||||
function ret() {
|
||||
if (!hash.has(arguments[0]))
|
||||
hash.set(arguments[0], fn(...arguments));
|
||||
|
||||
return hash.get(arguments[0]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
});
|
||||
|
||||
Resources.find_image = function (file, root = "") {
|
||||
return find_ext(file, Resources.images, root);
|
||||
}.hashify();
|
||||
|
||||
Resources.find_sound = function (file, root = "") {
|
||||
return find_ext(file, Resources.sounds, root);
|
||||
}.hashify();
|
||||
|
||||
Resources.find_script = function (file, root = "") {
|
||||
return find_ext(file, Resources.scripts, root);
|
||||
}.hashify();
|
||||
|
||||
console.transcript = "";
|
||||
console.say = function (msg) {
|
||||
msg += "\n";
|
||||
console.print(msg);
|
||||
if (debug.termout) console.term_print(msg);
|
||||
console.transcript += msg;
|
||||
};
|
||||
console.log = console.say;
|
||||
|
@ -200,7 +258,9 @@ console.stackstr = function (skip = 0) {
|
|||
};
|
||||
|
||||
console.stack = function (skip = 0) {
|
||||
console.log(console.stackstr(skip + 1));
|
||||
var stack = console.stackstr(skip+1);
|
||||
console.log(stack);
|
||||
return stack;
|
||||
};
|
||||
|
||||
console.stdout_lvl = 1;
|
||||
|
@ -223,37 +283,37 @@ globalThis.global = globalThis;
|
|||
|
||||
var use_cache = {};
|
||||
|
||||
globalThis.use = function use(file, env = {}, script) {
|
||||
globalThis.use = function use(file) {
|
||||
file = Resources.find_script(file);
|
||||
profile.cache("USE", file);
|
||||
|
||||
if (use_cache[file]) {
|
||||
var ret = use_cache[file].call(env);
|
||||
return;
|
||||
var ret = use_cache[file]();
|
||||
profile.endcache(" [cached]");
|
||||
return ret;
|
||||
}
|
||||
script ??= Resources.replstrs(file);
|
||||
|
||||
var script = Resources.replstrs(file);
|
||||
script = `(function() { var self = this; ${script}; })`;
|
||||
var fn = os.eval(file, script);
|
||||
use_cache[file] = fn;
|
||||
var ret = fn.call(env);
|
||||
var ret = fn();
|
||||
profile.endcache();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
function stripped_use (file, env = {}, script) {
|
||||
function stripped_use (file, script) {
|
||||
file = Resources.find_script(file);
|
||||
|
||||
if (use_cache[file]) {
|
||||
var ret = use_cache[file].call(env);
|
||||
return;
|
||||
var ret = use_cache[file]();
|
||||
return ret;
|
||||
}
|
||||
script ??= Resources.replstrs(file);
|
||||
|
||||
script = `(function() { var self = this; ${script}; })`;
|
||||
var fn = os.eval(file, script);
|
||||
var ret = fn.call(env);
|
||||
var ret = fn();
|
||||
profile.endcache();
|
||||
|
||||
return ret;
|
||||
|
@ -264,7 +324,7 @@ function bare_use(file)
|
|||
var script = io.slurp(file);
|
||||
if (!script) return;
|
||||
script = `(function() { var self = this; ${script}; })`;
|
||||
Object.assign(globalThis, os.eval(file, script).call(globalThis));
|
||||
Object.assign(globalThis, os.eval(file, script)());
|
||||
}
|
||||
|
||||
globalThis.debug = {};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
globalThis.entityreport = {};
|
||||
|
||||
var timer_update = function(dt)
|
||||
|
@ -73,7 +74,7 @@ var entity = {
|
|||
delay(fn, seconds) {
|
||||
var timers = this.timers;
|
||||
var stop = function() {
|
||||
delete timers[guid];
|
||||
timers.remove(stop);
|
||||
execute = undefined;
|
||||
stop = undefined;
|
||||
rm?.();
|
||||
|
@ -92,14 +93,15 @@ var entity = {
|
|||
|
||||
function update(dt) {
|
||||
profile.frame("timer");
|
||||
if (stop) { // TODO: This seems broken
|
||||
stop.remain -= dt;
|
||||
if (stop.remain <= 0) execute();
|
||||
}
|
||||
profile.endframe();
|
||||
}
|
||||
|
||||
var rm = Register.update.register(update);
|
||||
var guid = prosperon.guid();
|
||||
timers[guid] = (stop);
|
||||
timers.push(stop);
|
||||
return stop;
|
||||
},
|
||||
|
||||
|
@ -122,10 +124,8 @@ var entity = {
|
|||
/* Reparent 'this' to be 'parent's child */
|
||||
reparent(parent) {
|
||||
assert(parent, `Tried to reparent ${this.toString()} to nothing.`);
|
||||
console.spam(`parenting ${this.toString()} to ${parent.toString()}`);
|
||||
if (this.master === parent) {
|
||||
console.warn("not reparenting ...");
|
||||
console.warn(`${this.master} is the same as ${parent}`);
|
||||
console.warn(`not reparenting ... ${this.master} is the same as ${parent}`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -140,22 +140,25 @@ var entity = {
|
|||
},
|
||||
|
||||
remove_obj(obj) {
|
||||
if (this.objects)
|
||||
delete this.objects[obj.guid];
|
||||
else
|
||||
console.warn(`Object ${this.guid} has no objects file.`);
|
||||
delete this[obj.name];
|
||||
Object.unhide(this, obj.name);
|
||||
},
|
||||
|
||||
spawn(text, config, callback) {
|
||||
|
||||
var ent = Object.create(entity);
|
||||
var ent = class_use(text, config, entity, function(ent) {
|
||||
ent.transform = os.make_transform();
|
||||
|
||||
ent.guid = prosperon.guid();
|
||||
|
||||
ent.components = {};
|
||||
ent.objects = {};
|
||||
ent.timers = {};
|
||||
|
||||
ent.timers = [];
|
||||
ent.ur = {};
|
||||
ent.urname = text;
|
||||
});
|
||||
/*
|
||||
if (!text)
|
||||
ent.ur = emptyur;
|
||||
else if (text instanceof Object) {// assume it's an ur
|
||||
|
@ -169,12 +172,6 @@ var entity = {
|
|||
config = [ent.ur.data, config];
|
||||
}
|
||||
|
||||
if (typeof text === 'string')
|
||||
use(text, ent);
|
||||
else if (Array.isArray(text))
|
||||
for (var path of text) use(path,ent);
|
||||
profile.cache("ENTITY TIME", ent.ur.name);
|
||||
var st = profile.now();
|
||||
if (typeof config === 'string')
|
||||
Object.merge(ent, json.decode(Resources.replstrs(config)));
|
||||
else if (Array.isArray(config))
|
||||
|
@ -187,6 +184,14 @@ var entity = {
|
|||
Object.merge(ent,path);
|
||||
};
|
||||
|
||||
if (typeof text === 'string') {
|
||||
class_use(
|
||||
use(text, ent);
|
||||
}
|
||||
else if (Array.isArray(text))
|
||||
for (var path of text) use(path,ent);
|
||||
profile.cache("ENTITY TIME", ent.ur.name);
|
||||
*/
|
||||
ent.reparent(this);
|
||||
|
||||
for (var [prop, p] of Object.entries(ent)) {
|
||||
|
@ -200,11 +205,13 @@ var entity = {
|
|||
|
||||
check_registers(ent);
|
||||
|
||||
if (ent.load instanceof Function) ent.load();
|
||||
if (sim.playing())
|
||||
if (ent.awake instanceof Function) ent.awake();
|
||||
if (sim.playing()) {
|
||||
ent._started = true;
|
||||
if (ent.start instanceof Function) ent.start();
|
||||
}
|
||||
|
||||
Object.hide(ent, 'ur', 'components', 'objects', 'timers', 'guid', 'master');
|
||||
Object.hide(ent, 'ur', 'components', 'objects', 'timers', 'guid', 'master', 'guid');
|
||||
|
||||
ent._ed = {
|
||||
selectable: true,
|
||||
|
@ -296,6 +303,10 @@ var entity = {
|
|||
return bb ? bb : bbox.fromcwh([0, 0], [0, 0]);
|
||||
},
|
||||
|
||||
toJSON() {
|
||||
return {guid:this.guid};
|
||||
},
|
||||
|
||||
/* The unique components of this object. Its diff. */
|
||||
json_obj(depth=0) {
|
||||
var fresh = this.ur.fresh;
|
||||
|
@ -323,7 +334,8 @@ var entity = {
|
|||
|
||||
/* The object needed to store an object as an instance of a master */
|
||||
instance_obj() {
|
||||
var t = this.transform();
|
||||
var t = os.make_transform();
|
||||
t = this.transform;
|
||||
t.ur = this.ur.name;
|
||||
return t;
|
||||
},
|
||||
|
@ -345,7 +357,6 @@ dup(diff) {
|
|||
kill() {
|
||||
if (this.__kill) return;
|
||||
this.__kill = true;
|
||||
console.spam(`Killing entity of type ${this.ur}`);
|
||||
|
||||
this.timers.forEach(x => x());
|
||||
delete this.timers;
|
||||
|
@ -368,6 +379,8 @@ dup(diff) {
|
|||
|
||||
this.clear();
|
||||
if (this.stop instanceof Function) this.stop();
|
||||
if (typeof this.garbage === 'function') this.garbage();
|
||||
if (typeof this.then === 'function') this.then();
|
||||
|
||||
game.tag_clear_guid(this.guid);
|
||||
|
||||
|
|
|
@ -68,4 +68,14 @@ shape.circle.points = function(radius, n) {
|
|||
return shape.arc(radius, 360, n);
|
||||
};
|
||||
|
||||
shape.corners2points = function(ll, ur)
|
||||
{
|
||||
return [
|
||||
ll,
|
||||
ll.add([ur.x,0]),
|
||||
ur,
|
||||
ll.add([0,ur.y]),
|
||||
];
|
||||
}
|
||||
|
||||
return {shape};
|
||||
|
|
242
scripts/gui.js
242
scripts/gui.js
|
@ -1,242 +0,0 @@
|
|||
/*
|
||||
gui functions take screen space coordinates
|
||||
*/
|
||||
|
||||
gui.scissor_win = function() { gui.scissor(0,0,window.size.x,window.y); }
|
||||
|
||||
gui.input_lmouse_pressed = function() {
|
||||
if (gui.selected)
|
||||
gui.selected.action();
|
||||
};
|
||||
|
||||
gui.input_s_pressed = function() {
|
||||
if (gui.selected?.down) {
|
||||
gui.selected.selected = false;
|
||||
gui.selected = gui.selected.down;
|
||||
gui.selected.selected = true;
|
||||
}
|
||||
};
|
||||
|
||||
gui.input_w_pressed = function() {
|
||||
if (gui.selected?.up) {
|
||||
gui.selected.selected = false;
|
||||
gui.selected = gui.selected.up;
|
||||
gui.selected.selected = true;
|
||||
}
|
||||
};
|
||||
|
||||
gui.input_enter_pressed = function() {
|
||||
if (gui.selected) {
|
||||
gui.selected.action();
|
||||
}
|
||||
}
|
||||
|
||||
gui.controls = {};
|
||||
gui.controls.toString = function() { return "gui controls"; };
|
||||
gui.controls.update = function() { };
|
||||
|
||||
gui.controls.set_mum = function(mum)
|
||||
{
|
||||
mum.selected = true;
|
||||
|
||||
if (this.selected && this.selected !== mum)
|
||||
this.selected.selected = false;
|
||||
|
||||
this.selected = mum;
|
||||
}
|
||||
gui.controls.check_bb = function(mum)
|
||||
{
|
||||
if (bbox.pointin(mum.bb, input.mouse.screenpos()))
|
||||
gui.controls.set_mum(mum);
|
||||
}
|
||||
gui.controls.inputs = {};
|
||||
gui.controls.inputs.fallthru = false;
|
||||
gui.controls.inputs.mouse = {};
|
||||
gui.controls.inputs.mouse.move = function(pos,dpos)
|
||||
{
|
||||
}
|
||||
gui.controls.inputs.mouse.scroll = function(scroll)
|
||||
{
|
||||
}
|
||||
|
||||
gui.controls.check_submit = function() {
|
||||
if (this.selected && this.selected.action)
|
||||
this.selected.action(this.selected);
|
||||
}
|
||||
|
||||
var Mum = {
|
||||
padding:[0,0], /* Each element inset with this padding on all sides */
|
||||
offset:[0,0],
|
||||
font: "fonts/c64.ttf",
|
||||
selectable: false,
|
||||
selected: false,
|
||||
font_size: 1,
|
||||
text_align: "left", /* left, center, right */
|
||||
scale: 1,
|
||||
angle: 0,
|
||||
anchor: [0,1],
|
||||
hovered: {},
|
||||
text_shadow: {
|
||||
pos: [0,0],
|
||||
color: Color.white,
|
||||
},
|
||||
text_outline: 1, /* outline in pixels */
|
||||
color: Color.white,
|
||||
margin: [0,0], /* Distance between elements for things like columns */
|
||||
width: 0,
|
||||
height: 0,
|
||||
max_width: Infinity,
|
||||
max_height: Infinity,
|
||||
image_repeat: false,
|
||||
image_repeat_offset: [0,0],
|
||||
debug: false, /* set to true to draw debug boxes */
|
||||
|
||||
make(def) {
|
||||
var n = Object.create(this);
|
||||
Object.assign(n, def);
|
||||
return n;
|
||||
},
|
||||
|
||||
prestart() {
|
||||
this.hovered.__proto__ = this;
|
||||
},
|
||||
|
||||
start() {},
|
||||
|
||||
extend(def) {
|
||||
var n = Object.create(this);
|
||||
Object.assign(n, def);
|
||||
var fn = function(def) {
|
||||
var p = n.make(def);
|
||||
p.prestart();
|
||||
p.start();
|
||||
return p;
|
||||
};
|
||||
fn._int = n;
|
||||
return fn;
|
||||
},
|
||||
}
|
||||
|
||||
Mum.text = Mum.extend({
|
||||
draw(cursor = [0,0], cnt = Mum) {
|
||||
if (this.hide) return;
|
||||
if (this.selectable) gui.controls.check_bb(this);
|
||||
this.caret ??= -1;
|
||||
|
||||
/* if (!this.bb)
|
||||
this.calc_bb(cursor);
|
||||
else
|
||||
this.update_bb(cursor);
|
||||
*/
|
||||
var params = this.selected ? this.hovered : this;
|
||||
|
||||
this.width = Math.min(params.max_width, cnt.max_width);
|
||||
|
||||
this.calc_bb(cursor);
|
||||
this.height = this.wh.y;
|
||||
var aa = [0,1].sub(params.anchor);
|
||||
var pos = cursor.add(params.wh.scale(aa)).add(params.offset);
|
||||
// gui.font_set(params.font);
|
||||
render.text(params.str, pos, params.font_size, params.color, this.width, undefined, params.caret);
|
||||
},
|
||||
|
||||
update_bb(cursor) {
|
||||
this.bb = bbox.move(this.bb, cursor.sub(this.wh.scale(this.anchor)));
|
||||
},
|
||||
|
||||
calc_bb(cursor) {
|
||||
var bb = render.text_size(this.str, this.font_size, this.width);
|
||||
this.wh = bbox.towh(bb);
|
||||
var pos = cursor.add(this.wh.scale([0,1].sub(this.anchor))).add(this.offset);
|
||||
this.bb = bbox.move(bb,pos.add([this.wh.x/2,0]));
|
||||
},
|
||||
start() {
|
||||
this.calc_bb([0,0]);
|
||||
},
|
||||
});
|
||||
|
||||
Mum.button = Mum.text._int.extend({
|
||||
selectable: true,
|
||||
color: Color.blue,
|
||||
hovered:{
|
||||
color: Color.red
|
||||
},
|
||||
action() { console.warn("Button has no action."); },
|
||||
});
|
||||
|
||||
Mum.window = Mum.extend({
|
||||
start() {
|
||||
this.wh = [this.width, this.height];
|
||||
this.bb = bbox.fromcwh([0,0], this.wh);
|
||||
},
|
||||
draw(cursor = [0,0], cnt = Mum) {
|
||||
var p = cursor.sub(this.wh.scale(this.anchor)).add(this.padding);
|
||||
render.window(p,this.wh, this.color);
|
||||
this.bb = bbox.blwh(p, this.wh);
|
||||
this.max_width = this.width;
|
||||
if (this.selectable) gui.controls.check_bb(this);
|
||||
var pos = [this.bb.l, this.bb.t].add(this.padding);
|
||||
this.items.forEach(function(item) {
|
||||
if (item.hide) return;
|
||||
item.draw(pos.slice(),this);
|
||||
}, this);
|
||||
|
||||
bind.inst = render.flushtext();
|
||||
render.spdraw(bind);
|
||||
gui.scissor_win();
|
||||
},
|
||||
});
|
||||
|
||||
Mum.image = Mum.extend({
|
||||
start() {
|
||||
if (!this.path) {
|
||||
console.warn("Mum image needs a path.");
|
||||
this.draw = function(){};
|
||||
return;
|
||||
}
|
||||
|
||||
var tex_wh = texture.dimensions(this.path);
|
||||
this.wh = tex_wh.slice();
|
||||
if (this.width !== 0) this.wh.x = this.width;
|
||||
if (this.height !== 0) this.wh.y = this.height;
|
||||
|
||||
this.wh = wh.scale(this.scale);
|
||||
this.sendscale = [wh.x/tex_wh.x, wh.y/tex_wh.y];
|
||||
},
|
||||
|
||||
draw(pos) {
|
||||
this.calc_bb(pos);
|
||||
gui_img(this.path, pos.sub(this.anchor.scale([this.width, this.height])), this.sendscale, this.angle, this.image_repeat, this.image_repeat_offset, this.color);
|
||||
},
|
||||
|
||||
calc_bb(pos) {
|
||||
this.bb = bbox.fromcwh(this.wh.scale([0.5,0.5]), wh);
|
||||
this.bb = bbox.move(this.bb, pos.sub(this.wh.scale(this.anchor)));
|
||||
}
|
||||
});
|
||||
|
||||
Mum.column = Mum.extend({
|
||||
draw(cursor = [0,0], cnt = Mum) {
|
||||
if (this.hide) return;
|
||||
cursor = cursor.add(this.offset);
|
||||
this.max_width = cnt.width;
|
||||
|
||||
this.items.forEach(function(item) {
|
||||
if (item.hide) return;
|
||||
item.draw(cursor, this);
|
||||
cursor.y -= item.height;
|
||||
cursor.y -= this.padding.y;
|
||||
}, this);
|
||||
},
|
||||
});
|
||||
|
||||
/*
|
||||
Mum.debug_colors = {
|
||||
bounds: Color.red.slice(),
|
||||
margin: Color.blue.slice(),
|
||||
padding: Color.green.slice()
|
||||
};*/
|
||||
|
||||
//Object.values(Mum.debug_colors).forEach(function(v) { v.a = 100; });
|
||||
|
||||
//return { Mum };
|
|
@ -32,7 +32,6 @@ var mod = {
|
|||
released
|
||||
rep
|
||||
pressed
|
||||
pressrep
|
||||
down
|
||||
*/
|
||||
|
||||
|
@ -40,7 +39,7 @@ function keycode(name) { return charCodeAt(name); }
|
|||
|
||||
function keyname_extd(key)
|
||||
{
|
||||
if (typeof key === 'string') return key;
|
||||
if (!parseInt(key)) return key;
|
||||
|
||||
if (key > 289 && key < 302) {
|
||||
var num = key-289;
|
||||
|
@ -83,7 +82,6 @@ prosperon.keydown = function(key, repeat)
|
|||
mod.shift = 1;
|
||||
else {
|
||||
var emacs = modstr() + keyname_extd(key);
|
||||
player[0].raw_input(emacs, "pressrep");
|
||||
if (repeat)
|
||||
player[0].raw_input(emacs, "rep");
|
||||
else
|
||||
|
@ -213,10 +211,26 @@ input.print_pawn_kbm = function(pawn) {
|
|||
return str;
|
||||
};
|
||||
|
||||
var joysticks = {};
|
||||
|
||||
joysticks["wasd"] = {
|
||||
uy: "w",
|
||||
dy: "s",
|
||||
ux: "d",
|
||||
dx: "a"
|
||||
};
|
||||
|
||||
input.procdown = function()
|
||||
{
|
||||
for (var k in downkeys)
|
||||
player[0].raw_input(keyname_extd(k), "down");
|
||||
|
||||
for (var i in joysticks) {
|
||||
var joy = joysticks[i];
|
||||
var x = joy.ux - joy.dx;
|
||||
var y = joy.uy - joy.dy;
|
||||
player[0].joy_input(i, joysticks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
input.print_md_kbm = function(pawn) {
|
||||
|
@ -273,6 +287,11 @@ input.tabcomplete = function(val, list) {
|
|||
}
|
||||
|
||||
/* May be a human player; may be an AI player */
|
||||
|
||||
/*
|
||||
'block' on a pawn's input blocks any input from reaching below for the
|
||||
*/
|
||||
|
||||
var Player = {
|
||||
players: [],
|
||||
input(fn, ...args) {
|
||||
|
@ -301,6 +320,23 @@ var Player = {
|
|||
};
|
||||
},
|
||||
|
||||
joy_input(name, joystick) {
|
||||
for (var pawn of this.pawns.reversed()) {
|
||||
if (!pawn.inputs) return;
|
||||
if (!pawn.inputs.joystick) return;
|
||||
if (!pawn.inputs.joystick[name]) return;
|
||||
|
||||
var x = 0;
|
||||
if (input.keyboard.down(joystick.ux)) x++;
|
||||
if (input.keyboard.down(joystick.dx)) x--;
|
||||
var y = 0;
|
||||
if (input.keyboard.down(joystick.uy)) y++;
|
||||
if (input.keyboard.down(joystick.dy)) y--;
|
||||
|
||||
pawn.inputs.joystick[name](x,y);
|
||||
}
|
||||
},
|
||||
|
||||
raw_input(cmd, state, ...args) {
|
||||
for (var pawn of this.pawns.reversed()) {
|
||||
if (!pawn.inputs) {
|
||||
|
@ -308,12 +344,7 @@ var Player = {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (typeof pawn.inputs.any === 'function') {
|
||||
pawn.inputs.any(cmd);
|
||||
|
||||
if (!pawn.inputs.fallthru)
|
||||
return;
|
||||
}
|
||||
var block = pawn.inputs.block;
|
||||
|
||||
if (!pawn.inputs[cmd]) {
|
||||
if (pawn.inputs.block) return;
|
||||
|
@ -339,17 +370,15 @@ var Player = {
|
|||
fn = pawn.inputs[cmd];
|
||||
}
|
||||
|
||||
if (typeof fn === 'function') {
|
||||
if (typeof fn === 'function')
|
||||
fn.call(pawn, ... args);
|
||||
if (!pawn.inputs) continue; // TODO: OK? Checking if the call uncontrolled the pawn
|
||||
pawn.inputs.post?.call(pawn);
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case 'released':
|
||||
if (!pawn.inputs)
|
||||
if (block) return;
|
||||
else continue;
|
||||
|
||||
if (state === 'released')
|
||||
pawn.inputs.release_post?.call(pawn);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!pawn.inputs.fallthru) return;
|
||||
if (pawn.inputs.block) return;
|
||||
|
|
|
@ -25,7 +25,7 @@ mum.base = {
|
|||
inset: null,
|
||||
anchor: [0,1], // where to draw the item from, relative to the cursor. [0,1] is from the top left corner. [1,0] is from the bottom right
|
||||
background_image: null,
|
||||
slice: null,
|
||||
slice: null, // pass to slice an image as a 9 slice. see render.slice9 for its format
|
||||
hover: {
|
||||
color: Color.red,
|
||||
},
|
||||
|
@ -76,7 +76,7 @@ var pre = function(data)
|
|||
if (data.pos) cursor = data.pos.slice();
|
||||
data.drawpos = cursor.slice().add(data.offset);
|
||||
|
||||
if (data.opacity !== 1) {
|
||||
if (data.opacity && data.opacity !== 1) {
|
||||
data.color = data.color.slice();
|
||||
data.color[3] = data.opacity;
|
||||
}
|
||||
|
|
4
scripts/nogame.js
Normal file
4
scripts/nogame.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
this.hud = function()
|
||||
{
|
||||
mum.label("No game yet! Make game.js to get started!", {pos:game.size.scale(0.5), anchor:[0.5,0.5]});
|
||||
}
|
|
@ -9,17 +9,17 @@ emitter.color = Color.white;
|
|||
|
||||
emitter.draw = function()
|
||||
{
|
||||
var amt = Object.values(this.particles).length;
|
||||
if (amt === 0) return;
|
||||
var pars = Object.values(this.particles);
|
||||
if (pars.length === 0) return;
|
||||
render.use_shader(this.shader);
|
||||
render.use_mat(this);
|
||||
render.make_particle_ssbo(Object.values(this.particles), this.ssbo);
|
||||
render.draw(this.shape, this.ssbo, amt);
|
||||
render.make_particle_ssbo(pars, this.ssbo);
|
||||
render.draw(this.shape, this.ssbo, pars.length);
|
||||
}
|
||||
|
||||
var std_spawn = function(par)
|
||||
emitter.kill = function()
|
||||
{
|
||||
|
||||
emitters.remove(this);
|
||||
}
|
||||
|
||||
var std_step = function(p)
|
||||
|
@ -35,13 +35,7 @@ var std_step = function(p)
|
|||
p.transform.scale = [this.scale,this.scale,this.scale];
|
||||
}
|
||||
|
||||
var std_die = function(par)
|
||||
{
|
||||
}
|
||||
|
||||
emitter.spawn_hook = std_spawn;
|
||||
emitter.step_hook = std_step;
|
||||
emitter.die_hook = std_die;
|
||||
|
||||
emitter.spawn = function(t)
|
||||
{
|
||||
|
@ -53,7 +47,8 @@ emitter.spawn = function(t)
|
|||
par.transform.scale = [this.scale,this.scale,this.scale];
|
||||
this.particles[par.id] = par;
|
||||
par.time = 0;
|
||||
this.spawn_hook(par);
|
||||
this.spawn_hook?.(par);
|
||||
par.life = this.life;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -91,8 +86,8 @@ emitter.step = function(dt)
|
|||
p.time += dt;
|
||||
this.step_hook?.(p);
|
||||
|
||||
if (p.time >= p.life) {
|
||||
this.die_hook(p);
|
||||
if (this.kill_hook?.(p) || p.time >= p.life) {
|
||||
this.die_hook?.(p);
|
||||
this.dead.push(this.particles[p.id]);
|
||||
delete this.particles[p.id];
|
||||
}
|
||||
|
@ -103,6 +98,8 @@ emitter.burst = function(count, t) {
|
|||
for (var i = 0; i < count; i++) this.spawn(t);
|
||||
}
|
||||
|
||||
var emitters = [];
|
||||
|
||||
var make_emitter = function()
|
||||
{
|
||||
var e = Object.create(emitter);
|
||||
|
@ -110,7 +107,19 @@ var make_emitter = function()
|
|||
e.shape = shape.centered_quad;
|
||||
e.shader = "shaders/baseparticle.cg";
|
||||
e.dead = [];
|
||||
emitters.push(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
return {make_emitter};
|
||||
function update_emitters(dt)
|
||||
{
|
||||
for (var e of emitters)
|
||||
e.step(dt);
|
||||
}
|
||||
|
||||
function draw_emitters()
|
||||
{
|
||||
for (var e of emitters) e.draw();
|
||||
}
|
||||
|
||||
return {make_emitter, update_emitters, draw_emitters};
|
||||
|
|
|
@ -16,6 +16,7 @@ function calc_cpu(fn, times, diff=0)
|
|||
function empty_fn() {}
|
||||
|
||||
profile.cpu = function profile_cpu(fn, times = 1, q = "unnamed") {
|
||||
var retgather = gathering_cpu;
|
||||
profile.gather_stop();
|
||||
var empty = calc_cpu(empty_fn, 100000);
|
||||
var mean = Math.mean(empty);
|
||||
|
@ -26,7 +27,10 @@ profile.cpu = function profile_cpu(fn, times = 1, q = "unnamed") {
|
|||
var totalt = profile.best_t(elapsed);
|
||||
|
||||
say(`profile [${q}]: ${avgt} ± ${profile.best_t(Math.ci(series))} [${totalt} for ${times} loops]`);
|
||||
start_prof_gather();
|
||||
say(`result of function is ${fn()}`);
|
||||
|
||||
if (retgather)
|
||||
profile.start_prof_gather();
|
||||
}
|
||||
|
||||
profile.ms = function(t) { return t/1000000; }
|
||||
|
@ -81,12 +85,21 @@ profile.start_cpu_gather = function()
|
|||
});
|
||||
}
|
||||
|
||||
function push_time(arr, ob, max)
|
||||
{
|
||||
arr.push({
|
||||
time:profile.now(),
|
||||
ob
|
||||
});
|
||||
}
|
||||
|
||||
profile.cpu_frames = [];
|
||||
profile.cpu_frame = function()
|
||||
{
|
||||
if (gathering_cpu) return;
|
||||
|
||||
profile.gather(Math.random_range(300,600), function() {
|
||||
console.stack(2);
|
||||
push_time(profile.cpu_frames, console.stack(2));
|
||||
profile.gather_stop();
|
||||
});
|
||||
}
|
||||
|
@ -144,6 +157,7 @@ profile.best_t = function (t) {
|
|||
profile.report = function (start, msg = "[undefined report]") { console.info(`${msg} in ${profile.best_t(profile.now() - start)}`); };
|
||||
|
||||
var frame_avg = false;
|
||||
profile.frame_avg_t = 72000;
|
||||
|
||||
profile.start_frame_avg = function()
|
||||
{
|
||||
|
@ -170,31 +184,38 @@ profile.toggle_frame_avg = function()
|
|||
else profile.start_frame_avg();
|
||||
}
|
||||
|
||||
var profile_frames = {};
|
||||
var profile_frame_ts = [];
|
||||
var profile_cframe = profile_frames;
|
||||
var profile_framer = {
|
||||
series: [],
|
||||
avg: {},
|
||||
frame: 72000,
|
||||
};
|
||||
var profile_cframe = undefined;
|
||||
var pframe = 0;
|
||||
var profile_stack = [];
|
||||
|
||||
profile.frame = function profile_frame(title)
|
||||
{
|
||||
if (!frame_avg) return;
|
||||
|
||||
profile_frame_ts.push(profile_cframe);
|
||||
if (!profile_cframe) {
|
||||
profile_cframe = {};
|
||||
profile_framer.series.push({
|
||||
time:profile.now(),
|
||||
data:profile_cframe
|
||||
});
|
||||
} else
|
||||
profile_stack.push(profile_cframe);
|
||||
|
||||
profile_cframe[title] ??= {};
|
||||
profile_cframe = profile_cframe[title];
|
||||
profile_cframe._times ??= [];
|
||||
profile_cframe._times[pframe] ??= 0;
|
||||
profile_cframe._times[pframe] = profile.now() - profile_cframe._times[pframe];
|
||||
profile_cframe.time = profile.now();
|
||||
}
|
||||
|
||||
profile.endframe = function profile_endframe()
|
||||
{
|
||||
if (!frame_avg) return;
|
||||
|
||||
if (profile_cframe === profile_frames) return;
|
||||
profile_cframe._times[pframe] = profile.now() - profile_cframe._times[pframe];
|
||||
profile_cframe.time = profile.now() - profile_cframe.time;
|
||||
profile_cframe = profile_frame_ts.pop();
|
||||
if (profile_cframe === profile_frames) pframe++;
|
||||
}
|
||||
|
||||
var print_frame = function(frame, indent, title)
|
||||
|
@ -218,13 +239,28 @@ profile.print_frame_avg = function()
|
|||
say("\n");
|
||||
}
|
||||
|
||||
var cache_reporting = false;
|
||||
|
||||
var report_cache = {};
|
||||
|
||||
var cachest = 0;
|
||||
var cachegroup;
|
||||
var cachetitle;
|
||||
|
||||
profile.imgui = function()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
profile.cache_reporting = function() { return cache_reporting; }
|
||||
profile.cache_toggle = function() { cache_reporting = !cache_reporting; }
|
||||
profile.cache_dump = function() {
|
||||
report_cache = {};
|
||||
}
|
||||
|
||||
profile.cache = function profile_cache(group, title)
|
||||
{
|
||||
if (!cache_reporting) return;
|
||||
cachest = profile.now();
|
||||
cachegroup = group;
|
||||
cachetitle = title;
|
||||
|
@ -277,3 +313,42 @@ function printreport(cache, name) {
|
|||
|
||||
return report;
|
||||
};
|
||||
|
||||
profile.best_mem = function(bytes)
|
||||
{
|
||||
var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
||||
if (bytes == 0) return '0 Bytes';
|
||||
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
|
||||
return (bytes / Math.pow(1024, i)).toPrecision(3) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
profile.print_mem = function()
|
||||
{
|
||||
var mem = os.mem();
|
||||
say('total memory used: ' + profile.best_mem(mem.memory_used_size));
|
||||
say('total malloced: ' + profile.best_mem(mem.malloc_size));
|
||||
delete mem.memory_used_size;
|
||||
delete mem.malloc_size;
|
||||
for (var i in mem) {
|
||||
if (i. includes("size"))
|
||||
say(" " + i + " :: " + profile.best_mem(mem[i]));
|
||||
}
|
||||
}
|
||||
|
||||
profile.last_mem = undefined;
|
||||
profile.mems = [];
|
||||
profile.gcs = [];
|
||||
profile.print_gc = function()
|
||||
{
|
||||
var gc = os.check_gc();
|
||||
if (!gc) return;
|
||||
profile.gcs.push(gc);
|
||||
profile.mems.push(os.mem());
|
||||
say("GC Hit");
|
||||
say (`time: ${profile.best_t(gc.time)}`);
|
||||
say(`new threshold: ${profile.best_mem(profile.mems.last().gc_threshold)}`);
|
||||
say(`memory checked: ${profile.best_mem(profile.gcs.last().mem)}`);
|
||||
say(`memory freed: ${profile.best_mem(profile.gcs.last().startmem - profile.gcs.last().mem)}`);
|
||||
}
|
||||
|
||||
return {profile};
|
||||
|
|
|
@ -4,6 +4,7 @@ global.check_registers = function (obj) {
|
|||
for (var reg in Register.registries) {
|
||||
if (typeof obj[reg] === 'function') {
|
||||
var fn = obj[reg].bind(obj);
|
||||
fn.layer = obj[reg].layer;
|
||||
var name = obj.ur ? obj.ur.name : obj.toString();
|
||||
obj.timers.push(Register.registries[reg].register(fn, name));
|
||||
}
|
||||
|
@ -19,6 +20,7 @@ global.check_registers = function (obj) {
|
|||
global.obscure("global");
|
||||
global.mixin("scripts/render");
|
||||
global.mixin("scripts/debug");
|
||||
global.mixin("scripts/repl");
|
||||
|
||||
var frame_t = profile.secs(profile.now());
|
||||
|
||||
|
@ -27,6 +29,12 @@ sim.mode = "play";
|
|||
sim.play = function () {
|
||||
this.mode = "play";
|
||||
os.reindex_static();
|
||||
game.all_objects(o => {
|
||||
if (!o._started) {
|
||||
o._started = true;
|
||||
o.start?.();
|
||||
}
|
||||
});
|
||||
};
|
||||
sim.playing = function () {
|
||||
return this.mode === "play";
|
||||
|
@ -53,12 +61,37 @@ game.engine_start = function (s) {
|
|||
function () {
|
||||
global.mixin("scripts/sound.js");
|
||||
world_start();
|
||||
window.set_icon(os.make_texture("icons/moon.gif"));
|
||||
window.set_icon(game.texture("moon"));
|
||||
Object.readonly(window.__proto__, "vsync");
|
||||
Object.readonly(window.__proto__, "enable_dragndrop");
|
||||
Object.readonly(window.__proto__, "enable_clipboard");
|
||||
Object.readonly(window.__proto__, "high_dpi");
|
||||
Object.readonly(window.__proto__, "sample_count");
|
||||
|
||||
prosperon.camera = prosperon.make_camera();
|
||||
var camera = prosperon.camera;
|
||||
camera.transform.pos = [0,0,-100];
|
||||
camera.mode = "keep";
|
||||
camera.break = "fit";
|
||||
camera.size = game.size;
|
||||
gamestate.camera = camera;
|
||||
|
||||
prosperon.hudcam = prosperon.make_camera();
|
||||
var hudcam = prosperon.hudcam;
|
||||
hudcam.near = 0;
|
||||
hudcam.size = camera.size;
|
||||
hudcam.mode = "keep";
|
||||
hudcam.break = "fit";
|
||||
|
||||
prosperon.appcam = prosperon.make_camera();
|
||||
var appcam = prosperon.appcam;
|
||||
appcam.near = 0;
|
||||
appcam.size = window.size;
|
||||
appcam.transform.pos = [window.size.x,window.size.y,-100];
|
||||
prosperon.screencolor = render.screencolor();
|
||||
|
||||
globalThis.imgui = render.imgui_init();
|
||||
|
||||
s();
|
||||
|
||||
shape.quad = {
|
||||
|
@ -86,28 +119,6 @@ game.engine_start = function (s) {
|
|||
};
|
||||
|
||||
render.init();
|
||||
|
||||
prosperon.camera = prosperon.make_camera();
|
||||
var camera = prosperon.camera;
|
||||
camera.transform.pos = [0,0,-100];
|
||||
camera.mode = "keep";
|
||||
camera.break = "fit";
|
||||
camera.size = game.size;
|
||||
gamestate.camera = camera;
|
||||
|
||||
prosperon.hudcam = prosperon.make_camera();
|
||||
var hudcam = prosperon.hudcam;
|
||||
hudcam.near = 0;
|
||||
hudcam.size = camera.size;
|
||||
hudcam.mode = "keep";
|
||||
hudcam.break = "fit";
|
||||
|
||||
prosperon.appcam = prosperon.make_camera();
|
||||
var appcam = prosperon.appcam;
|
||||
appcam.near = 0;
|
||||
appcam.size = window.size;
|
||||
appcam.transform.pos = [window.size.x,window.size.y,-100];
|
||||
prosperon.screencolor = render.screencolor();
|
||||
},
|
||||
prosperon.process,
|
||||
window.size.x,
|
||||
|
@ -116,7 +127,6 @@ game.engine_start = function (s) {
|
|||
};
|
||||
|
||||
game.startengine = 0;
|
||||
var frames = [];
|
||||
|
||||
prosperon.release_mode = function()
|
||||
{
|
||||
|
@ -126,13 +136,6 @@ prosperon.release_mode = function()
|
|||
}
|
||||
prosperon.debug = true;
|
||||
|
||||
globalThis.fps = function () {
|
||||
return 0;
|
||||
// var sum = 0;
|
||||
// for (var i = 0; i < frames.length; i++) sum += frames[i];
|
||||
// return frames.length / sum;
|
||||
};
|
||||
|
||||
game.timescale = 1;
|
||||
|
||||
var eachobj = function (obj, fn) {
|
||||
|
@ -176,17 +179,41 @@ game.doc.pause = "Pause game simulation.";
|
|||
game.doc.play = "Resume or start game simulation.";
|
||||
game.doc.camera = "Current camera.";
|
||||
|
||||
game.texture = function (path, force = false) {
|
||||
if (force && game.texture.cache[path]) return game.texture.cache[path];
|
||||
game.tex_hotreload = function()
|
||||
{
|
||||
for (var path in game.texture.cache) {
|
||||
if (io.mod(path) > game.texture.time_cache[path]) {
|
||||
say(`HOT SWAPPING IMAGE ${path}`);
|
||||
var tex = game.texture.cache[path];
|
||||
game.texture.time_cache[path] = io.mod(path);
|
||||
os.texture_swap(path, game.texture.cache[path]);
|
||||
for (var sprite of Object.values(allsprites)) {
|
||||
if (sprite.texture == tex) {
|
||||
say('syncing a sprite ...');
|
||||
sprite.tex_sync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
game.texture = function (path) {
|
||||
if (!path) return game.texture("icons/no_text.gif");
|
||||
path = Resources.find_image(path);
|
||||
|
||||
if (!io.exists(path)) {
|
||||
console.warn(`Missing texture: ${path}`);
|
||||
console.error(`Missing texture: ${path}`);
|
||||
game.texture.cache[path] = game.texture("icons/no_tex.gif");
|
||||
} else game.texture.cache[path] ??= os.make_texture(path);
|
||||
|
||||
game.texture.time_cache[path] = io.mod(path);
|
||||
return game.texture.cache[path];
|
||||
}
|
||||
if (game.texture.cache[path]) return game.texture.cache[path];
|
||||
game.texture.cache[path] = os.make_texture(path);
|
||||
game.texture.time_cache[path] = io.mod(path);
|
||||
return game.texture.cache[path];
|
||||
};
|
||||
game.texture.cache = {};
|
||||
game.texture.time_cache = {};
|
||||
|
||||
prosperon.semver = {};
|
||||
prosperon.semver.valid = function (v, range) {
|
||||
|
@ -226,8 +253,6 @@ prosperon.semver.cmp = function (v1, v2) {
|
|||
return 0;
|
||||
};
|
||||
|
||||
prosperon.semver.doc =
|
||||
"Functions for semantic versioning numbers. Semantic versioning is given as a triple digit number, as MAJOR.MINOR.PATCH.";
|
||||
prosperon.semver.cmp.doc =
|
||||
"Compare two semantic version numbers, given like X.X.X.";
|
||||
prosperon.semver.valid.doc = `Test if semantic version v is valid, given a range.
|
||||
|
@ -252,6 +277,7 @@ prosperon.quit = function () {
|
|||
profile.print_cache_report();
|
||||
profile.stop_frame_avg()
|
||||
profile.stop_cpu_instr();
|
||||
prosperon.quit_hook?.();
|
||||
};
|
||||
|
||||
window.size = [640, 480];
|
||||
|
@ -264,17 +290,24 @@ window.doc = {};
|
|||
window.doc.dimensions = "Window width and height packaged in an array [width,height]";
|
||||
window.doc.title = "Name in the title bar of the window.";
|
||||
window.doc.boundingbox = "Boundingbox of the window, with top and right being its height and width.";
|
||||
window.__proto__.toJSON = function()
|
||||
{
|
||||
return {
|
||||
size: this.size,
|
||||
fullscreen: this.fullscreen,
|
||||
title: this.title
|
||||
};
|
||||
}
|
||||
|
||||
global.mixin("scripts/input");
|
||||
global.mixin("scripts/std");
|
||||
global.mixin("scripts/diff");
|
||||
global.mixin("scripts/color");
|
||||
global.mixin("scripts/gui");
|
||||
global.mixin("scripts/tween");
|
||||
global.mixin("scripts/ai");
|
||||
global.mixin("scripts/particle");
|
||||
global.mixin("scripts/physics");
|
||||
global.mixin("scripts/geometry");
|
||||
global.mixin("scripts/geometry")
|
||||
|
||||
/*
|
||||
Factory for creating registries. Register one with 'X.register',
|
||||
|
@ -283,9 +316,9 @@ which returns a function that, when invoked, cancels the registry.
|
|||
var Register = {
|
||||
registries: [],
|
||||
|
||||
add_cb(name, e_event = false) {
|
||||
add_cb(name, e_event = false, flush = undefined) {
|
||||
var n = {};
|
||||
var fns = {};
|
||||
var fns = [];
|
||||
|
||||
n.register = function (fn, oname) {
|
||||
if (!(fn instanceof Function)) return;
|
||||
|
@ -299,15 +332,33 @@ var Register = {
|
|||
profile.endcache();
|
||||
}
|
||||
|
||||
fns[guid] = dofn;
|
||||
fns.push(dofn);
|
||||
dofn.layer = fn.layer;
|
||||
dofn.layer ??= 0;
|
||||
|
||||
fns.sort((a,b) => a.layer > b.layer);
|
||||
|
||||
return function () {
|
||||
delete fns[guid];
|
||||
fns.remove(dofn);
|
||||
};
|
||||
};
|
||||
|
||||
if (!flush) {
|
||||
prosperon[name] = function(...args) {
|
||||
fns.forEach(x => x(...args));
|
||||
};
|
||||
fns.forEach(fn => fn(...args));
|
||||
}
|
||||
}
|
||||
else
|
||||
prosperon[name] = function(...args) {
|
||||
var layer = undefined;
|
||||
for (var fn of fns) {
|
||||
if (layer !== fn.layer) {
|
||||
flush();
|
||||
layer = fn.layer;
|
||||
}
|
||||
fn();
|
||||
}
|
||||
}
|
||||
|
||||
prosperon[name].fns = fns;
|
||||
n.clear = function () {
|
||||
|
@ -325,10 +376,7 @@ Register.add_cb("appupdate", true);
|
|||
Register.add_cb("update", true).doc = "Called once per frame.";
|
||||
Register.add_cb("physupdate", true);
|
||||
Register.add_cb("gui", true);
|
||||
Register.add_cb("hud", true);
|
||||
Register.add_cb("draw_dbg", true);
|
||||
Register.add_cb("gui_dbg", true);
|
||||
Register.add_cb("hud_dbg", true);
|
||||
Register.add_cb("hud", true, render.flush);
|
||||
Register.add_cb("draw", true);
|
||||
Register.add_cb("imgui", true);
|
||||
|
||||
|
@ -358,7 +406,9 @@ var Event = {
|
|||
|
||||
global.mixin("scripts/spline");
|
||||
global.mixin("scripts/components");
|
||||
|
||||
global.mixin("scripts/actor");
|
||||
|
||||
global.mixin("scripts/entity");
|
||||
|
||||
function world_start() {
|
||||
|
|
|
@ -44,6 +44,8 @@ function set_model(t)
|
|||
render.setunim4(0, cur.shader.vs.unimap.model.slot, t);
|
||||
}
|
||||
|
||||
render.set_model = set_model;
|
||||
|
||||
var shaderlang = {
|
||||
macos: "metal_macos",
|
||||
windows: "hlsl5",
|
||||
|
@ -56,7 +58,7 @@ var attr_map = {
|
|||
a_pos: 0,
|
||||
a_uv: 1,
|
||||
a_norm: 2,
|
||||
a_bone: 3,
|
||||
a_joint: 3,
|
||||
a_weight: 4,
|
||||
a_color: 5,
|
||||
a_tan: 6,
|
||||
|
@ -154,6 +156,7 @@ render.set_camera = function(cam)
|
|||
}
|
||||
|
||||
var shader_cache = {};
|
||||
var shader_times = {};
|
||||
|
||||
function strip_shader_inputs(shader)
|
||||
{
|
||||
|
@ -161,42 +164,27 @@ function strip_shader_inputs(shader)
|
|||
a.name = a.name.slice(2);
|
||||
}
|
||||
|
||||
function make_shader(shader)
|
||||
render.hotreload = function()
|
||||
{
|
||||
if (shader_cache[shader]) return shader_cache[shader];
|
||||
|
||||
var file = shader;
|
||||
shader = io.slurp(shader);
|
||||
if (!shader) {
|
||||
console.info(`not found! slurping shaders/${file}`);
|
||||
shader = io.slurp(`shaders/${file}`);
|
||||
}
|
||||
var writejson = `.prosperon/${file.name()}.shader.json`;
|
||||
|
||||
profile.cache("shader", file);
|
||||
|
||||
breakme: if (io.exists(writejson)) {
|
||||
var data = json.decode(io.slurp(writejson));
|
||||
var filemod = io.mod(writejson);
|
||||
if (!data.files) break breakme;
|
||||
for (var i of data.files) {
|
||||
if (io.mod(i) > filemod) {
|
||||
break breakme;
|
||||
}
|
||||
}
|
||||
|
||||
profile.endcache(" [cached]");
|
||||
var shaderobj = json.decode(io.slurp(writejson));
|
||||
var obj = shaderobj[os.sys()];
|
||||
strip_shader_inputs(obj);
|
||||
for (var i in shader_times) {
|
||||
if (io.mod(i) <= shader_times[i]) continue;
|
||||
say(`HOT RELOADING SHADER ${i}`);
|
||||
shader_times[i] = io.mod(i);
|
||||
var obj = create_shader_obj(i);
|
||||
obj = obj[os.sys()];
|
||||
obj.pipe = render.pipeline(obj);
|
||||
shader_cache[shader] = obj;
|
||||
return obj;
|
||||
var old = shader_cache[i];
|
||||
Object.assign(shader_cache[i], obj);
|
||||
cur.bind = undefined;
|
||||
cur.mesh = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
var out = `.prosperon/${file.name()}.shader`;
|
||||
|
||||
function create_shader_obj(file)
|
||||
{
|
||||
var files = [file];
|
||||
var out = ".prosperon/tmp.shader";
|
||||
var shader = io.slurp(file);
|
||||
|
||||
var incs = shader.match(/#include <.*>/g);
|
||||
if (incs)
|
||||
|
@ -223,7 +211,6 @@ function make_shader(shader)
|
|||
|
||||
shader = shader.replace(/uniform\s+(\w+)\s+(\w+);/g, "uniform _$2 { $1 $2; };");
|
||||
shader = shader.replace(/(texture2D|sampler) /g, "uniform $1 ");
|
||||
// shader = shader.replace(/uniform texture2D ?(.*);/g, "uniform _$1_size { vec2 $1_size; };\nuniform texture2D $1;");
|
||||
|
||||
io.slurpwrite(out, shader);
|
||||
|
||||
|
@ -253,11 +240,11 @@ function make_shader(shader)
|
|||
}
|
||||
|
||||
add_code(obj.vs);
|
||||
if (!obj.fs)
|
||||
if (obj.vs.fs) {
|
||||
if (!obj.fs && obj.vs.fs) {
|
||||
obj.fs = obj.vs.fs;
|
||||
delete obj.vs.fs;
|
||||
}
|
||||
|
||||
add_code(obj.fs);
|
||||
|
||||
obj.blend = blend;
|
||||
|
@ -296,19 +283,58 @@ function make_shader(shader)
|
|||
|
||||
obj.name = file;
|
||||
|
||||
strip_shader_inputs(obj);
|
||||
|
||||
compiled[platform] = obj;
|
||||
}
|
||||
|
||||
compiled.files = files;
|
||||
compiled.source = shader;
|
||||
|
||||
return compiled;
|
||||
}
|
||||
|
||||
function make_shader(shader)
|
||||
{
|
||||
if (shader_cache[shader]) return shader_cache[shader];
|
||||
|
||||
var file = shader;
|
||||
shader = io.slurp(file);
|
||||
if (!shader) {
|
||||
console.info(`not found! slurping shaders/${file}`);
|
||||
shader = io.slurp(`shaders/${file}`);
|
||||
}
|
||||
var writejson = `.prosperon/${file.name()}.shader.json`;
|
||||
|
||||
profile.cache("shader", file);
|
||||
|
||||
breakme: if (io.exists(writejson)) {
|
||||
var data = json.decode(io.slurp(writejson));
|
||||
var filemod = io.mod(writejson);
|
||||
if (!data.files) break breakme;
|
||||
for (var i of data.files) {
|
||||
if (io.mod(i) > filemod) {
|
||||
break breakme;
|
||||
}
|
||||
}
|
||||
|
||||
profile.endcache(" [cached]");
|
||||
var shaderobj = json.decode(io.slurp(writejson));
|
||||
var obj = shaderobj[os.sys()];
|
||||
obj.pipe = render.pipeline(obj);
|
||||
shader_cache[file] = obj;
|
||||
shader_times[file] = io.mod(file);
|
||||
return obj;
|
||||
}
|
||||
|
||||
var compiled = create_shader_obj(file);
|
||||
io.slurpwrite(writejson, json.encode(compiled));
|
||||
profile.endcache();
|
||||
|
||||
var obj = compiled[os.sys()];
|
||||
strip_shader_inputs(obj);
|
||||
obj.pipe = render.pipeline(obj);
|
||||
|
||||
shader_cache[shader] = obj;
|
||||
shader_cache[file] = obj;
|
||||
shader_times[file] = io.mod(file);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -335,6 +361,12 @@ function shader_apply_material(shader, material = {}, old = {})
|
|||
if (material[p] === old[p]) continue;
|
||||
assert(p in material, `shader ${shader.name} has no uniform for ${p}`);
|
||||
var s = shader.vs.unimap[p];
|
||||
|
||||
if (p === 'bones') {
|
||||
render.setunibones(0, s.slot, material[p]);
|
||||
continue;
|
||||
}
|
||||
|
||||
shader_unisize[s.size](0, s.slot, material[p]);
|
||||
}
|
||||
|
||||
|
@ -358,13 +390,6 @@ function shader_apply_material(shader, material = {}, old = {})
|
|||
|
||||
function sg_bind(mesh, ssbo)
|
||||
{
|
||||
if (cur.mesh === mesh && cur.bind) {
|
||||
cur.bind.inst = 1;
|
||||
cur.bind.images = cur.images;
|
||||
render.setbind(cur.bind);
|
||||
return cur.bind;
|
||||
}
|
||||
|
||||
cur.mesh = mesh;
|
||||
|
||||
var bind = {};
|
||||
|
@ -372,7 +397,7 @@ function sg_bind(mesh, ssbo)
|
|||
if (cur.shader.vs.inputs)
|
||||
for (var a of cur.shader.vs.inputs) {
|
||||
if (!(a.name in mesh)) {
|
||||
console.error(`cannot draw shader ${cur.shader.name}; there is no attrib ${a.name} in the given mesh.`);
|
||||
console.error(`cannot draw shader ${cur.shader.name}; there is no attrib ${a.name} in the given mesh. ${json.encode(mesh)}`);
|
||||
return undefined;
|
||||
} else
|
||||
bind.attrib.push(mesh[a.name]);
|
||||
|
@ -455,12 +480,9 @@ render.init = function() {
|
|||
polyshader = make_shader("shaders/poly.cg");
|
||||
parshader = make_shader("shaders/baseparticle.cg");
|
||||
polyssboshader = make_shader("shaders/poly_ssbo.cg");
|
||||
textssbo = render.make_textssbo();
|
||||
poly_ssbo = render.make_textssbo();
|
||||
sprite_ssbo = render.make_textssbo();
|
||||
|
||||
globalThis.imgui = render.imgui_init();
|
||||
|
||||
render.textshader = textshader;
|
||||
|
||||
os.make_circle2d().draw = function() {
|
||||
|
@ -493,8 +515,52 @@ render.init = function() {
|
|||
}
|
||||
}
|
||||
|
||||
render.draw_sprites = true;
|
||||
render.draw_particles = true;
|
||||
render.draw_hud = true;
|
||||
render.draw_gui = true;
|
||||
render.draw_gizmos = true;
|
||||
|
||||
render.sprites = function render_sprites(gridsize = 1)
|
||||
{
|
||||
// When y sorting, draw layer is firstly important followed by the gameobject position
|
||||
var buckets;
|
||||
if (render.y_sort) {
|
||||
profile.frame("y bucketing");
|
||||
var sps = Object.values(allsprites);
|
||||
buckets = {};
|
||||
|
||||
for (var sprite of sps) {
|
||||
var layer = (sprite.gameobject.drawlayer*10000)-sprite.gameobject.pos.y;
|
||||
buckets[layer] ??= {};
|
||||
if (buckets[layer][sprite.path])
|
||||
buckets[layer][sprite.path].push(sprite);
|
||||
else
|
||||
buckets[layer][sprite.path] = [sprite];
|
||||
}
|
||||
|
||||
profile.endframe();
|
||||
|
||||
profile.frame("y sorting");
|
||||
buckets = Object.entries(buckets).sort((a,b) => {
|
||||
var na = Number(a[0]);
|
||||
var nb = Number(b[0]);
|
||||
if (na < nb) return -1;
|
||||
return 1;
|
||||
});
|
||||
profile.endframe();
|
||||
} else {
|
||||
profile.frame("sorting");
|
||||
var sprite_buckets = component.sprite_buckets();
|
||||
|
||||
var buckets = Object.entries(sprite_buckets).sort((a,b) => {
|
||||
var na = Number(a[0]);
|
||||
var nb = Number(b[0]);
|
||||
if (na < nb) return -1;
|
||||
return 1;
|
||||
});
|
||||
profile.endframe();
|
||||
}
|
||||
/*
|
||||
profile.frame("bucketing");
|
||||
var sps = Object.values(allsprites);
|
||||
|
@ -514,17 +580,6 @@ render.sprites = function render_sprites(gridsize = 1)
|
|||
profile.endframe();
|
||||
*/
|
||||
|
||||
profile.frame("sorting");
|
||||
var sprite_buckets = component.sprite_buckets();
|
||||
|
||||
var buckets = Object.entries(sprite_buckets).sort((a,b) => {
|
||||
var na = Number(a[0]);
|
||||
var nb = Number(b[0]);
|
||||
if (na < nb) return -1;
|
||||
return 1;
|
||||
});
|
||||
profile.endframe();
|
||||
|
||||
profile.frame("drawing");
|
||||
render.use_shader(spritessboshader);
|
||||
for (var layer of buckets) {
|
||||
|
@ -535,22 +590,31 @@ render.sprites = function render_sprites(gridsize = 1)
|
|||
render.use_mat(ss);
|
||||
render.make_sprite_ssbo(sparray, sprite_ssbo);
|
||||
render.draw(shape.quad, sprite_ssbo, sparray.length);
|
||||
if (debug.sprite_nums) render.text(ss.diffuse.getid(), ss.transform.pos);
|
||||
}
|
||||
}
|
||||
profile.endframe();
|
||||
}
|
||||
|
||||
render.circle = function render_circle(pos, radius, color) {
|
||||
flush();
|
||||
render.circle = function render_circle(pos, radius, color, inner_radius = 1) {
|
||||
check_flush(undefined);
|
||||
|
||||
if (inner_radius >= 1)
|
||||
inner_radius = inner_radius/radius;
|
||||
else if (inner_radius < 0)
|
||||
inner_radius = 1.0;
|
||||
|
||||
var mat = {
|
||||
radius: radius,
|
||||
inner_r: inner_radius,
|
||||
coord: pos,
|
||||
shade: color
|
||||
shade: color,
|
||||
};
|
||||
render.use_shader(circleshader);
|
||||
render.use_mat(mat);
|
||||
render.draw(shape.quad);
|
||||
}
|
||||
render.circle.doc = "Draw a circle at pos, with a given radius and color. If inner_radius is between 0 and 1, it acts as a percentage of radius. If it is above 1, is acts as a unit (usually a pixel).";
|
||||
|
||||
render.poly = function render_poly(points, color, transform) {
|
||||
var buffer = render.poly_prim(points);
|
||||
|
@ -578,6 +642,8 @@ function check_flush(flush_fn)
|
|||
}
|
||||
}
|
||||
|
||||
render.flush = check_flush;
|
||||
|
||||
var poly_cache = [];
|
||||
var poly_idx = 0;
|
||||
var poly_ssbo;
|
||||
|
@ -605,17 +671,21 @@ function flush_poly()
|
|||
render.use_shader(polyssboshader);
|
||||
render.use_mat({});
|
||||
render.make_particle_ssbo(poly_cache.slice(0,poly_idx), poly_ssbo);
|
||||
render.draw(shape.centered_quad, poly_ssbo, poly_cache.length);
|
||||
render.draw(shape.centered_quad, poly_ssbo, poly_idx);
|
||||
poly_idx = 0;
|
||||
}
|
||||
|
||||
render.line = function render_line(points, color = Color.white, thickness = 1) {
|
||||
for (var i = 0; i < points.length-1; i++) {
|
||||
var a = points[i];
|
||||
var b = points[i+1];
|
||||
var poly = poly_e();
|
||||
var dist = vector.distance(points[0],points[1]);
|
||||
poly.transform.move(vector.midpoint(points[0],points[1]));
|
||||
poly.transform.rotate([0,0,-1], vector.angle([points[1].x-points[0].x, points[1].y-points[0].y]));
|
||||
var dist = vector.distance(a,b);
|
||||
poly.transform.move(vector.midpoint(a,b));
|
||||
poly.transform.rotate([0,0,-1], vector.angle([b.x-a.x, b.y-a.y]));
|
||||
poly.transform.scale = [dist, thickness, 1];
|
||||
poly.color = color;
|
||||
}
|
||||
check_flush(flush_poly);
|
||||
}
|
||||
|
||||
|
@ -696,7 +766,7 @@ render.text_bb = function(str, size = 1, wrap = -1, pos = [0,0])
|
|||
|
||||
render.text = function(str, pos, size = 1, color = Color.white, wrap = -1, anchor = [0,1], cursor = -1) {
|
||||
var bb = render.text_bb(str, size, wrap, pos);
|
||||
gui.text(str, pos, size, color, wrap, cursor);
|
||||
gui.text(str, pos, size, color, wrap, cursor); // this puts text into buffer
|
||||
check_flush(render.flush_text);
|
||||
return bb;
|
||||
|
||||
|
@ -711,6 +781,12 @@ render.text = function(str, pos, size = 1, color = Color.white, wrap = -1, ancho
|
|||
};
|
||||
|
||||
render.image = function(tex, pos, scale = [tex.width, tex.height], rotation = 0, color = Color.white) {
|
||||
if (typeof tex === 'string') {
|
||||
tex = game.texture(tex);
|
||||
scale.x ??= tex.width;
|
||||
scale.y ??= tex.height;
|
||||
}
|
||||
if (!tex) return;
|
||||
flush();
|
||||
var t = os.make_transform();
|
||||
t.pos = pos;
|
||||
|
@ -759,30 +835,32 @@ render.slice9 = function(tex, pos, bb, scale = [tex.width,tex.height], color = C
|
|||
render.draw(shape.quad);
|
||||
}
|
||||
|
||||
render.emitter = function(emit)
|
||||
function endframe()
|
||||
{
|
||||
var amt = Object.values(emit.particles).length;
|
||||
if (amt === 0) return;
|
||||
render.use_shader(parshader);
|
||||
render.use_mat(emit);
|
||||
var ts = [];
|
||||
for (var p of Object.values(emit.particles)) ts.push([p.transform,p.color]);
|
||||
render.make_particle_ssbo(ts, emit.ssbo);
|
||||
render.draw(shape.quad, emit.ssbo, amt);
|
||||
tdraw = 0;
|
||||
}
|
||||
|
||||
var textssbo;
|
||||
var textssbos = [];
|
||||
var tdraw = 0;
|
||||
|
||||
render.flush_text = function()
|
||||
{
|
||||
if (!render.textshader) return;
|
||||
var amt = render.flushtext(textssbo);
|
||||
tdraw++;
|
||||
if (textssbos.length < tdraw)
|
||||
textssbos.push(render.make_textssbo());
|
||||
|
||||
var textssbo = textssbos[tdraw-1];
|
||||
var amt = render.flushtext(textssbo); // load from buffer into ssbo
|
||||
|
||||
if (amt === 0) {
|
||||
tdraw--;
|
||||
return;
|
||||
}
|
||||
|
||||
render.use_shader(render.textshader);
|
||||
render.use_mat({text:render.font.texture});
|
||||
|
||||
if (amt === 0) return;
|
||||
|
||||
render.draw(shape.quad, textssbo, amt);
|
||||
}
|
||||
|
||||
|
@ -799,21 +877,20 @@ render.set_font = function(path, size) {
|
|||
}
|
||||
|
||||
render.doc = "Draw shapes in screen space.";
|
||||
//render.circle.doc = "Draw a circle at pos, with a given radius and color.";
|
||||
render.cross.doc = "Draw a cross centered at pos, with arm length size.";
|
||||
render.arrow.doc = "Draw an arrow from start to end, with wings of length wingspan at angle wingangle.";
|
||||
render.rectangle.doc = "Draw a rectangle, with its corners at lowerleft and upperright.";
|
||||
|
||||
render.draw = function render_draw(mesh, ssbo, inst = 1)
|
||||
render.draw = function render_draw(mesh, ssbo, inst = 1, e_start = 0)
|
||||
{
|
||||
sg_bind(mesh, ssbo);
|
||||
profile.frame("gpu");
|
||||
render.spdraw(cur.bind.count, inst);
|
||||
render.spdraw(e_start, cur.bind.count, inst);
|
||||
profile.endframe();
|
||||
}
|
||||
|
||||
// Returns an array in the form of [left, bottom, right, top] in pixels of the camera to render to
|
||||
// Camera viewport is [left,bottom,right,top] in relative values
|
||||
// Camera viewport is [left,bottom,width,height] in relative values
|
||||
function camviewport()
|
||||
{
|
||||
var aspect = (this.viewport[2]-this.viewport[0])/(this.viewport[3]-this.viewport[1])*window.size.x/window.size.y;
|
||||
|
@ -861,21 +938,43 @@ function camscreen2world(pos)
|
|||
return view;
|
||||
}
|
||||
|
||||
// three coordinatse
|
||||
// world coordinates, the "actual" view relative to the game's universe
|
||||
// camera coordinates, normalized from 0 to 1 inside of a camera's viewport, bottom left is 0,0, top right is 1,1
|
||||
// screen coordinates, pixels, 0,0 at the bottom left of the window and [w,h] at the top right of the screen
|
||||
|
||||
camscreen2world.doc = "Convert a view position for a camera to world."
|
||||
|
||||
// return camera coordinates given a screen position
|
||||
function screen2cam(pos)
|
||||
{
|
||||
var viewport = this.view();
|
||||
var width = viewport[2]-viewport[0];
|
||||
var height = viewport[3]-viewport[1];
|
||||
var left = pos.x-viewport[0];
|
||||
var bottom = pos.y-viewport[1];
|
||||
var p = [left/width, bottom/height];
|
||||
return p;
|
||||
var width = viewport[2];
|
||||
var height = viewport[3];
|
||||
var viewpos = pos.sub([viewport[0],viewport[1]]);
|
||||
return viewpos.div([width,height]);
|
||||
}
|
||||
|
||||
function camextents()
|
||||
{
|
||||
var half = this.size;//.scale(0.5);
|
||||
return {
|
||||
l: this.pos.x-half.x,
|
||||
r: this.pos.x+half.x,
|
||||
t:this.pos.y+half.y,
|
||||
b:this.pos.y-half.y
|
||||
};
|
||||
}
|
||||
|
||||
screen2cam.doc = "Convert a screen space position in pixels to a normalized viewport position in a camera."
|
||||
|
||||
prosperon.gizmos = function()
|
||||
{
|
||||
game.all_objects(o => {
|
||||
if (o.gizmo) render.image(game.texture(o.gizmo), o.pos);
|
||||
});
|
||||
}
|
||||
|
||||
prosperon.make_camera = function()
|
||||
{
|
||||
var cam = world.spawn();
|
||||
|
@ -888,7 +987,7 @@ prosperon.make_camera = function()
|
|||
cam.mode = "stretch";
|
||||
cam.screen2world = camscreen2world;
|
||||
cam.screen2cam = screen2cam;
|
||||
|
||||
cam.extents = camextents;
|
||||
cam.mousepos = function() { return this.screen2world(input.mouse.screenpos()); }
|
||||
cam.view = camviewport;
|
||||
cam.offscreen = false;
|
||||
|
@ -897,12 +996,83 @@ prosperon.make_camera = function()
|
|||
|
||||
var screencolor;
|
||||
|
||||
globalThis.imtoggle = function(name, obj, field) { obj[field] = imgui.checkbox(name, obj[field]); }
|
||||
var replstr = "";
|
||||
|
||||
var imdebug = function()
|
||||
{
|
||||
imtoggle("Physics", debug, 'draw_phys');
|
||||
imtoggle("Bouning boxes", debug, 'draw_bb');
|
||||
imtoggle("Gizmos", debug, 'draw_gizmos');
|
||||
imtoggle("Names", debug, 'draw_names');
|
||||
imtoggle("Sprite nums", debug, 'sprite_nums');
|
||||
imtoggle("Debug overlay", debug, 'show');
|
||||
imtoggle("Show ur names", debug, 'urnames');
|
||||
}
|
||||
|
||||
var imgui_fn = function()
|
||||
{
|
||||
render.imgui_new(window.size.x, window.size.y, 0.01);
|
||||
if (debug.console) debug.console = imgui.window("console", _ => { imgui.text(console.transcript); replstr = imgui.textinput(undefined, replstr); imgui.button("submit", _ => { eval(replstr); replstr = ""; }); });
|
||||
|
||||
imgui.mainmenubar(_=>{
|
||||
imgui.menu("File", _ => {
|
||||
imgui.menu("Game settings", _ => {
|
||||
window.title = imgui.textinput("Title", window.title);
|
||||
window.icon = imgui.textinput("Icon", window.icon);
|
||||
imgui.button("Refresh window", _ => {
|
||||
window.set_icon(game.texture(window.icon));
|
||||
});
|
||||
});
|
||||
imgui.button("quit", os.quit);
|
||||
});
|
||||
imgui.menu("Debug", imdebug);
|
||||
imgui.menu("View", _ => {
|
||||
imtoggle("Profiler", debug, 'showprofiler');
|
||||
imtoggle("Terminal out", debug, 'termout');
|
||||
imtoggle("Meta [f7]", debug, 'meta');
|
||||
imtoggle("Cheats [f8]", debug, 'cheat');
|
||||
imtoggle("Console [f9]", debug, 'console');
|
||||
});
|
||||
|
||||
imgui.sokol_gfx();
|
||||
|
||||
imgui.menu("Graphics", _ => {
|
||||
imtoggle("Draw sprites", render, 'draw_sprites');
|
||||
imtoggle("Draw particles", render, 'draw_particles');
|
||||
imtoggle("Draw HUD", render, 'draw_hud');
|
||||
imtoggle("Draw GUI", render, 'draw_gui');
|
||||
imtoggle("Draw gizmos", render, 'draw_gizmos');
|
||||
|
||||
imgui.menu("Window", _ => {
|
||||
window.fullscreen = imgui.checkbox("fullscreen", window.fullscreen);
|
||||
// window.vsync = imgui.checkbox("vsync", window.vsync);
|
||||
imgui.menu("MSAA", _ => {
|
||||
for (var msaa of gamestate.msaa)
|
||||
imgui.button(msaa + "x", _ => window.sample_count = msaa);
|
||||
});
|
||||
imgui.menu("Resolution", _ => {
|
||||
for (var res of gamestate.resolutions)
|
||||
imgui.button(res, _ => window.resolution = res);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
prosperon.menu_hook?.();
|
||||
});
|
||||
|
||||
prosperon.imgui();
|
||||
render.imgui_end();
|
||||
}
|
||||
|
||||
prosperon.render = function()
|
||||
{
|
||||
profile.frame("world");
|
||||
render.set_camera(prosperon.camera);
|
||||
profile.frame("sprites");
|
||||
render.sprites();
|
||||
if (render.draw_sprites) render.sprites();
|
||||
if (render.draw_particles) draw_emitters();
|
||||
profile.endframe();
|
||||
profile.frame("draws");
|
||||
prosperon.draw();
|
||||
|
@ -913,17 +1083,23 @@ prosperon.render = function()
|
|||
|
||||
profile.endframe();
|
||||
profile.frame("hud");
|
||||
if (render.draw_hud) prosperon.hud();
|
||||
render.flush_text();
|
||||
|
||||
prosperon.hud();
|
||||
render.set_camera(prosperon.camera);
|
||||
if (render.draw_gizmos && prosperon.gizmos) prosperon.gizmos();
|
||||
render.flush_text();
|
||||
|
||||
render.end_pass();
|
||||
|
||||
profile.endframe();
|
||||
|
||||
profile.frame("post process");
|
||||
profile.endframe();
|
||||
profile.endframe();
|
||||
/* draw the image of the game world first */
|
||||
render.glue_pass();
|
||||
profile.frame("frame");
|
||||
profile.frame("render");
|
||||
profile.frame("post process");
|
||||
render.viewport(...prosperon.camera.view());
|
||||
render.use_shader(render.postshader);
|
||||
render.use_mat({diffuse:prosperon.screencolor});
|
||||
|
@ -944,24 +1120,26 @@ prosperon.render = function()
|
|||
|
||||
// Call gui functions
|
||||
mum.style = mum.dbg_style;
|
||||
prosperon.gui();
|
||||
if (render.draw_gui) prosperon.gui();
|
||||
if (mum.drawinput) mum.drawinput();
|
||||
prosperon.gui_dbg();
|
||||
render.flush_text();
|
||||
mum.style = mum.base;
|
||||
|
||||
check_flush();
|
||||
|
||||
profile.endframe();
|
||||
|
||||
profile.frame("imgui");
|
||||
|
||||
render.imgui_new(window.size.x, window.size.y, 0.01);
|
||||
prosperon.imgui();
|
||||
render.imgui_end();
|
||||
if (debug.show)
|
||||
imgui_fn();
|
||||
|
||||
profile.endframe();
|
||||
|
||||
render.end_pass();
|
||||
render.commit();
|
||||
|
||||
endframe();
|
||||
}
|
||||
|
||||
prosperon.process = function process() {
|
||||
|
@ -969,6 +1147,19 @@ prosperon.process = function process() {
|
|||
var dt = profile.secs(profile.now()) - frame_t;
|
||||
frame_t = profile.secs(profile.now());
|
||||
|
||||
profile.frame("hotreload");
|
||||
actor.hotreload();
|
||||
render.hotreload();
|
||||
game.tex_hotreload();
|
||||
repl.hotreload();
|
||||
profile.endframe();
|
||||
|
||||
/* debugging: check for gc */
|
||||
profile.print_gc();
|
||||
|
||||
var cycles = os.check_cycles();
|
||||
if (cycles) say(cycles);
|
||||
|
||||
profile.frame("app update");
|
||||
prosperon.appupdate(dt);
|
||||
profile.endframe();
|
||||
|
@ -980,6 +1171,7 @@ prosperon.process = function process() {
|
|||
if (sim.mode === "play" || sim.mode === "step") {
|
||||
profile.frame("update");
|
||||
prosperon.update(dt * game.timescale);
|
||||
update_emitters(dt * game.timescale);
|
||||
profile.endframe();
|
||||
if (sim.mode === "step") sim.pause();
|
||||
|
||||
|
@ -1002,6 +1194,4 @@ prosperon.process = function process() {
|
|||
profile.endframe();
|
||||
}
|
||||
|
||||
|
||||
|
||||
return {render};
|
||||
|
|
15
scripts/repl.js
Normal file
15
scripts/repl.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
var repl = {};
|
||||
|
||||
var file = "repl.jj";
|
||||
var last = 0;
|
||||
|
||||
repl.hotreload = function() {
|
||||
if (io.mod(file) > last) {
|
||||
say("REPL:::");
|
||||
last = io.mod(file);
|
||||
var script = io.slurp(file);
|
||||
eval(script);
|
||||
}
|
||||
}
|
||||
|
||||
return {repl:repl};
|
|
@ -22,9 +22,18 @@ audio.bus.master = dspsound.master();
|
|||
audio.dsp = {};
|
||||
audio.dsp = dspsound;
|
||||
|
||||
audio.cry = function(file)
|
||||
audio.dsp.mix().__proto__.imgui = function()
|
||||
{
|
||||
var player = audio.play(file);
|
||||
imgui.pushid(this.memid());
|
||||
this.volume = imgui.slider("Volume", this.volume);
|
||||
this.off = imgui.checkbox("Mute", this.off);
|
||||
imgui.popid();
|
||||
}
|
||||
|
||||
audio.cry = function(file, bus = audio.bus.sfx)
|
||||
{
|
||||
file = Resources.find_sound(file);
|
||||
var player = audio.play(file, bus);
|
||||
if (!player) return;
|
||||
|
||||
player.guid = prosperon.guid();
|
||||
|
@ -45,29 +54,43 @@ var killer = Register.appupdate.register(function() {
|
|||
|
||||
var song;
|
||||
|
||||
audio.music = function(file, fade = 0) {
|
||||
// Play 'file' for new song, cross fade for seconds
|
||||
audio.music = function(file, fade = 0.5) {
|
||||
if (!file) {
|
||||
if (song)
|
||||
song.volume = 0;
|
||||
return;
|
||||
}
|
||||
file = Resources.find_sound(file);
|
||||
if (!fade) {
|
||||
song = audio.play(file);
|
||||
song = audio.play(file, audio.bus.music);
|
||||
song.loop = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var temp = audio.play(file);
|
||||
if (!song) {
|
||||
song = audio.play(file, audio.bus.music);
|
||||
song.volume = 1;
|
||||
// tween(song,'volume', 1, fade);
|
||||
return;
|
||||
}
|
||||
|
||||
var temp = audio.play(file, audio.bus.music);
|
||||
if (!temp) return;
|
||||
|
||||
temp.volume = 0;
|
||||
temp.volume = 1;
|
||||
var temp2 = song;
|
||||
tween(temp, 'volume', 1, fade);
|
||||
tween(temp2, 'volume', 0, fade);
|
||||
// tween(temp, 'volume', 1, fade);
|
||||
// tween(temp2, 'volume', 0, fade);
|
||||
song = temp;
|
||||
song.loop = true;
|
||||
}
|
||||
|
||||
audio.dsp.mix = function(to) {
|
||||
var n = audio.dsp.mix();
|
||||
if (to) n.plugin(to);
|
||||
return n;
|
||||
};
|
||||
audio.bus.music = audio.dsp.mix();
|
||||
audio.bus.music.plugin(audio.bus.master);
|
||||
|
||||
audio.bus.sfx = audio.dsp.mix();
|
||||
audio.bus.sfx.plugin(audio.bus.master);
|
||||
|
||||
audio.dsp.allpass = function(secs, decay) {
|
||||
var composite = {};
|
||||
|
@ -96,6 +119,8 @@ audio.dsp.doc = {
|
|||
red: "Red noise"
|
||||
};
|
||||
|
||||
audio.dsp.obscure('doc');
|
||||
|
||||
Object.mixin(audio.bus.master.__proto__, {
|
||||
get db() { return 20*Math.log10(Math.abs(this.volume)); },
|
||||
set db(x) { x = Math.clamp(x,-100,0); this.volume = Math.pow(10, x/20); },
|
||||
|
@ -103,6 +128,16 @@ Object.mixin(audio.bus.master.__proto__, {
|
|||
set volume(x) { this.gain = x; },
|
||||
});
|
||||
|
||||
audio.bus.master.__proto__.toJSON = function()
|
||||
{
|
||||
return {
|
||||
volume: this.volume,
|
||||
off: this.off,
|
||||
pan: this.pan,
|
||||
pass: this.pass
|
||||
};
|
||||
}
|
||||
|
||||
/*Object.mixin(audio.dsp.source().__proto__, {
|
||||
length() { return this.frames()/audio.samplerate(); },
|
||||
time() { return this.frame/sound.samplerate(); },
|
||||
|
|
|
@ -10,15 +10,16 @@ var appy = {};
|
|||
appy.inputs = {};
|
||||
if (os.sys() === 'macos') {
|
||||
appy.inputs['S-q'] = os.quit;
|
||||
appy.inputs['S-h'] = function() { };
|
||||
appy.inputs['S-g'] = os.gc;
|
||||
}
|
||||
|
||||
//appy.inputs.f12 = function() { mum.debug = !mum.debug; }
|
||||
appy.inputs.f12 = function() { profile.cpu_frame(); }
|
||||
appy.inputs.f7 = function() { debug.meta = !debug.meta; }
|
||||
appy.inputs.f8 = function() { debug.cheat = !debug.cheat; }
|
||||
appy.inputs.f9 = function() { debug.console = !debug.console; }
|
||||
appy.inputs.f10 = function() { debug.show = !debug.show; }
|
||||
appy.inputs.f11 = window.toggle_fullscreen;
|
||||
appy.inputs.f10 = function() { profile.toggle_frame_avg(); }
|
||||
appy.inputs['M-f4'] = prosperon.quit;
|
||||
appy.inputs.f11.doc = "Toggle window fullscreen.";
|
||||
appy.inputs.f11.title = "Toggle Fullscreen";
|
||||
appy.inputs['M-f4'] = os.quit;
|
||||
|
||||
player[0].control(appy);
|
||||
|
||||
|
@ -53,24 +54,6 @@ os.openurl = function(url) {
|
|||
var projectfile = "project.prosperon";
|
||||
io.dumpfolder = '.prosperon';
|
||||
|
||||
Resources.is_sound = function(path) {
|
||||
var ext = path.ext();
|
||||
return Resources.sounds.any(x => x === ext);
|
||||
}
|
||||
|
||||
Resources.is_animation = function(path)
|
||||
{
|
||||
if (path.ext() === 'gif' && Resources.gif.frames(path) > 1) return true;
|
||||
if (path.ext() === 'ase') return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Resources.is_path = function(str)
|
||||
{
|
||||
return !/[\\\/:*?"<>|]/.test(str);
|
||||
}
|
||||
|
||||
Resources.texture = {};
|
||||
Resources.texture.dimensions = function(path) { texture.dimensions(path); }
|
||||
|
||||
|
@ -139,6 +122,23 @@ io.rm = function(f)
|
|||
tmprm(Resources.replpath(f));
|
||||
}
|
||||
|
||||
io.globToRegex = function(glob) {
|
||||
// Escape special regex characters
|
||||
// Replace glob characters with regex equivalents
|
||||
let regexStr = glob
|
||||
.replace(/[\.\\]/g, '\\$&') // Escape literal backslashes and dots
|
||||
.replace(/([^\*])\*/g, '$1[^/]*') // * matches any number of characters except /
|
||||
.replace(/\*\*/g, '.*') // ** matches any number of characters, including none
|
||||
.replace(/\[(.*?)\]/g, '[$1]') // Character sets
|
||||
.replace(/\?/g, '.'); // ? matches any single character
|
||||
|
||||
// Ensure the regex matches the whole string
|
||||
regexStr = '^' + regexStr + '$';
|
||||
|
||||
// Create and return the regex object
|
||||
return new RegExp(regexStr);
|
||||
}
|
||||
|
||||
io.mixin({
|
||||
extensions(ext) {
|
||||
var paths = io.ls();
|
||||
|
@ -148,12 +148,7 @@ io.mixin({
|
|||
|
||||
glob(pat) {
|
||||
var paths = io.ls('.');
|
||||
pat = pat.replaceAll(/([\[\]\(\)\^\$\.\|\+])/g, "\\$1");
|
||||
pat = pat.replaceAll('**', '.*');
|
||||
pat = pat.replaceAll(/[^\.]\*/g, '[^\\/]*');
|
||||
pat = pat.replaceAll('?', '.');
|
||||
|
||||
var regex = new RegExp("^"+pat+"$", "");
|
||||
var regex = io.globToRegex(pat);
|
||||
paths = paths.filter(str => str.match(regex)).sort();
|
||||
return paths;
|
||||
},
|
||||
|
@ -216,11 +211,6 @@ Cmdline.register_order("init", function() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!(io.ls().filter(x => x[0] !== '.').length === 0)) {
|
||||
say("Directory is not empty. Make an empty one and init there.");
|
||||
return;
|
||||
}
|
||||
|
||||
io.mkdir(io.dumpfolder);
|
||||
var project = {};
|
||||
project.version = prosperon.version;
|
||||
|
@ -240,7 +230,7 @@ Cmdline.register_order("play", function(argv) {
|
|||
if (argv[0])
|
||||
io.chdir(argv[0]);
|
||||
|
||||
game.loadurs();
|
||||
// game.loadurs();
|
||||
|
||||
if (!io.exists(projectfile)) {
|
||||
say("No game to play. Try making one with 'prosperon init'.");
|
||||
|
@ -249,12 +239,22 @@ Cmdline.register_order("play", function(argv) {
|
|||
|
||||
var project = json.decode(io.slurp(projectfile));
|
||||
game.title = project.title;
|
||||
game.size = [1280,720];
|
||||
window.size = game.size;
|
||||
if (io.exists("config.js"))
|
||||
global.mixin("config.js");
|
||||
else
|
||||
console.warn('No config.js file found. Starting with default parameters.');
|
||||
|
||||
if (project.title) window.title = project.title;
|
||||
|
||||
game.engine_start(function() {
|
||||
render.set_font("fonts/c64.ttf", 8);
|
||||
if (io.exists("game.js"))
|
||||
global.app = actor.spawn("game.js");
|
||||
else
|
||||
global.app = actor.spawn("scripts/nogame.js");
|
||||
|
||||
if (project.icon) window.set_icon(game.texture(project.icon));
|
||||
game.camera = world.spawn("scripts/camera2d");
|
||||
});
|
||||
|
@ -320,7 +320,7 @@ Cmdline.register_order("about", function(argv) {
|
|||
}, "Get information about this game.");
|
||||
|
||||
Cmdline.register_order("ur", function(argv) {
|
||||
game.loadurs();
|
||||
// game.loadurs();
|
||||
for (var i of ur._list.sort()) say(i);
|
||||
}, "Get information about the ur types in your game.");
|
||||
|
||||
|
|
69
scripts/stdprofile.js
Normal file
69
scripts/stdprofile.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
var aa = [1,2,3,4,5,6,7,8,9,10];
|
||||
|
||||
/*
|
||||
var ta = [1,2,3,4,5,6,7,8,9,10];
|
||||
|
||||
function tadd(a,b)
|
||||
{
|
||||
var c = a.slice();
|
||||
for (var i = 0; i < a.length; i++)
|
||||
c[i] += b[i];
|
||||
return c;
|
||||
}
|
||||
|
||||
say(vector.angle_between([0,1], [1,0]));
|
||||
|
||||
function test_arrays(ta, tb)
|
||||
{
|
||||
profile.cpu(_=> ta.add(tb), 100000, "add two arrays");
|
||||
say(ta.add(tb));
|
||||
}
|
||||
*/
|
||||
//for (var i = 2; i <= 10; i++) {
|
||||
// say(`TESTING FOR ${i} ARRAY`);
|
||||
// test_arrays(ta.slice(0,i), ta.slice(0,i));
|
||||
//}
|
||||
/*
|
||||
say(prosperon.guid());
|
||||
say(prosperon.guid());
|
||||
var aa = [];
|
||||
var ao = {};
|
||||
|
||||
var amt = 10000;
|
||||
|
||||
profile.cpu(_ => prosperon.guid(), 10000, "guid generation");
|
||||
|
||||
profile.cpu(_ => aa.push(1), amt, "add one to array");
|
||||
profile.cpu(_ => ao[prosperon.guid()] = 1, amt, "add one via guid");
|
||||
|
||||
var aos = Object.keys(ao);
|
||||
|
||||
say(aa.length);
|
||||
|
||||
var useguid = aos[amt/2];
|
||||
|
||||
say(useguid);
|
||||
|
||||
var tries = [];
|
||||
for (var i = 0; i < amt; i++)
|
||||
tries[i] = aa.slice();
|
||||
|
||||
var rmamt = amt/2;
|
||||
profile.cpu(x => tries[x].remove(rmamt), amt, "remove from array");
|
||||
|
||||
for (var i = 0; i < amt; i++) {
|
||||
tries[i] = {};
|
||||
for (var j in ao) tries[i][j] = ao[j];
|
||||
}
|
||||
|
||||
|
||||
profile.cpu(x => delete tries[x][useguid], amt, "delete with guid");
|
||||
|
||||
//profile.cpu(_ => Object.values(ao), 10000, "make array from objects");
|
||||
var dofn = function(x) { x += 1; }
|
||||
profile.cpu(_ => aa.forEach(dofn), 1000, "iterate array");
|
||||
profile.cpu(_ => ao.forEach(dofn), 1000, "iterate object foreach");
|
||||
profile.cpu(_ => {
|
||||
for (var i in ao) ao[i] += 1;
|
||||
}, 1000, "iterate in object values");
|
||||
*/
|
10
scripts/stdtest.js
Normal file
10
scripts/stdtest.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
test.run("set transform scale", _ => {
|
||||
var t = os.make_transform();
|
||||
var s1 = t.scale.slice();
|
||||
t.scale = s1;
|
||||
return (t.scale.equal(s1));
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,11 +1,23 @@
|
|||
/* Tests for prosperon */
|
||||
|
||||
var test = {};
|
||||
|
||||
var tests = [];
|
||||
var pass = 0;
|
||||
var fail = 0;
|
||||
var failed = [];
|
||||
|
||||
var test = function(name, fn)
|
||||
test.run_suite = function(file)
|
||||
{
|
||||
test = [];
|
||||
pass = 0;
|
||||
fail = 0;
|
||||
failed = [];
|
||||
|
||||
|
||||
}
|
||||
|
||||
test.run = function(name, fn)
|
||||
{
|
||||
var func = function() {
|
||||
print(`${pass+fail+1}/${tests.length}: ${name} ... `);
|
||||
|
@ -36,3 +48,5 @@ for (var f of failed)
|
|||
say(f);
|
||||
|
||||
os.quit();
|
||||
|
||||
return {test};
|
||||
|
|
|
@ -103,7 +103,7 @@ Ease.elastic = {
|
|||
Ease.elastic.c4 = 2*Math.PI/3;
|
||||
Ease.elastic.c5 = 2*Math.PI / 4.5;
|
||||
|
||||
var tween = function(from, to, time, fn)
|
||||
var tween = function(from, to, time, fn, endfn)
|
||||
{
|
||||
var start = profile.secs(profile.now());
|
||||
var update = function(dt) {
|
||||
|
@ -114,6 +114,7 @@ var tween = function(from, to, time, fn)
|
|||
fn(to);
|
||||
if (stop.then) stop.then();
|
||||
stop();
|
||||
endfn?.();
|
||||
}
|
||||
profile.endframe();
|
||||
};
|
||||
|
|
|
@ -27,17 +27,19 @@ void main() {
|
|||
in vec2 coords;
|
||||
in float rad;
|
||||
uniform vec4 shade;
|
||||
uniform float inner_r;
|
||||
out vec4 color;
|
||||
void main() {
|
||||
float px = 1/rad;
|
||||
float blur = 1.0+px;
|
||||
float R = 1;
|
||||
float R2 = 0.90;
|
||||
float dist = sqrt(dot(coords,coords));
|
||||
float sm = 1 - smoothstep(R-px,R,dist);
|
||||
float sm2 = smoothstep(R2-px,R2,dist);
|
||||
float R2 = 1-inner_r;
|
||||
float dist = distance(vec2(0,0),coords);
|
||||
float sm = 1 - smoothstep(R-px,R*blur,dist);
|
||||
float sm2 = smoothstep(R2-px,R2*blur,dist);
|
||||
|
||||
float alpha = sm*sm2;
|
||||
color = vec4(shade.xyz, alpha*alpha);
|
||||
color = vec4(shade.xyz, alpha*shade.a);
|
||||
}
|
||||
@end
|
||||
|
||||
|
|
|
@ -7,12 +7,14 @@
|
|||
in vec3 a_pos;
|
||||
in vec2 a_uv;
|
||||
out vec2 uv;
|
||||
out vec4 shade;
|
||||
|
||||
vec3 pos;
|
||||
|
||||
struct sprite {
|
||||
mat4 model;
|
||||
vec4 rect;
|
||||
vec4 shade;
|
||||
};
|
||||
|
||||
readonly buffer ssbo {
|
||||
|
@ -32,19 +34,20 @@ void main()
|
|||
pos *= vec3(diffuse_size * s.rect.zw,1);
|
||||
uv = (uv*s.rect.zw)+s.rect.xy;
|
||||
gl_Position = vp * s.model * vec4(pos, 1.0);
|
||||
shade = s.shade;
|
||||
}
|
||||
@end
|
||||
|
||||
@fs fs
|
||||
|
||||
in vec2 uv;
|
||||
in vec4 shade;
|
||||
|
||||
out vec4 color;
|
||||
|
||||
texture2D diffuse;
|
||||
sampler smp;
|
||||
|
||||
uniform vec4 shade;
|
||||
void frag()
|
||||
{
|
||||
color = texture(sampler2D(diffuse,smp), uv);
|
||||
|
|
|
@ -25,12 +25,11 @@ struct anim_channel {
|
|||
sampler *sampler;
|
||||
};
|
||||
|
||||
struct animation {
|
||||
char *name;
|
||||
typedef struct animation {
|
||||
double time;
|
||||
struct anim_channel *channels;
|
||||
sampler *samplers;
|
||||
};
|
||||
} animation;
|
||||
|
||||
void animation_run(struct animation *anim, float now);
|
||||
HMM_Vec4 sample_sampler(sampler *sampler, float time);
|
||||
|
|
|
@ -4,48 +4,73 @@
|
|||
#include "sokol/sokol_app.h"
|
||||
#include "imgui.h"
|
||||
#include "implot.h"
|
||||
#include "imnodes.h"
|
||||
#include "imgui_neo_sequencer.h"
|
||||
#include "ImSequencer.h"
|
||||
|
||||
#include "stb_ds.h"
|
||||
|
||||
#define SOKOL_IMPL
|
||||
#include "sokol/util/sokol_imgui.h"
|
||||
#include "sokol/util/sokol_gfx_imgui.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
static sgimgui_t sgimgui;
|
||||
|
||||
#include "jsffi.h"
|
||||
|
||||
JSC_CCALL(imgui_begin,
|
||||
char *title = js2strdup(argv[0]);
|
||||
static int wantkeys = 0;
|
||||
static int wantmouse = 0;
|
||||
|
||||
JSC_SCALL(imgui_window,
|
||||
bool active = true;
|
||||
ImGui::Begin(title, &active, ImGuiWindowFlags_MenuBar);
|
||||
free(title);
|
||||
return boolean2js(active);
|
||||
ImGui::Begin(str, &active);
|
||||
script_call_sym(argv[1], 0, NULL);
|
||||
ImGui::End();
|
||||
ret = boolean2js(active);
|
||||
)
|
||||
JSC_SCALL(imgui_menu,
|
||||
if (ImGui::BeginMenu(str)) {
|
||||
script_call_sym(argv[1], 0, NULL);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
)
|
||||
|
||||
JSC_CCALL(imgui_end, ImGui::End())
|
||||
JSC_CCALL(imgui_menubar,
|
||||
if (ImGui::BeginMenuBar()) {
|
||||
script_call_sym(argv[0], 0, NULL);
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
)
|
||||
|
||||
JSC_CCALL(imgui_beginmenu,
|
||||
char *title = js2strdup(argv[0]);
|
||||
bool active = ImGui::BeginMenu(title);
|
||||
free(title);
|
||||
return boolean2js(active);
|
||||
JSC_CCALL(imgui_mainmenubar,
|
||||
if (ImGui::BeginMainMenuBar()) {
|
||||
script_call_sym(argv[0], 0, NULL);
|
||||
ImGui::EndMainMenuBar();
|
||||
}
|
||||
)
|
||||
|
||||
JSC_CCALL(imgui_menuitem,
|
||||
char *name = js2strdup(argv[0]);
|
||||
char *hotkey = js2strdup(argv[1]);
|
||||
if (ImGui::MenuItem(name,hotkey))
|
||||
char *keyfn = JS_IsUndefined(argv[1]) ? NULL : js2strdup(argv[1]);
|
||||
bool on = JS_IsUndefined(argv[3]) ? false : js2boolean(argv[3]);
|
||||
if (ImGui::MenuItem(JS_Is(argv[0]) ? name : "##empty" ,keyfn, &on))
|
||||
script_call_sym(argv[2], 0, NULL);
|
||||
free(name);
|
||||
free(hotkey);
|
||||
|
||||
if (JS_Is(argv[0])) free(name);
|
||||
if (keyfn) free(keyfn);
|
||||
|
||||
return boolean2js(on);
|
||||
)
|
||||
|
||||
JSC_SCALL(imgui_startplot,
|
||||
JSC_SCALL(imgui_plot,
|
||||
ImPlot::SetNextAxisToFit(ImAxis_X1);
|
||||
ImPlot::SetNextAxisToFit(ImAxis_Y1);
|
||||
ImPlot::BeginPlot(str);
|
||||
script_call_sym(argv[1], 0, NULL);
|
||||
ImPlot::EndPlot();
|
||||
)
|
||||
|
||||
JSC_CCALL(imgui_endplot, ImPlot::EndPlot() )
|
||||
|
||||
JSC_SCALL(imgui_lineplot,
|
||||
double data[js_arrlen(argv[1])];
|
||||
for (int i = 0; i < js_arrlen(argv[1]); i++)
|
||||
|
@ -54,9 +79,6 @@ JSC_SCALL(imgui_lineplot,
|
|||
ImPlot::PlotLine(str, data, js_arrlen(argv[1]));
|
||||
)
|
||||
|
||||
JSC_CCALL(imgui_beginmenubar, ImGui::BeginMenuBar())
|
||||
JSC_CCALL(imgui_endmenubar, ImGui::EndMenuBar())
|
||||
|
||||
JSC_SSCALL(imgui_textinput,
|
||||
char buffer[512];
|
||||
strncpy(buffer, str2, 512);
|
||||
|
@ -64,17 +86,379 @@ JSC_SSCALL(imgui_textinput,
|
|||
ret = str2js(buffer);
|
||||
)
|
||||
|
||||
JSC_SSCALL(imgui_textbox,
|
||||
char buffer[512];
|
||||
strncpy(buffer, str2, 512);
|
||||
ImGui::InputTextMultiline(str, buffer, sizeof(buffer));
|
||||
ret = str2js(buffer);
|
||||
)
|
||||
|
||||
JSC_SCALL(imgui_text, ImGui::Text(str) )
|
||||
|
||||
JSC_SCALL(imgui_button,
|
||||
if (ImGui::Button(str))
|
||||
script_call_sym(argv[1], 1, argv);
|
||||
)
|
||||
|
||||
JSC_CCALL(imgui_sokol_gfx,
|
||||
sgimgui_draw(&sgimgui);
|
||||
if (ImGui::BeginMenu("sokol-gfx")) {
|
||||
ImGui::MenuItem("Capabilities", 0, &sgimgui.caps_window.open);
|
||||
ImGui::MenuItem("Frame Stats", 0, &sgimgui.frame_stats_window.open);
|
||||
ImGui::MenuItem("Buffers", 0, &sgimgui.buffer_window.open);
|
||||
ImGui::MenuItem("Images", 0, &sgimgui.image_window.open);
|
||||
ImGui::MenuItem("Samplers", 0, &sgimgui.sampler_window.open);
|
||||
ImGui::MenuItem("Shaders", 0, &sgimgui.shader_window.open);
|
||||
ImGui::MenuItem("Pipelines", 0, &sgimgui.pipeline_window.open);
|
||||
ImGui::MenuItem("Attachments", 0, &sgimgui.attachments_window.open);
|
||||
ImGui::MenuItem("Calls", 0, &sgimgui.capture_window.open);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
)
|
||||
|
||||
JSC_SCALL(imgui_slider,
|
||||
float low = JS_IsUndefined(argv[2]) ? 0.0 : js2number(argv[2]);
|
||||
float high = JS_IsUndefined(argv[3]) ? 1.0 : js2number(argv[3]);
|
||||
|
||||
if (JS_IsArray(js, argv[1])) {
|
||||
int n = js_arrlen(argv[1]);
|
||||
float a[n];
|
||||
js2floatarr(argv[1], n, a);
|
||||
|
||||
switch(n) {
|
||||
case 2:
|
||||
ImGui::SliderFloat2(str, a, low, high);
|
||||
break;
|
||||
case 3:
|
||||
ImGui::SliderFloat3(str, a, low, high);
|
||||
break;
|
||||
case 4:
|
||||
ImGui::SliderFloat3(str, a, low, high);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = floatarr2js(n, a);
|
||||
} else {
|
||||
float val = js2number(argv[1]);
|
||||
ImGui::SliderFloat(str, &val, low, high, "%.3f");
|
||||
ret = number2js(val);
|
||||
}
|
||||
)
|
||||
|
||||
JSC_SCALL(imgui_checkbox,
|
||||
bool val = js2boolean(argv[1]);
|
||||
ImGui::Checkbox(str, &val);
|
||||
ret = boolean2js(val);
|
||||
)
|
||||
|
||||
JSC_CCALL(imgui_pushid,
|
||||
ImGui::PushID(js2number(argv[0]));
|
||||
)
|
||||
|
||||
JSC_CCALL(imgui_popid, ImGui::PopID(); )
|
||||
|
||||
JSC_CCALL(imgui_image,
|
||||
texture *tex = js2texture(argv[0]);
|
||||
simgui_image_desc_t simgd;
|
||||
simgd.image = tex->id;
|
||||
simgd.sampler = std_sampler;
|
||||
simgui_image_t simgui_img = simgui_make_image(&simgd);
|
||||
ImTextureID tex_id = simgui_imtextureid(simgui_img);
|
||||
ImGui::Image(tex_id, ImVec2(tex->width, tex->height), ImVec2(0,0), ImVec2(1,1));
|
||||
simgui_destroy_image(simgui_img);
|
||||
)
|
||||
|
||||
JSC_CCALL(imgui_sameline, ImGui::SameLine(js2number(argv[0])) )
|
||||
JSC_CCALL(imgui_columns, ImGui::Columns(js2number(argv[0])) )
|
||||
JSC_CCALL(imgui_nextcolumn, ImGui::NextColumn() )
|
||||
JSC_SCALL(imgui_collapsingheader, ret = boolean2js(ImGui::CollapsingHeader(str)) )
|
||||
JSC_SCALL(imgui_radio, ret = boolean2js(ImGui::RadioButton(str, js2boolean(argv[1]))))
|
||||
|
||||
JSC_SCALL(imgui_tree,
|
||||
if (ImGui::TreeNode(str)) {
|
||||
script_call_sym(argv[1],0,NULL);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
)
|
||||
|
||||
JSC_SCALL(imgui_tabbar,
|
||||
if (ImGui::BeginTabBar(str)) {
|
||||
script_call_sym(argv[1],0,NULL);
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
)
|
||||
|
||||
JSC_SCALL(imgui_tab,
|
||||
if (ImGui::BeginTabItem(str)) {
|
||||
script_call_sym(argv[1],0,NULL);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
)
|
||||
|
||||
JSC_SCALL(imgui_listbox,
|
||||
char **arr = js2strarr(argv[1]);
|
||||
int n = js_arrlen(argv[1]);
|
||||
int idx = js2number(argv[2]);
|
||||
ImGui::ListBox(str, &idx, arr, n, 4);
|
||||
for (int i = 0; i < n; i++)
|
||||
free(arr[i]);
|
||||
|
||||
// arrfree(arr); // TODO: Doesn't this need freed?
|
||||
ret = number2js(idx);
|
||||
)
|
||||
|
||||
JSC_SCALL(imgui_int,
|
||||
int n = js2number(argv[1]);
|
||||
ImGui::InputInt(str, &n);
|
||||
ret = number2js(n);
|
||||
)
|
||||
|
||||
JSC_SCALL(imgui_open_popup,
|
||||
ImGui::OpenPopup(str);
|
||||
)
|
||||
|
||||
JSC_SCALL(imgui_popup,
|
||||
if (ImGui::BeginPopup(str)) {
|
||||
script_call_sym(argv[1],0,NULL);
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
)
|
||||
|
||||
JSC_CCALL(imgui_close_popup,
|
||||
ImGui::CloseCurrentPopup();
|
||||
)
|
||||
|
||||
JSC_SCALL(imgui_modal,
|
||||
if (ImGui::BeginPopupModal(str)) {
|
||||
script_call_sym(argv[1],0,NULL);
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
)
|
||||
|
||||
JSC_SCALL(imgui_context,
|
||||
if (ImGui::BeginPopupContextItem(str)) {
|
||||
script_call_sym(argv[1],0,NULL);
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
)
|
||||
|
||||
JSC_SCALL(imgui_table,
|
||||
if (ImGui::BeginTable(str, js2number(argv[1]))) {
|
||||
script_call_sym(argv[2],0,NULL);
|
||||
ImGui::EndTable();
|
||||
}
|
||||
)
|
||||
|
||||
JSC_CCALL(imgui_tablenextrow, ImGui::TableNextRow())
|
||||
JSC_CCALL(imgui_tablenextcolumn, ImGui::TableNextColumn())
|
||||
|
||||
JSC_SCALL(imgui_dnd,
|
||||
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
|
||||
double n = js2number(argv[1]);
|
||||
ImGui::SetDragDropPayload(str, &n, sizeof(n));
|
||||
script_call_sym(argv[2],0,NULL);
|
||||
ImGui::EndDragDropSource();
|
||||
}
|
||||
)
|
||||
|
||||
JSC_SCALL(imgui_dndtarget,
|
||||
if (ImGui::BeginDragDropTarget()) {
|
||||
if (const ImGuiPayload *payload = ImGui::AcceptDragDropPayload(str)) {
|
||||
JSValue n = number2js(*(double*)payload->Data);
|
||||
script_call_sym(argv[1], 1, &n);
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
)
|
||||
|
||||
JSC_SCALL(imgui_color,
|
||||
int n = js_arrlen(argv[1]);
|
||||
float color[n];
|
||||
js2floatarr(argv[1],n,color);
|
||||
|
||||
if (n == 3)
|
||||
ImGui::ColorEdit3(str, color);
|
||||
else if (n == 4)
|
||||
ImGui::ColorEdit4(str, color);
|
||||
|
||||
ret = floatarr2js(n, color);
|
||||
)
|
||||
|
||||
JSC_CCALL(imgui_startnode,
|
||||
ImNodes::BeginNodeEditor();
|
||||
script_call_sym(argv[0],0,NULL);
|
||||
ImNodes::EndNodeEditor();
|
||||
int start_attr;
|
||||
int end_attr;
|
||||
if (ImNodes::IsLinkCreated(&start_attr, &end_attr))
|
||||
{
|
||||
JSValue ab[2];
|
||||
ab[0] = number2js(start_attr);
|
||||
ab[1] = number2js(end_attr);
|
||||
script_call_sym(argv[1], 2, ab);
|
||||
|
||||
for (int i = 0; i < 2; i++) JS_FreeValue(js, ab[i]);
|
||||
}
|
||||
|
||||
int node_id;
|
||||
if (ImNodes::IsNodeHovered(&node_id))
|
||||
{
|
||||
JSValue a = number2js(node_id);
|
||||
script_call_sym(argv[2],1,&a);
|
||||
JS_FreeValue(js,a);
|
||||
}
|
||||
|
||||
int link_id;
|
||||
if (ImNodes::IsLinkHovered(&link_id))
|
||||
{
|
||||
JSValue a = number2js(link_id);
|
||||
script_call_sym(argv[3],1,&a);
|
||||
JS_FreeValue(js,a);
|
||||
}
|
||||
)
|
||||
|
||||
JSC_CCALL(imgui_node,
|
||||
ImNodes::BeginNode(js2number(argv[0]));
|
||||
script_call_sym(argv[1],0,NULL);
|
||||
ImNodes::EndNode();
|
||||
)
|
||||
|
||||
JSC_CCALL(imgui_nodein,
|
||||
ImNodes::BeginInputAttribute(js2number(argv[0]));
|
||||
script_call_sym(argv[1],0,NULL);
|
||||
ImNodes::EndInputAttribute();
|
||||
)
|
||||
|
||||
JSC_CCALL(imgui_nodeout,
|
||||
ImNodes::BeginOutputAttribute(js2number(argv[0]));
|
||||
script_call_sym(argv[1],0,NULL);
|
||||
ImNodes::EndOutputAttribute();
|
||||
)
|
||||
|
||||
JSC_CCALL(imgui_nodelink,
|
||||
ImNodes::Link(js2number(argv[0]), js2number(argv[1]), js2number(argv[2]));
|
||||
)
|
||||
|
||||
JSC_CCALL(imgui_nodemini, ImNodes::MiniMap(js2number(argv[0])))
|
||||
|
||||
struct MySequence : public ImSequencer::SequenceInterface {
|
||||
int GetFrameMin() const { return 0; }
|
||||
int GetFrameMax() const { return 100; }
|
||||
int GetItemCount() const { return 0; }
|
||||
virtual void Get(int index, int **start, int **end, int *type, unsigned int *color) {
|
||||
}
|
||||
};
|
||||
|
||||
JSC_SCALL(imgui_seq,
|
||||
struct MySequence mseq = {};
|
||||
|
||||
int selected = -1;
|
||||
int first = 0;
|
||||
int current = 100;
|
||||
bool expanded = true;
|
||||
Sequencer(&mseq, ¤t, &expanded, &selected, &first, ImSequencer::SEQUENCER_EDIT_STARTEND | ImSequencer::SEQUENCER_ADD | ImSequencer::SEQUENCER_DEL | ImSequencer::SEQUENCER_COPYPASTE | ImSequencer::SEQUENCER_CHANGE_FRAME);
|
||||
|
||||
)
|
||||
|
||||
JSC_SCALL(imgui_sequencer,
|
||||
int32_t current = js2number(js_getpropstr(argv[1], "current"));
|
||||
int32_t start = js2number(js_getpropstr(argv[1], "start"));
|
||||
int32_t end = js2number(js_getpropstr(argv[1], "end"));
|
||||
if(ImGui::BeginNeoSequencer(str, ¤t, &start, &end, {700,200},
|
||||
ImGuiNeoSequencerFlags_AllowLengthChanging |
|
||||
ImGuiNeoSequencerFlags_EnableSelection |
|
||||
ImGuiNeoSequencerFlags_Selection_EnableDragging |
|
||||
ImGuiNeoSequencerFlags_Selection_EnableDeletion)) {
|
||||
script_call_sym(argv[2], 0, NULL);
|
||||
ImGui::EndNeoSequencer();
|
||||
}
|
||||
|
||||
js_setpropstr(argv[1], "current", number2js(current));
|
||||
js_setpropstr(argv[1], "start", number2js(start));
|
||||
js_setpropstr(argv[1], "end", number2js(end));
|
||||
)
|
||||
|
||||
JSC_SCALL(imgui_timeline,
|
||||
float *k = js2newfloatarr(argv[1]);
|
||||
int n = arrlen(k);
|
||||
int32_t *keys = (int32_t*)malloc(n*sizeof(*keys));
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
keys[i] = k[i];
|
||||
}
|
||||
|
||||
arrfree(k);
|
||||
|
||||
if (ImGui::BeginNeoTimelineEx(str)) {
|
||||
for (int i = 0; i < n; i++)
|
||||
ImGui::NeoKeyframe(keys+i);
|
||||
ImGui::EndNeoTimeLine();
|
||||
}
|
||||
|
||||
JSValue arr = JS_NewArray(js);
|
||||
for (int i = 0; i < n; i++)
|
||||
js_setprop_num(arr, i, number2js(keys[i]));
|
||||
|
||||
free(keys);
|
||||
ret = arr;
|
||||
)
|
||||
|
||||
JSC_SCALL(imgui_tlgroup,
|
||||
if (ImGui::BeginNeoGroup(str)) {
|
||||
script_call_sym(argv[1], 0, NULL);
|
||||
ImGui::EndNeoGroup();
|
||||
}
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_imgui_funcs[] = {
|
||||
MIST_FUNC_DEF(imgui, begin, 1),
|
||||
MIST_FUNC_DEF(imgui, end,0),
|
||||
MIST_FUNC_DEF(imgui, beginmenu, 1),
|
||||
MIST_FUNC_DEF(imgui, window, 2),
|
||||
MIST_FUNC_DEF(imgui, menu, 2),
|
||||
MIST_FUNC_DEF(imgui, sameline, 1),
|
||||
MIST_FUNC_DEF(imgui, int, 2),
|
||||
MIST_FUNC_DEF(imgui, pushid, 1),
|
||||
MIST_FUNC_DEF(imgui, popid, 0),
|
||||
MIST_FUNC_DEF(imgui, slider, 4),
|
||||
MIST_FUNC_DEF(imgui, menubar, 1),
|
||||
MIST_FUNC_DEF(imgui, mainmenubar, 1),
|
||||
MIST_FUNC_DEF(imgui, menuitem, 3),
|
||||
MIST_FUNC_DEF(imgui, beginmenubar, 0),
|
||||
MIST_FUNC_DEF(imgui, endmenubar, 0),
|
||||
MIST_FUNC_DEF(imgui, radio, 2),
|
||||
MIST_FUNC_DEF(imgui, image, 1),
|
||||
MIST_FUNC_DEF(imgui, textinput, 2),
|
||||
MIST_FUNC_DEF(imgui, startplot,1),
|
||||
MIST_FUNC_DEF(imgui,endplot,0),
|
||||
MIST_FUNC_DEF(imgui,lineplot,2)
|
||||
MIST_FUNC_DEF(imgui, textbox, 2),
|
||||
MIST_FUNC_DEF(imgui, button, 2),
|
||||
MIST_FUNC_DEF(imgui, checkbox, 2),
|
||||
MIST_FUNC_DEF(imgui, text, 1),
|
||||
MIST_FUNC_DEF(imgui, plot,1),
|
||||
MIST_FUNC_DEF(imgui, lineplot,2),
|
||||
MIST_FUNC_DEF(imgui, sokol_gfx, 0),
|
||||
MIST_FUNC_DEF(imgui, columns, 1),
|
||||
MIST_FUNC_DEF(imgui, nextcolumn, 0),
|
||||
MIST_FUNC_DEF(imgui, collapsingheader, 1),
|
||||
MIST_FUNC_DEF(imgui, tree, 2),
|
||||
MIST_FUNC_DEF(imgui, listbox, 3),
|
||||
MIST_FUNC_DEF(imgui, tabbar, 2),
|
||||
MIST_FUNC_DEF(imgui, tab, 2),
|
||||
MIST_FUNC_DEF(imgui, open_popup, 1),
|
||||
MIST_FUNC_DEF(imgui, modal, 2),
|
||||
MIST_FUNC_DEF(imgui, popup, 2),
|
||||
MIST_FUNC_DEF(imgui, close_popup,0),
|
||||
MIST_FUNC_DEF(imgui, context,2),
|
||||
MIST_FUNC_DEF(imgui, table, 3),
|
||||
MIST_FUNC_DEF(imgui, tablenextcolumn,0),
|
||||
MIST_FUNC_DEF(imgui, tablenextrow,0),
|
||||
MIST_FUNC_DEF(imgui, dnd, 3),
|
||||
MIST_FUNC_DEF(imgui, dndtarget, 2),
|
||||
MIST_FUNC_DEF(imgui, color, 2),
|
||||
MIST_FUNC_DEF(imgui, startnode, 1),
|
||||
MIST_FUNC_DEF(imgui, node, 2),
|
||||
MIST_FUNC_DEF(imgui, nodein, 2),
|
||||
MIST_FUNC_DEF(imgui, nodeout, 2),
|
||||
MIST_FUNC_DEF(imgui, nodelink, 3),
|
||||
MIST_FUNC_DEF(imgui, nodemini, 1),
|
||||
MIST_FUNC_DEF(imgui, sequencer, 3),
|
||||
MIST_FUNC_DEF(imgui, timeline, 3),
|
||||
MIST_FUNC_DEF(imgui, tlgroup, 2),
|
||||
MIST_FUNC_DEF(imgui, seq, 3),
|
||||
};
|
||||
|
||||
static int started = 0;
|
||||
|
@ -88,6 +472,7 @@ JSValue gui_init(JSContext *js)
|
|||
sgimgui_init(&sgimgui, &desc);
|
||||
|
||||
ImPlot::CreateContext();
|
||||
ImNodes::CreateContext();
|
||||
|
||||
JSValue imgui = JS_NewObject(js);
|
||||
JS_SetPropertyFunctionList(js, imgui, js_imgui_funcs, countof(js_imgui_funcs));
|
||||
|
@ -97,8 +482,11 @@ JSValue gui_init(JSContext *js)
|
|||
|
||||
void gui_input(sapp_event *e)
|
||||
{
|
||||
if (started)
|
||||
if (!started) return;
|
||||
simgui_handle_event(e);
|
||||
ImGuiIO io = ImGui::GetIO();
|
||||
wantkeys = io.WantCaptureKeyboard;
|
||||
wantmouse = io.WantCaptureMouse;
|
||||
}
|
||||
|
||||
void gui_newframe(int x, int y, float dt)
|
||||
|
@ -111,12 +499,6 @@ void gui_newframe(int x, int y, float dt)
|
|||
simgui_new_frame(&frame);
|
||||
}
|
||||
|
||||
void gfx_gui()
|
||||
{
|
||||
sgimgui_draw(&sgimgui);
|
||||
sgimgui_draw_menu(&sgimgui, "sokol-gfx");
|
||||
}
|
||||
|
||||
void gui_endframe()
|
||||
{
|
||||
simgui_render();
|
||||
|
@ -126,3 +508,6 @@ void gui_exit()
|
|||
{
|
||||
sgimgui_discard(&sgimgui);
|
||||
}
|
||||
|
||||
int gui_wantmouse() { return wantmouse; }
|
||||
int gui_wantkeys() { return wantkeys; }
|
||||
|
|
|
@ -15,6 +15,9 @@ void gui_input(sapp_event *e);
|
|||
void gui_endframe();
|
||||
void gui_exit();
|
||||
|
||||
int gui_wantmouse();
|
||||
int gui_wantkeys();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#include "par/par_shapes.h"
|
||||
#include "sokol_glue.h"
|
||||
#include <chipmunk/chipmunk_unsafe.h>
|
||||
#include <chipmunk/chipmunk_structs.h>
|
||||
#include <stdint.h>
|
||||
#include "gui.h"
|
||||
#include "timer.h"
|
||||
|
||||
|
@ -46,8 +48,6 @@ static JSValue globalThis;
|
|||
static JSClassID js_ptr_id;
|
||||
static JSClassDef js_ptr_class = { "POINTER" };
|
||||
|
||||
static JSValue JSUNDEF;
|
||||
|
||||
JSValue str2js(const char *c, ...) {
|
||||
if (!c) return JS_UNDEFINED;
|
||||
char *result = NULL;
|
||||
|
@ -62,6 +62,8 @@ JSValue str2js(const char *c, ...) {
|
|||
return JS_NewString(js, buf);
|
||||
}
|
||||
|
||||
int JS_Is(JSValue v) { return JS_ToBool(js, v); }
|
||||
|
||||
const char *js2str(JSValue v) {
|
||||
return JS_ToCString(js, v);
|
||||
}
|
||||
|
@ -93,6 +95,11 @@ void cpConstraint_free(cpConstraint *c)
|
|||
cpConstraintFree(c);
|
||||
}
|
||||
|
||||
void skin_free(skin *sk) {
|
||||
arrfree(sk->invbind);
|
||||
free(sk);
|
||||
}
|
||||
|
||||
void jsfreestr(const char *s) { JS_FreeCString(js, s); }
|
||||
QJSCLASS(gameobject)
|
||||
QJSCLASS(transform)
|
||||
|
@ -107,6 +114,7 @@ QJSCLASS(datastream)
|
|||
QJSCLASS(cpShape)
|
||||
QJSCLASS(cpConstraint)
|
||||
QJSCLASS(timer)
|
||||
QJSCLASS(skin);
|
||||
|
||||
static JSValue js_circle2d;
|
||||
static JSValue js_poly2d;
|
||||
|
@ -155,6 +163,7 @@ void js_setprop_num(JSValue obj, uint32_t i, JSValue v) { JS_SetPropertyUint32(j
|
|||
|
||||
JSValue js_getpropidx(JSValue v, uint32_t i)
|
||||
{
|
||||
if (!JS_IsArray(js, v)) return JS_UNDEFINED;
|
||||
JSValue p = JS_GetPropertyUint32(js, v, i);
|
||||
JS_FreeValue(js,p);
|
||||
return p;
|
||||
|
@ -175,6 +184,17 @@ void js_setpropstr(JSValue v, const char *str, JSValue p)
|
|||
|
||||
static inline cpBody *js2body(JSValue v) { return js2gameobject(v)->body; }
|
||||
|
||||
char **js2strarr(JSValue v)
|
||||
{
|
||||
int n = js_arrlen(v);
|
||||
char **arr = malloc(sizeof(*arr));
|
||||
arr = NULL;
|
||||
for (int i = 0; i < n; i++)
|
||||
arrput(arr, js2strdup(js_getpropidx(v, i)));
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
JSValue strarr2js(char **c)
|
||||
{
|
||||
JSValue arr = JS_NewArray(js);
|
||||
|
@ -202,6 +222,7 @@ uint64_t js2uint64(JSValue v)
|
|||
JSValue angle2js(double g) {
|
||||
return number2js(g*HMM_RadToTurn);
|
||||
}
|
||||
|
||||
double js2angle(JSValue v) {
|
||||
double n = js2number(v);
|
||||
return n * HMM_TurnToRad;
|
||||
|
@ -374,6 +395,29 @@ struct boundingbox js2bb(JSValue v)
|
|||
cpVect js2cvec2(JSValue v) { return js2vec2(v).cp; }
|
||||
JSValue cvec22js(cpVect v) { return vec22js((HMM_Vec2)v); }
|
||||
|
||||
void js2floatarr(JSValue v, int n, float *a) {
|
||||
if (!JS_IsArray(js,v)) return;
|
||||
for (int i = 0; i < n; i++)
|
||||
a[i] = js2number(js_getpropidx(v,i));
|
||||
}
|
||||
|
||||
JSValue floatarr2js(int n, float *a) {
|
||||
JSValue arr = JS_NewArray(js);
|
||||
for (int i = 0; i < n; i++)
|
||||
js_setprop_num(arr, i, number2js(a[i]));
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
float *js2newfloatarr(JSValue v)
|
||||
{
|
||||
float *arr = NULL;
|
||||
for (int i = 0; i < js_arrlen(v); i++)
|
||||
arrpush(arr, js2number(js_getpropidx(v,i)));
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
HMM_Vec2 js2vec2(JSValue v)
|
||||
{
|
||||
HMM_Vec2 v2;
|
||||
|
@ -399,6 +443,16 @@ HMM_Vec3 js2vec3(JSValue v)
|
|||
return v3;
|
||||
}
|
||||
|
||||
HMM_Vec3 js2vec3f(JSValue v)
|
||||
{
|
||||
HMM_Vec3 vec;
|
||||
if (JS_IsArray(js, v))
|
||||
return js2vec3(v);
|
||||
else
|
||||
vec.x = vec.y = vec.z = js2number(v);
|
||||
return vec;
|
||||
}
|
||||
|
||||
JSValue vec32js(HMM_Vec3 v)
|
||||
{
|
||||
JSValue array = JS_NewArray(js);
|
||||
|
@ -408,6 +462,8 @@ JSValue vec32js(HMM_Vec3 v)
|
|||
return array;
|
||||
}
|
||||
|
||||
JSValue vec3f2js(HMM_Vec3 v) { return vec32js(v); }
|
||||
|
||||
JSValue quat2js(HMM_Quat q)
|
||||
{
|
||||
JSValue arr = JS_NewArray(js);
|
||||
|
@ -426,6 +482,22 @@ HMM_Vec4 js2vec4(JSValue v)
|
|||
return v4;
|
||||
}
|
||||
|
||||
double arr_vec_length(JSValue v)
|
||||
{
|
||||
int len = js_arrlen(v);
|
||||
switch(len) {
|
||||
case 2: return HMM_LenV2(js2vec2(v));
|
||||
case 3: return HMM_LenV3(js2vec3(v));
|
||||
case 4: return HMM_LenV4(js2vec4(v));
|
||||
}
|
||||
|
||||
double sum = 0;
|
||||
for (int i = 0; i < len; i++)
|
||||
sum += pow(js2number(js_getpropidx(v, i)), 2);
|
||||
|
||||
return sqrt(sum);
|
||||
}
|
||||
|
||||
HMM_Quat js2quat(JSValue v)
|
||||
{
|
||||
return js2vec4(v).quat;
|
||||
|
@ -504,6 +576,7 @@ int js_print_exception(JSValue v)
|
|||
JS_FreeCString(js, msg);
|
||||
JS_FreeCString(js, stack);
|
||||
JS_FreeValue(js,ex);
|
||||
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
|
@ -641,8 +714,10 @@ sg_bindings js2bind(JSValue v)
|
|||
{
|
||||
sg_bindings bind = {0};
|
||||
JSValue attrib = js_getpropstr(v, "attrib");
|
||||
for (int i = 0; i < js_arrlen(attrib); i++)
|
||||
|
||||
for (int i = 0; i < js_arrlen(attrib); i++) {
|
||||
bind.vertex_buffers[i] = *js2sg_buffer(js_getpropidx(attrib,i));
|
||||
}
|
||||
|
||||
JSValue index = js_getpropstr(v, "index");
|
||||
if (!JS_IsUndefined(index))
|
||||
|
@ -836,6 +911,33 @@ sg_shader js2shader(JSValue v)
|
|||
return sh;
|
||||
}
|
||||
|
||||
static int mat2type(int mat)
|
||||
{
|
||||
switch(mat) {
|
||||
case MAT_POS:
|
||||
case MAT_NORM:
|
||||
return SG_VERTEXFORMAT_FLOAT3;
|
||||
case MAT_PPOS:
|
||||
case MAT_WH:
|
||||
case MAT_ST:
|
||||
return SG_VERTEXFORMAT_FLOAT2;
|
||||
case MAT_UV:
|
||||
return SG_VERTEXFORMAT_USHORT2N;
|
||||
case MAT_TAN:
|
||||
return SG_VERTEXFORMAT_UINT10_N2;
|
||||
case MAT_BONE:
|
||||
return SG_VERTEXFORMAT_UBYTE4;
|
||||
case MAT_WEIGHT:
|
||||
case MAT_COLOR:
|
||||
return SG_VERTEXFORMAT_UBYTE4N;
|
||||
case MAT_ANGLE:
|
||||
case MAT_SCALE:
|
||||
return SG_VERTEXFORMAT_FLOAT;
|
||||
};
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
sg_vertex_layout_state js2layout(JSValue v)
|
||||
{
|
||||
sg_vertex_layout_state st = {0};
|
||||
|
@ -916,6 +1018,11 @@ JSC_CCALL(render_setunivp,
|
|||
sg_apply_uniforms(js2number(argv[0]), js2number(argv[1]), SG_RANGE_REF(globalview.vp));
|
||||
)
|
||||
|
||||
JSC_CCALL(render_setunibones,
|
||||
skin *sk = js2skin(argv[2]);
|
||||
sg_apply_uniforms(js2number(argv[0]), js2number(argv[1]), SG_RANGE_REF(sk->binds));
|
||||
)
|
||||
|
||||
JSC_CCALL(render_setunim4,
|
||||
HMM_Mat4 m = MAT1;
|
||||
if (JS_IsArray(js, argv[2])) {
|
||||
|
@ -950,7 +1057,6 @@ JSC_CCALL(render_make_particle_ssbo,
|
|||
size_t size = js_arrlen(array)*(sizeof(particle_ss));
|
||||
sg_buffer *b = js2sg_buffer(argv[1]);
|
||||
if (!b) return JS_UNDEFINED;
|
||||
|
||||
particle_ss ms[js_arrlen(array)];
|
||||
|
||||
if (sg_query_buffer_will_overflow(*b, size)) {
|
||||
|
@ -978,6 +1084,7 @@ JSC_CCALL(render_make_particle_ssbo,
|
|||
typedef struct sprite_ss {
|
||||
HMM_Mat4 model;
|
||||
HMM_Vec4 rect;
|
||||
HMM_Vec4 shade;
|
||||
} sprite_ss;
|
||||
|
||||
JSC_CCALL(render_make_sprite_ssbo,
|
||||
|
@ -1002,6 +1109,7 @@ JSC_CCALL(render_make_sprite_ssbo,
|
|||
JSValue sub = js_getpropidx(array,i);
|
||||
ms[i].model = transform2mat(js2transform(js_getpropstr(sub, "transform")));
|
||||
ms[i].rect = js2vec4(js_getpropstr(sub,"rect"));
|
||||
ms[i].shade = js2vec4(js_getpropstr(sub,"shade"));
|
||||
}
|
||||
|
||||
sg_append_buffer(*b, (&(sg_range){
|
||||
|
@ -1038,7 +1146,7 @@ JSC_CCALL(render_make_t_ssbo,
|
|||
)
|
||||
|
||||
JSC_CCALL(render_spdraw,
|
||||
sg_draw(0,js2number(argv[0]),js2number(argv[1]));
|
||||
sg_draw(js2number(argv[0]),js2number(argv[1]),js2number(argv[2]));
|
||||
)
|
||||
|
||||
JSC_CCALL(render_setpipeline,
|
||||
|
@ -1054,7 +1162,6 @@ JSC_CCALL(render_screencolor,
|
|||
)
|
||||
|
||||
JSC_CCALL(render_imgui_new, gui_newframe(js2number(argv[0]),js2number(argv[1]),js2number(argv[2])); )
|
||||
JSC_CCALL(render_gfx_gui, gfx_gui())
|
||||
JSC_CCALL(render_imgui_end, gui_endframe())
|
||||
|
||||
JSC_CCALL(render_imgui_init, return gui_init(js))
|
||||
|
@ -1072,7 +1179,8 @@ static const JSCFunctionListEntry js_render_funcs[] = {
|
|||
MIST_FUNC_DEF(render, pipeline, 1),
|
||||
MIST_FUNC_DEF(render, setuniv3, 2),
|
||||
MIST_FUNC_DEF(render, setuniv, 2),
|
||||
MIST_FUNC_DEF(render, spdraw, 2),
|
||||
MIST_FUNC_DEF(render, spdraw, 3),
|
||||
MIST_FUNC_DEF(render, setunibones, 3),
|
||||
MIST_FUNC_DEF(render, setbind, 1),
|
||||
MIST_FUNC_DEF(render, setuniproj, 2),
|
||||
MIST_FUNC_DEF(render, setuniview, 2),
|
||||
|
@ -1083,7 +1191,6 @@ static const JSCFunctionListEntry js_render_funcs[] = {
|
|||
MIST_FUNC_DEF(render, setpipeline, 1),
|
||||
MIST_FUNC_DEF(render, screencolor, 0),
|
||||
MIST_FUNC_DEF(render, imgui_new, 3),
|
||||
MIST_FUNC_DEF(render, gfx_gui, 0),
|
||||
MIST_FUNC_DEF(render, imgui_end, 0),
|
||||
MIST_FUNC_DEF(render, imgui_init, 0),
|
||||
MIST_FUNC_DEF(render, make_t_ssbo, 2),
|
||||
|
@ -1217,12 +1324,14 @@ JSC_CCALL(vector_inflate,
|
|||
|
||||
JSC_CCALL(vector_rotate,
|
||||
HMM_Vec2 vec = js2vec2(argv[0]);
|
||||
float r = HMM_LenV2(vec);
|
||||
double angle = js2angle(argv[1]);
|
||||
HMM_Vec2 pivot = JS_IsUndefined(argv[2]) ? v2zero : js2vec2(argv[2]);
|
||||
vec = HMM_SubV2(vec,pivot);
|
||||
float r = HMM_LenV2(vec);
|
||||
angle += atan2(vec.y,vec.x);
|
||||
vec.x = r*cos(angle);
|
||||
vec.y = r*sin(angle);
|
||||
return vec22js(vec);
|
||||
return vec22js(HMM_AddV2(vec,pivot));
|
||||
)
|
||||
|
||||
JSC_CCALL(vector_add,
|
||||
|
@ -1240,7 +1349,14 @@ JSC_CCALL(vector_norm,
|
|||
case 3: return vec32js(HMM_NormV3(js2vec3(argv[0])));
|
||||
case 4: return vec42js(HMM_NormV4(js2vec4(argv[0])));
|
||||
}
|
||||
return argv[0];
|
||||
|
||||
double length = arr_vec_length(argv[0]);
|
||||
JSValue newarr = JS_NewArray(js);
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
js_setprop_num(newarr, i, number2js(js2number(js_getpropidx(argv[0],i))/length));
|
||||
|
||||
return newarr;
|
||||
)
|
||||
|
||||
JSC_CCALL(vector_angle_between,
|
||||
|
@ -1315,6 +1431,10 @@ JSC_CCALL(vector_angledist,
|
|||
return number2js(dist);
|
||||
)
|
||||
|
||||
JSC_CCALL(vector_length,
|
||||
return number2js(arr_vec_length(argv[0]));
|
||||
)
|
||||
|
||||
double r2()
|
||||
{
|
||||
return (double)rand() / (double)RAND_MAX ;
|
||||
|
@ -1415,7 +1535,8 @@ static const JSCFunctionListEntry js_vector_funcs[] = {
|
|||
MIST_FUNC_DEF(vector, mean, 1),
|
||||
MIST_FUNC_DEF(vector, sum, 1),
|
||||
MIST_FUNC_DEF(vector, sigma, 1),
|
||||
MIST_FUNC_DEF(vector, median, 1)
|
||||
MIST_FUNC_DEF(vector, median, 1),
|
||||
MIST_FUNC_DEF(vector, length, 1)
|
||||
};
|
||||
|
||||
#define JS_HMM_FN(OP, HMM, SIGN) \
|
||||
|
@ -1452,9 +1573,9 @@ JS_HMM_FN(div, Div, /)
|
|||
JS_HMM_FN(scale, Mul, *)
|
||||
|
||||
JSC_CCALL(array_lerp,
|
||||
double t = js2number(argv[1]);
|
||||
int len = js_arrlen(self);
|
||||
JSValue arr = JS_NewArray(js);
|
||||
double t = js2number(argv[1]);
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
double from = js2number(js_getpropidx(self, i));
|
||||
|
@ -1465,11 +1586,11 @@ JSC_CCALL(array_lerp,
|
|||
)
|
||||
|
||||
static const JSCFunctionListEntry js_array_funcs[] = {
|
||||
MIST_FUNC_DEF(array, add, 1),
|
||||
MIST_FUNC_DEF(array, sub, 1),
|
||||
MIST_FUNC_DEF(array, div,1),
|
||||
MIST_FUNC_DEF(array, scale, 1),
|
||||
MIST_FUNC_DEF(array, lerp, 2)
|
||||
PROTO_FUNC_DEF(array, add, 1),
|
||||
PROTO_FUNC_DEF(array, sub, 1),
|
||||
PROTO_FUNC_DEF(array, div,1),
|
||||
PROTO_FUNC_DEF(array, scale, 1),
|
||||
PROTO_FUNC_DEF(array, lerp, 2)
|
||||
};
|
||||
|
||||
JSC_CCALL(game_engine_start, engine_start(argv[0],argv[1], js2number(argv[2]), js2number(argv[3])))
|
||||
|
@ -1540,6 +1661,7 @@ static const JSCFunctionListEntry js_time_funcs[] = {
|
|||
};
|
||||
|
||||
JSC_SCALL(console_print, log_print(str))
|
||||
JSC_SCALL(console_term_print, term_print(str));
|
||||
|
||||
JSValue js_console_rec(JSContext *js, JSValue self, int argc, JSValue *argv)
|
||||
{
|
||||
|
@ -1560,6 +1682,7 @@ JSC_GETSET_GLOBAL(stdout_lvl, number)
|
|||
|
||||
static const JSCFunctionListEntry js_console_funcs[] = {
|
||||
MIST_FUNC_DEF(console,print,1),
|
||||
MIST_FUNC_DEF(console, term_print, 1),
|
||||
MIST_FUNC_DEF(console,rec,4),
|
||||
CGETSET_ADD(global, stdout_lvl)
|
||||
};
|
||||
|
@ -1629,6 +1752,7 @@ JSValue js_io_slurpbytes(JSContext *js, JSValue self, int argc, JSValue *argv)
|
|||
|
||||
JSValue js_io_slurp(JSContext *js, JSValue self, int argc, JSValue *argv)
|
||||
{
|
||||
|
||||
char *f = js2str(argv[0]);
|
||||
size_t len;
|
||||
|
||||
|
@ -1835,7 +1959,7 @@ static const JSCFunctionListEntry js_physics_funcs[] = {
|
|||
};
|
||||
|
||||
JSC_GETSET(transform, pos, vec3)
|
||||
JSC_GETSET(transform, scale, vec3)
|
||||
JSC_GETSET(transform, scale, vec3f)
|
||||
JSC_GETSET(transform, rotation, quat)
|
||||
JSC_CCALL(transform_move, transform_move(js2transform(self), js2vec3(argv[0])); )
|
||||
|
||||
|
@ -2383,6 +2507,8 @@ JSC_GET(texture, width, number)
|
|||
JSC_GET(texture, height, number)
|
||||
JSC_GET(texture, frames, number)
|
||||
JSC_GET(texture, delays, ints)
|
||||
JSC_GET(texture, size, number)
|
||||
JSC_GET(texture, gpusize, number)
|
||||
|
||||
JSC_SCALL(texture_save, texture_save(js2texture(self), str));
|
||||
|
||||
|
@ -2390,13 +2516,21 @@ JSC_CCALL(texture_blit,
|
|||
texture *tex = js2texture(self);
|
||||
texture_blit(js2texture(self), js2texture(argv[0]), js2number(argv[1]), js2number(argv[2]), js2number(argv[3]), js2number(argv[4])))
|
||||
|
||||
JSC_CCALL(texture_getid,
|
||||
texture *tex = js2texture(self);
|
||||
return number2js(tex->id.id);
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_texture_funcs[] = {
|
||||
MIST_GET(texture, width),
|
||||
MIST_GET(texture, height),
|
||||
MIST_GET(texture, frames),
|
||||
MIST_GET(texture, delays),
|
||||
MIST_GET(texture, gpusize),
|
||||
MIST_GET(texture, size),
|
||||
MIST_FUNC_DEF(texture, save, 1),
|
||||
MIST_FUNC_DEF(texture, blit, 5)
|
||||
MIST_FUNC_DEF(texture, blit, 5),
|
||||
MIST_FUNC_DEF(texture, getid, 0),
|
||||
};
|
||||
|
||||
static const JSCFunctionListEntry js_timer_funcs[] = {
|
||||
|
@ -2466,7 +2600,6 @@ static const JSCFunctionListEntry js_nota_funcs[] = {
|
|||
MIST_FUNC_DEF(nota, decode, 1)
|
||||
};
|
||||
|
||||
|
||||
JSValue js_os_cwd(JSContext *js, JSValue self, int argc, JSValue *argv)
|
||||
{
|
||||
char cwd[PATH_MAX];
|
||||
|
@ -2501,6 +2634,141 @@ JSC_CCALL(os_quit, quit();)
|
|||
JSC_CCALL(os_exit, exit(js2number(argv[0]));)
|
||||
JSC_CCALL(os_reindex_static, cpSpaceReindexStatic(space));
|
||||
JSC_CCALL(os_gc, script_gc());
|
||||
JSC_CCALL(os_mem_limit, script_mem_limit(js2number(argv[0])))
|
||||
JSC_CCALL(os_gc_threshold, script_gc_threshold(js2number(argv[0])))
|
||||
JSC_CCALL(os_max_stacksize, script_max_stacksize(js2number(argv[0])))
|
||||
|
||||
static JSValue tmp2js(FILE *tmp)
|
||||
{
|
||||
size_t size = ftell(tmp);
|
||||
rewind(tmp);
|
||||
char *buffer = calloc(size+1, sizeof(char));
|
||||
fread(buffer, sizeof(char),size, tmp);
|
||||
JSValue ret = str2js(buffer);
|
||||
free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
JSC_CCALL(os_dump_value,
|
||||
|
||||
FILE *tmp = tmpfile();
|
||||
quickjs_set_dumpout(tmp);
|
||||
JS_DumpMyValue(rt, argv[0]);
|
||||
ret = tmp2js(tmp);
|
||||
)
|
||||
|
||||
JSC_CCALL(os_dump_atoms,
|
||||
FILE *tmp = tmpfile();
|
||||
quickjs_set_dumpout(tmp);
|
||||
JS_PrintAtoms(rt);
|
||||
ret = tmp2js(tmp);
|
||||
)
|
||||
|
||||
JSC_CCALL(os_dump_shapes,
|
||||
FILE *tmp = tmpfile();
|
||||
quickjs_set_dumpout(tmp);
|
||||
JS_PrintShapes(rt);
|
||||
size_t size = ftell(tmp);
|
||||
rewind(tmp);
|
||||
char buffer[size];
|
||||
fgets(buffer, sizeof(char)*size, tmp);
|
||||
fclose(tmp);
|
||||
ret = str2js(buffer);
|
||||
)
|
||||
|
||||
JSC_CCALL(os_calc_mem,
|
||||
return number2js(JS_MyValueSize(rt, argv[0]));
|
||||
)
|
||||
|
||||
#define JSOBJ_ADD_FIELD(OBJ, STRUCT, FIELD, TYPE) \
|
||||
js_setpropstr(OBJ, #FIELD, TYPE##2js(STRUCT.FIELD));\
|
||||
|
||||
#define JSJMEMRET(FIELD) JSOBJ_ADD_FIELD(ret, jsmem, FIELD, number)
|
||||
|
||||
JSC_CCALL(os_memstate,
|
||||
JSMemoryUsage jsmem;
|
||||
JS_FillMemoryState(rt, &jsmem);
|
||||
ret = JS_NewObject(js);
|
||||
JSJMEMRET(malloc_size)
|
||||
JSJMEMRET(malloc_limit)
|
||||
JSJMEMRET(gc_threshold)
|
||||
)
|
||||
|
||||
JSC_CCALL(os_mem,
|
||||
JSMemoryUsage jsmem;
|
||||
JS_ComputeMemoryUsage(rt, &jsmem);
|
||||
ret = JS_NewObject(js);
|
||||
JSJMEMRET(malloc_size)
|
||||
JSJMEMRET(malloc_limit)
|
||||
JSJMEMRET(gc_threshold)
|
||||
JSJMEMRET(memory_used_size)
|
||||
JSJMEMRET(memory_used_count)
|
||||
JSJMEMRET(atom_count)
|
||||
JSJMEMRET(atom_size)
|
||||
JSJMEMRET(str_count)
|
||||
JSJMEMRET(str_size)
|
||||
JSJMEMRET(obj_count)
|
||||
JSJMEMRET(obj_size)
|
||||
JSJMEMRET(prop_count)
|
||||
JSJMEMRET(prop_size)
|
||||
JSJMEMRET(shape_count)
|
||||
JSJMEMRET(shape_size)
|
||||
JSJMEMRET(js_func_count)
|
||||
JSJMEMRET(js_func_size)
|
||||
JSJMEMRET(js_func_code_size)
|
||||
JSJMEMRET(js_func_pc2line_count)
|
||||
JSJMEMRET(js_func_pc2line_size)
|
||||
JSJMEMRET(c_func_count)
|
||||
JSJMEMRET(array_count)
|
||||
JSJMEMRET(fast_array_count)
|
||||
JSJMEMRET(fast_array_elements)
|
||||
JSJMEMRET(binary_object_count)
|
||||
JSJMEMRET(binary_object_size)
|
||||
)
|
||||
|
||||
JSC_CCALL(os_dump_mem,
|
||||
FILE *tmp = tmpfile();
|
||||
JSMemoryUsage mem = {0};
|
||||
JS_DumpMemoryUsage(tmp, &mem, rt);
|
||||
ret = tmp2js(tmp);
|
||||
)
|
||||
|
||||
JSC_CCALL(os_value_id,
|
||||
return number2js((intptr_t)JS_VALUE_GET_PTR(argv[0]));
|
||||
)
|
||||
|
||||
static double gc_t = 0;
|
||||
static double gc_mem = 0;
|
||||
static double gc_startmem = 0;
|
||||
void script_report_gc_time(double t, double startmem, double mem)
|
||||
{
|
||||
gc_t = t;
|
||||
gc_mem = mem;
|
||||
gc_startmem = startmem;
|
||||
}
|
||||
|
||||
static FILE *cycles;
|
||||
|
||||
JSC_CCALL(os_check_cycles,
|
||||
if (ftell(cycles) == 0) return JS_UNDEFINED;
|
||||
cycles = tmpfile();
|
||||
quickjs_set_cycleout(cycles);
|
||||
ret = tmp2js(cycles);
|
||||
)
|
||||
|
||||
JSC_CCALL(os_check_gc,
|
||||
if (gc_t == 0) return JS_UNDEFINED;
|
||||
|
||||
JSValue gc = JS_NewObject(js);
|
||||
js_setpropstr(gc, "time", number2js(gc_t));
|
||||
js_setpropstr(gc, "mem", number2js(gc_mem));
|
||||
js_setpropstr(gc, "startmem", number2js(gc_startmem));
|
||||
gc_t = 0;
|
||||
gc_mem = 0;
|
||||
gc_startmem = 0;
|
||||
return gc;
|
||||
)
|
||||
|
||||
JSC_SSCALL(os_eval, ret = script_eval(str, str2))
|
||||
|
||||
JSC_CCALL(os_make_body,
|
||||
|
@ -2618,6 +2886,13 @@ JSC_CCALL(os_make_circle2d,
|
|||
return ret;
|
||||
)
|
||||
|
||||
JSC_CCALL(os_make_timer, return timer2js(timer_make()))
|
||||
JSC_CCALL(os_update_timers, timer_update(js2number(argv[0])))
|
||||
|
||||
JSC_CCALL(os_obj_size,
|
||||
|
||||
)
|
||||
|
||||
JSC_CCALL(poly2d_setverts,
|
||||
cpShape *s = js2cpShape(self);
|
||||
HMM_Vec2 *v = js2cpvec2arr(argv[0]);
|
||||
|
@ -2695,6 +2970,13 @@ JSC_SCALL(os_make_texture,
|
|||
JS_SetPropertyStr(js, ret, "path", JS_DupValue(js,argv[0]));
|
||||
)
|
||||
|
||||
JSC_SCALL(os_texture_swap,
|
||||
texture *old = js2texture(argv[1]);
|
||||
texture *tex = texture_from_file(str);
|
||||
JS_SetOpaque(argv[1], tex);
|
||||
texture_free(old);
|
||||
)
|
||||
|
||||
JSC_CCALL(os_make_tex_data,
|
||||
ret = texture2js(texture_empty(js2number(argv[0]), js2number(argv[1]), js2number(argv[2])))
|
||||
)
|
||||
|
@ -2709,42 +2991,36 @@ JSC_CCALL(os_make_transform, return transform2js(make_transform()))
|
|||
|
||||
JSC_SCALL(os_system, return number2js(system(str)); )
|
||||
|
||||
#define PRIMCHECK(VAR, JS, VAL) \
|
||||
if (VAR->VAL.id) js_setpropstr(JS, #VAL, sg_buffer2js(&VAR->VAL)); \
|
||||
JSC_SCALL(os_gltf_buffer,
|
||||
int buffer_idx = js2number(argv[1]);
|
||||
int type = js2number(argv[2]);
|
||||
cgltf_options options = {0};
|
||||
cgltf_data *data = NULL;
|
||||
cgltf_result result = cgltf_parse_file(&options, str, &data);
|
||||
result = cgltf_load_buffers(&options, data, str);
|
||||
|
||||
JSValue primitive2js(primitive *p)
|
||||
{
|
||||
JSValue v = JS_NewObject(js);
|
||||
PRIMCHECK(p, v, pos)
|
||||
PRIMCHECK(p,v,norm)
|
||||
PRIMCHECK(p,v,uv)
|
||||
PRIMCHECK(p,v,bone)
|
||||
PRIMCHECK(p,v,weight)
|
||||
PRIMCHECK(p,v,color)
|
||||
PRIMCHECK(p,v,index)
|
||||
js_setpropstr(v, "count", number2js(p->idx_count));
|
||||
sg_buffer *b = malloc(sizeof(*b));
|
||||
*b = accessor2buffer(&data->accessors[buffer_idx], type);
|
||||
cgltf_free(data);
|
||||
|
||||
return v;
|
||||
ret = sg_buffer2js(b);
|
||||
)
|
||||
|
||||
JSC_SCALL(os_gltf_skin,
|
||||
cgltf_options options = {0};
|
||||
cgltf_data *data = NULL;
|
||||
cgltf_parse_file(&options,str,&data);
|
||||
cgltf_load_buffers(&options,data,str);
|
||||
|
||||
if (data->skins_count <= 0) {
|
||||
ret = (JS_UNDEFINED);
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
JSValue material2js(material *m)
|
||||
{
|
||||
JSValue v = JS_NewObject(js);
|
||||
if (m->diffuse)
|
||||
js_setpropstr(v, "diffuse", texture2js(m->diffuse));
|
||||
ret = skin2js(make_gltf_skin(data->skins+0, data));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
JSC_SCALL(os_make_model,
|
||||
model *m = model_make(str);
|
||||
if (arrlen(m->meshes) != 1) return JSUNDEF;
|
||||
mesh *me = m->meshes+0;
|
||||
|
||||
JSValue v = JS_NewObject(js);
|
||||
js_setpropstr(v, "mesh", primitive2js(me->primitives+0));
|
||||
js_setpropstr(v, "material", material2js(me->primitives[0].mat));
|
||||
return v;
|
||||
CLEANUP:
|
||||
cgltf_free(data);
|
||||
)
|
||||
|
||||
JSC_CCALL(os_make_buffer,
|
||||
|
@ -2907,6 +3183,11 @@ JSC_SCALL(os_make_video,
|
|||
js_setpropstr(ret, "texture", texture2js(t));
|
||||
)
|
||||
|
||||
JSC_CCALL(os_skin_calculate,
|
||||
skin *sk = js2skin(argv[0]);
|
||||
skin_calculate(sk);
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_os_funcs[] = {
|
||||
MIST_FUNC_DEF(os, cwd, 0),
|
||||
MIST_FUNC_DEF(os, env, 1),
|
||||
|
@ -2922,9 +3203,9 @@ static const JSCFunctionListEntry js_os_funcs[] = {
|
|||
MIST_FUNC_DEF(os, make_poly2d, 2),
|
||||
MIST_FUNC_DEF(os, make_seg2d, 1),
|
||||
MIST_FUNC_DEF(os, make_texture, 1),
|
||||
MIST_FUNC_DEF(os, texture_swap, 2),
|
||||
MIST_FUNC_DEF(os, make_tex_data, 3),
|
||||
MIST_FUNC_DEF(os, make_font, 2),
|
||||
MIST_FUNC_DEF(os, make_model, 1),
|
||||
MIST_FUNC_DEF(os, make_transform, 0),
|
||||
MIST_FUNC_DEF(os, make_buffer, 1),
|
||||
MIST_FUNC_DEF(os, make_line_prim, 4),
|
||||
|
@ -2938,6 +3219,24 @@ static const JSCFunctionListEntry js_os_funcs[] = {
|
|||
MIST_FUNC_DEF(os, make_hemisphere, 2),
|
||||
MIST_FUNC_DEF(os, make_plane, 2),
|
||||
MIST_FUNC_DEF(os, make_video, 1),
|
||||
MIST_FUNC_DEF(os, make_timer, 0),
|
||||
MIST_FUNC_DEF(os, update_timers, 1),
|
||||
MIST_FUNC_DEF(os, mem, 1),
|
||||
MIST_FUNC_DEF(os, mem_limit, 1),
|
||||
MIST_FUNC_DEF(os, gc_threshold, 1),
|
||||
MIST_FUNC_DEF(os, max_stacksize, 1),
|
||||
MIST_FUNC_DEF(os, dump_value, 1),
|
||||
MIST_FUNC_DEF(os, dump_mem, 0),
|
||||
MIST_FUNC_DEF(os, dump_shapes, 0),
|
||||
MIST_FUNC_DEF(os, dump_atoms,0),
|
||||
MIST_FUNC_DEF(os, calc_mem, 1),
|
||||
MIST_FUNC_DEF(os, check_gc, 0),
|
||||
MIST_FUNC_DEF(os, check_cycles, 0),
|
||||
MIST_FUNC_DEF(os, memstate, 0),
|
||||
MIST_FUNC_DEF(os, value_id, 1),
|
||||
MIST_FUNC_DEF(os, gltf_buffer, 3),
|
||||
MIST_FUNC_DEF(os, gltf_skin, 1),
|
||||
MIST_FUNC_DEF(os, skin_calculate, 1),
|
||||
};
|
||||
|
||||
#include "steam.h"
|
||||
|
@ -2948,7 +3247,9 @@ JS_SetPropertyFunctionList(js, js_##NAME, js_##NAME##_funcs, countof(js_##NAME##
|
|||
JS_SetPrototype(js, js_##NAME, PARENT); \
|
||||
|
||||
void ffi_load() {
|
||||
JSUNDEF = JS_UNDEFINED;
|
||||
cycles = tmpfile();
|
||||
quickjs_set_cycleout(cycles);
|
||||
|
||||
globalThis = JS_GetGlobalObject(js);
|
||||
|
||||
QJSCLASSPREP(ptr);
|
||||
|
@ -2990,6 +3291,7 @@ void ffi_load() {
|
|||
|
||||
JS_SetPropertyStr(js, prosperon, "version", str2js(VER));
|
||||
JS_SetPropertyStr(js, prosperon, "revision", str2js(COM));
|
||||
JS_SetPropertyStr(js, prosperon, "date", str2js(DATE));
|
||||
JS_SetPropertyStr(js, globalThis, "window", window2js(&mainwin));
|
||||
JS_SetPropertyStr(js, globalThis, "texture", JS_DupValue(js,texture_proto));
|
||||
|
||||
|
@ -3021,7 +3323,7 @@ void ffi_load() {
|
|||
|
||||
JSValue array_proto = js_getpropstr(globalThis, "Array");
|
||||
array_proto = js_getpropstr(array_proto, "prototype");
|
||||
JS_SetPropertyFunctionList(js, array_proto, js_array_funcs, 4);
|
||||
JS_SetPropertyFunctionList(js, array_proto, js_array_funcs, countof(js_array_funcs));
|
||||
|
||||
JS_FreeValue(js,globalThis);
|
||||
}
|
||||
|
|
|
@ -10,17 +10,22 @@ extern "C" {
|
|||
#include <stdarg.h>
|
||||
#include <chipmunk/chipmunk.h>
|
||||
|
||||
void script_report_gc_time(double t, double startmem, double mem);
|
||||
|
||||
int JS_Is(JSValue v);
|
||||
|
||||
extern JSValue cpShape2js(cpShape *s);
|
||||
|
||||
#define MIST_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } }
|
||||
#define MIST_CFUNC_DEF(name, length, func1, props) { name, props, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } }
|
||||
|
||||
#define MIST_FUNC_DEF(TYPE, FN, LEN) MIST_CFUNC_DEF(#FN, LEN, js_##TYPE##_##FN)
|
||||
#define MIST_FUNC_DEF(TYPE, FN, LEN) MIST_CFUNC_DEF(#FN, LEN, js_##TYPE##_##FN, JS_PROP_C_W_E)
|
||||
#define PROTO_FUNC_DEF(TYPE, FN, LEN) MIST_CFUNC_DEF(#FN, LEN, js_##TYPE##_##FN, 0)
|
||||
|
||||
#define JS_SETSIG JSContext *js, JSValue self, JSValue val
|
||||
|
||||
#define JSC_SCALL(NAME, FN) JSC_CCALL(NAME, \
|
||||
const char *str = js2str(argv[0]); \
|
||||
FN ; \
|
||||
{FN;} ; \
|
||||
JS_FreeCString(js,str); \
|
||||
) \
|
||||
|
||||
|
@ -92,7 +97,6 @@ JSValue js_##ID##_get_##ENTRY (JSContext *js, JSValue self) { \
|
|||
static JSClassID js_##TYPE##_id;\
|
||||
static void js_##TYPE##_finalizer(JSRuntime *rt, JSValue val){\
|
||||
TYPE *n = JS_GetOpaque(val, js_##TYPE##_id);\
|
||||
YughSpam("Freeing " #TYPE " at %p", n); \
|
||||
TYPE##_free(n);}\
|
||||
static JSClassDef js_##TYPE##_class = {\
|
||||
#TYPE,\
|
||||
|
@ -105,11 +109,11 @@ TYPE *js2##TYPE (JSValue val) { \
|
|||
}\
|
||||
JSValue TYPE##2js(TYPE *n) { \
|
||||
JSValue j = JS_NewObjectClass(js,js_##TYPE##_id);\
|
||||
YughSpam("Created " #TYPE " at %p", n); \
|
||||
JS_SetOpaque(j,n);\
|
||||
return j; }\
|
||||
\
|
||||
static JSValue js_##TYPE##_memid (JSContext *js, JSValue self) { return str2js("%p", js2##TYPE(self)); } \
|
||||
static JSValue js_##TYPE##_memsize (JSContext *js, JSValue self) { return number2js(sizeof(TYPE)); } \
|
||||
|
||||
#define QJSGLOBALCLASS(NAME) \
|
||||
JSValue NAME = JS_NewObject(js); \
|
||||
|
@ -126,6 +130,7 @@ QJSCLASSPREP(TYPE); \
|
|||
JSValue TYPE##_proto = JS_NewObject(js); \
|
||||
JS_SetPropertyFunctionList(js, TYPE##_proto, js_##TYPE##_funcs, countof(js_##TYPE##_funcs)); \
|
||||
JS_SetPropertyStr(js, TYPE##_proto, "memid", JS_NewCFunction(js, &js_##TYPE##_memid, "memid", 0)); \
|
||||
JS_SetPropertyStr(js, TYPE##_proto, "memsize", JS_NewCFunction(js, &js_##TYPE##_memsize, "memsize", 0)); \
|
||||
JS_SetClassProto(js, js_##TYPE##_id, TYPE##_proto); \
|
||||
|
||||
#define countof(x) (sizeof(x)/sizeof((x)[0]))
|
||||
|
@ -150,17 +155,27 @@ uint64_t js2uint64(JSValue v);
|
|||
|
||||
JSValue str2js(const char *c, ...);
|
||||
|
||||
struct texture;
|
||||
struct texture *js2texture(JSValue v);
|
||||
|
||||
void nota_int(char *blob);
|
||||
|
||||
void js_setprop_num(JSValue a, uint32_t n, JSValue v);
|
||||
JSValue js_getpropidx(JSValue v, uint32_t i);
|
||||
JSValue js_getpropstr(JSValue v, const char *str);
|
||||
void jsfreestr(const char *str);
|
||||
int js_arrlen(JSValue v);
|
||||
void js_setpropstr(JSValue v, const char *str, JSValue p);
|
||||
void js2floatarr(JSValue v, int n, float *a);
|
||||
JSValue floatarr2js(int n, float *a);
|
||||
|
||||
float *js2newfloatarr(JSValue v);
|
||||
|
||||
int js2boolean(JSValue v);
|
||||
JSValue boolean2js(int b);
|
||||
|
||||
char **js2strarr(JSValue v);
|
||||
|
||||
#define PREP_PARENT(TYPE, PARENT) \
|
||||
TYPE##_proto = JS_NewObject(js); \
|
||||
JS_SetPropertyFunctionList(js, TYPE##_proto, js_##TYPE##_funcs, countof(js_##TYPE##_funcs)); \
|
||||
|
|
|
@ -108,15 +108,19 @@ void mYughLog(int category, int priority, int line, const char *file, const char
|
|||
void log_print(const char *str)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
fprintf(stdout, "%s", str);
|
||||
fprintf(writeout, "%s", str);
|
||||
fflush(stdout);
|
||||
#else
|
||||
printf(str);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
void term_print(const char *str)
|
||||
{
|
||||
fprintf(stdout, "%s", str);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void sg_logging(const char *tag, uint32_t lvl, uint32_t id, const char *msg, uint32_t line, const char *file, void *data) {
|
||||
lvl = LOG_PANIC-lvl;
|
||||
mYughLog(LOG_RENDER, lvl, line, file, "tag: %s, id: %d, msg: %s", tag, id, msg);
|
||||
|
|
|
@ -41,5 +41,6 @@ void mYughLog(int category, int priority, int line, const char *file, const char
|
|||
void sg_logging(const char *tag, uint32_t lvl, uint32_t id, const char *msg, uint32_t line, const char *file, void *data);
|
||||
|
||||
void log_print(const char *str);
|
||||
void term_print(const char *str);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,47 +25,10 @@
|
|||
|
||||
#include "sokol/sokol_gfx.h"
|
||||
|
||||
static void processnode();
|
||||
static void processmesh();
|
||||
static void processtexture();
|
||||
|
||||
static cgltf_data *cdata;
|
||||
static char *cpath;
|
||||
|
||||
cgltf_attribute *get_attr_type(cgltf_primitive *p, cgltf_attribute_type t)
|
||||
{
|
||||
for (int i = 0; i < p->attributes_count; i++) {
|
||||
if (p->attributes[i].type == t)
|
||||
return &p->attributes[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#include "jsffi.h"
|
||||
|
||||
unsigned short pack_short_tex(float c) { return c * USHRT_MAX; }
|
||||
|
||||
|
||||
void mesh_add_material(primitive *prim, cgltf_material *mat)
|
||||
{
|
||||
if (!mat) return;
|
||||
|
||||
prim->mat = calloc(sizeof(*prim->mat), 1);
|
||||
material *pmat = prim->mat;
|
||||
|
||||
if (mat->has_pbr_metallic_roughness && mat->pbr_metallic_roughness.base_color_texture.texture) {
|
||||
cgltf_image *img = mat->pbr_metallic_roughness.base_color_texture.texture->image;
|
||||
if (img->buffer_view) {
|
||||
cgltf_buffer_view *buf = img->buffer_view;
|
||||
pmat->diffuse = texture_fromdata(buf->buffer->data, buf->size);
|
||||
} else {
|
||||
// char *path = makepath(dirname(cpath), img->uri);
|
||||
// pmat->diffuse = texture_from_file(path);
|
||||
// free(path);
|
||||
}
|
||||
} else
|
||||
pmat->diffuse = texture_from_file("icons/moon.gif");
|
||||
}
|
||||
|
||||
sg_buffer texcoord_floats(float *f, int n)
|
||||
{
|
||||
unsigned short packed[n];
|
||||
|
@ -125,6 +88,7 @@ uint32_t pack_int10_n2(float *norm)
|
|||
return ret;
|
||||
}
|
||||
|
||||
// Pack an array of normals into
|
||||
sg_buffer normal_floats(float *f, int n)
|
||||
{
|
||||
return float_buffer(f, n);
|
||||
|
@ -156,179 +120,38 @@ sg_buffer ubyte_buffer(float *f, int v)
|
|||
return sg_make_buffer(&(sg_buffer_desc){.data=SG_RANGE(b)});
|
||||
}
|
||||
|
||||
sg_buffer joint_buf(float *f, int v)
|
||||
sg_buffer accessor2buffer(cgltf_accessor *a, int type)
|
||||
{
|
||||
char joints[v];
|
||||
for (int i = 0; i < (v); i++)
|
||||
joints[i] = f[i];
|
||||
|
||||
return sg_make_buffer(&(sg_buffer_desc){ .data = SG_RANGE(joints)});
|
||||
}
|
||||
|
||||
sg_buffer weight_buf(float *f, int v)
|
||||
{
|
||||
unsigned char weights[v];
|
||||
for (int i = 0; i < (v); i++)
|
||||
weights[i] = f[i]*255;
|
||||
|
||||
return sg_make_buffer(&(sg_buffer_desc){ .data = SG_RANGE(weights)});
|
||||
}
|
||||
|
||||
HMM_Vec3 index_to_vert(uint32_t idx, float *f)
|
||||
{
|
||||
return (HMM_Vec3){f[idx*3], f[idx*3+1], f[idx*3+2]};
|
||||
}
|
||||
|
||||
void primitive_gen_indices(primitive *prim)
|
||||
{
|
||||
if (prim->idx_count != 0) return;
|
||||
|
||||
uint16_t *idxs = malloc(sizeof(*idxs)*prim->idx_count);
|
||||
|
||||
for (int z = 0; z < prim->idx_count; z++)
|
||||
idxs[z] = z;
|
||||
|
||||
prim->index = sg_make_buffer(&(sg_buffer_desc){
|
||||
.data.ptr = idxs,
|
||||
.data.size = sizeof(uint16_t) * prim->idx_count,
|
||||
.type = SG_BUFFERTYPE_INDEXBUFFER});
|
||||
|
||||
free(idxs);
|
||||
}
|
||||
|
||||
struct primitive mesh_add_primitive(cgltf_primitive *prim)
|
||||
{
|
||||
primitive retp = (primitive){0};
|
||||
|
||||
uint16_t *idxs;
|
||||
if (prim->indices) {
|
||||
int n = cgltf_accessor_unpack_floats(prim->indices, NULL, 0);
|
||||
float fidx[n];
|
||||
cgltf_accessor_unpack_floats(prim->indices, fidx, n);
|
||||
idxs = malloc(sizeof(*idxs)*n);
|
||||
for (int i = 0; i < n; i++)
|
||||
idxs[i] = fidx[i];
|
||||
|
||||
retp.index = sg_make_buffer(&(sg_buffer_desc){
|
||||
.data.ptr = idxs,
|
||||
.data.size = sizeof(*idxs) * n,
|
||||
.type = SG_BUFFERTYPE_INDEXBUFFER,
|
||||
.label = "mesh index buffer",
|
||||
});
|
||||
|
||||
retp.idx_count = n;
|
||||
free(idxs);
|
||||
} else {
|
||||
retp.idx_count = cgltf_accessor_unpack_floats(prim->attributes[0].data, NULL, 0);
|
||||
primitive_gen_indices(&retp);
|
||||
}
|
||||
|
||||
printf("adding material\n");
|
||||
mesh_add_material(&retp, prim->material);
|
||||
|
||||
for (int k = 0; k < prim->attributes_count; k++) {
|
||||
cgltf_attribute attribute = prim->attributes[k];
|
||||
|
||||
int n = cgltf_accessor_unpack_floats(attribute.data, NULL, 0); /* floats per vertex x num elements. In other words, total floats pulled */
|
||||
int comp = cgltf_num_components(attribute.data->type);
|
||||
int verts = n/comp;
|
||||
int n = cgltf_accessor_unpack_floats(a, NULL, 0);
|
||||
float vs[n];
|
||||
cgltf_accessor_unpack_floats(attribute.data, vs, n);
|
||||
cgltf_accessor_unpack_floats(a, vs, n);
|
||||
|
||||
switch (attribute.type) {
|
||||
case cgltf_attribute_type_position:
|
||||
retp.pos = sg_make_buffer(&(sg_buffer_desc){
|
||||
switch(type) {
|
||||
case MAT_POS:
|
||||
return sg_make_buffer(&(sg_buffer_desc){
|
||||
.data.ptr = vs,
|
||||
.data.size = sizeof(float) * n,
|
||||
.label = "mesh vert buffer"
|
||||
.data.size = sizeof(float)*n
|
||||
});
|
||||
break;
|
||||
|
||||
case cgltf_attribute_type_normal:
|
||||
retp.norm = normal_floats(vs, n);
|
||||
break;
|
||||
|
||||
case cgltf_attribute_type_tangent:
|
||||
break;
|
||||
|
||||
case cgltf_attribute_type_color:
|
||||
retp.color = ubyten_buffer(vs,n);
|
||||
break;
|
||||
|
||||
case cgltf_attribute_type_weights:
|
||||
retp.weight = ubyten_buffer(vs, n);
|
||||
break;
|
||||
|
||||
case cgltf_attribute_type_joints:
|
||||
retp.bone = ubyte_buffer(vs, n);
|
||||
break;
|
||||
|
||||
case cgltf_attribute_type_texcoord:
|
||||
retp.uv = texcoord_floats(vs, n);
|
||||
break;
|
||||
case cgltf_attribute_type_invalid:
|
||||
YughWarn("Invalid type.");
|
||||
break;
|
||||
|
||||
case cgltf_attribute_type_custom:
|
||||
break;
|
||||
|
||||
case cgltf_attribute_type_max_enum:
|
||||
break;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
if (!retp.bone.id) {
|
||||
char joints[retp.idx_count*4];
|
||||
memset(joints, 0, retp.idx_count*4);
|
||||
retp.bone = sg_make_buffer(&(sg_buffer_desc){ .data = SG_RANGE(joints)});
|
||||
}
|
||||
|
||||
if (!retp.weight.id) {
|
||||
char weights[retp.idx_count*4];
|
||||
memset(weights,0,retp.idx_count*4);
|
||||
retp.weight = sg_make_buffer(&(sg_buffer_desc){ .data = SG_RANGE(weights)});
|
||||
}
|
||||
|
||||
if (!retp.color.id) {
|
||||
char colors[retp.idx_count*4];
|
||||
memset(colors,0,retp.idx_count*4);
|
||||
retp.color = sg_make_buffer(&(sg_buffer_desc) { .data = SG_RANGE(colors) });
|
||||
}
|
||||
|
||||
if (!retp.norm.id) {
|
||||
YughInfo("Making normals.");
|
||||
cgltf_attribute *pa = get_attr_type(prim, cgltf_attribute_type_position);
|
||||
int n = cgltf_accessor_unpack_floats(pa->data, NULL,0);
|
||||
int comp = 3;
|
||||
int verts = n/comp;
|
||||
uint32_t face_norms[verts];
|
||||
float ps[n];
|
||||
cgltf_accessor_unpack_floats(pa->data,ps,n);
|
||||
|
||||
for (int i = 0; i < verts; i+=3) {
|
||||
HMM_Vec3 a = index_to_vert(i,ps);
|
||||
HMM_Vec3 b = index_to_vert(i+1,ps);
|
||||
HMM_Vec3 c = index_to_vert(i+2,ps);
|
||||
HMM_Vec3 norm = HMM_NormV3(HMM_Cross(HMM_SubV3(b,a), HMM_SubV3(c,a)));
|
||||
uint32_t packed_norm = pack_int10_n2(norm.Elements);
|
||||
face_norms[i] = face_norms[i+1] = face_norms[i+2] = packed_norm;
|
||||
}
|
||||
|
||||
retp.norm = sg_make_buffer(&(sg_buffer_desc){
|
||||
.data.ptr = face_norms,
|
||||
.data.size = sizeof(uint32_t) * verts});
|
||||
}
|
||||
|
||||
return retp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void model_add_cgltf_mesh(mesh *m, cgltf_mesh *gltf_mesh)
|
||||
{
|
||||
for (int i = 0; i < gltf_mesh->primitives_count; i++)
|
||||
arrput(m->primitives, mesh_add_primitive(gltf_mesh->primitives+i));
|
||||
return sg_make_buffer(&(sg_buffer_desc) {
|
||||
.data.size = 4,
|
||||
.usage = SG_USAGE_STREAM
|
||||
});
|
||||
}
|
||||
|
||||
void packFloats(float *src, float *dest, int srcLength) {
|
||||
|
@ -341,11 +164,17 @@ void packFloats(float *src, float *dest, int srcLength) {
|
|||
}
|
||||
}
|
||||
|
||||
void model_add_cgltf_anim(model *model, cgltf_animation *anim)
|
||||
static md5joint *node2joint(skin *sk, cgltf_node *n, cgltf_skin *skin)
|
||||
{
|
||||
YughInfo("FOUND ANIM, using %d channels and %d samplers", anim->channels_count, anim->samplers_count);
|
||||
int k = 0;
|
||||
while (skin->joints[k] != n && k < skin->joints_count) k++;
|
||||
return sk->joints+k;
|
||||
}
|
||||
|
||||
struct animation an = (struct animation){0};
|
||||
animation *gltf_anim(cgltf_animation *anim, skin *sk, cgltf_skin *skin)
|
||||
{
|
||||
animation *ret = calloc(sizeof(*ret), 1);
|
||||
animation an = *ret;
|
||||
arrsetlen(an.samplers, anim->samplers_count);
|
||||
|
||||
for (int i = 0; i < anim->samplers_count; i++) {
|
||||
|
@ -378,7 +207,7 @@ void model_add_cgltf_anim(model *model, cgltf_animation *anim)
|
|||
for (int i = 0; i < anim->channels_count; i++) {
|
||||
cgltf_animation_channel ch = anim->channels[i];
|
||||
struct anim_channel ach = (struct anim_channel){0};
|
||||
md5joint *md = model->nodes+(ch.target_node-cdata->nodes);
|
||||
md5joint *md = node2joint(sk, ch.target_node, skin);
|
||||
switch(ch.target_path) {
|
||||
case cgltf_animation_path_type_translation:
|
||||
ach.target = &md->pos;
|
||||
|
@ -396,31 +225,34 @@ void model_add_cgltf_anim(model *model, cgltf_animation *anim)
|
|||
arrput(an.channels, ach);
|
||||
}
|
||||
|
||||
model->anim = an;
|
||||
model->anim.time = apptime();
|
||||
an.time = 0;
|
||||
|
||||
*ret = an;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void model_add_cgltf_skin(model *model, cgltf_skin *skin)
|
||||
skin *make_gltf_skin(cgltf_skin *skin, cgltf_data *data)
|
||||
{
|
||||
int n = cgltf_accessor_unpack_floats(skin->inverse_bind_matrices, NULL, 0);
|
||||
struct skin sk = (struct skin){0};
|
||||
arrsetlen(sk.invbind, n/16);
|
||||
cgltf_accessor_unpack_floats(skin->inverse_bind_matrices, sk.invbind, n);
|
||||
YughInfo("FOUND SKIN, of %d bones, and %d vert comps", skin->joints_count, n);
|
||||
struct skin *sk = NULL;
|
||||
sk = calloc(sizeof(*sk),1);
|
||||
arrsetlen(sk->invbind, n/16);
|
||||
cgltf_accessor_unpack_floats(skin->inverse_bind_matrices, sk->invbind, n);
|
||||
|
||||
cgltf_node *root = skin->skeleton;
|
||||
|
||||
arrsetlen(sk.joints, skin->joints_count);
|
||||
sk.root = model->nodes+(skin->skeleton-cdata->nodes);
|
||||
arrsetlen(sk->joints, skin->joints_count);
|
||||
|
||||
for (int i = 0; i < 50; i++)
|
||||
sk.binds[i] = MAT1;
|
||||
sk->binds[i] = MAT1;
|
||||
|
||||
for (int i = 0; i < skin->joints_count; i++) {
|
||||
int offset = skin->joints[i]-cdata->nodes;
|
||||
sk.joints[i] = model->nodes+offset;
|
||||
md5joint *j = sk.joints[i];
|
||||
cgltf_node *n = skin->joints[i];
|
||||
md5joint *j = sk->joints+i;
|
||||
|
||||
if (n == skin->skeleton)
|
||||
j->parent = NULL;
|
||||
else
|
||||
j->parent = node2joint(sk, n->parent, skin);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
j->pos.e[i] = n->translation[i];
|
||||
j->scale.e[i] = n->scale[i];
|
||||
|
@ -429,196 +261,20 @@ void model_add_cgltf_skin(model *model, cgltf_skin *skin)
|
|||
j->rot.e[i] = n->rotation[i];
|
||||
}
|
||||
|
||||
model->skin = sk;
|
||||
sk->anim = gltf_anim(data->animations+0, sk, skin);
|
||||
|
||||
return sk;
|
||||
}
|
||||
|
||||
void model_process_node(model *model, cgltf_node *node)
|
||||
void skin_calculate(skin *sk)
|
||||
{
|
||||
int n = node-cdata->nodes;
|
||||
cgltf_node_transform_world(node, model->nodes[n].t.e);
|
||||
model->nodes[n].parent = model->nodes+(node->parent-cdata->nodes);
|
||||
|
||||
if (node->mesh) {
|
||||
int meshn = node->mesh-cdata->meshes;
|
||||
arrsetlen(model->meshes, meshn+1);
|
||||
model->meshes[meshn].m = &model->nodes[n].t;
|
||||
model_add_cgltf_mesh(model->meshes+meshn, node->mesh);
|
||||
}
|
||||
}
|
||||
|
||||
struct model *model_make(const char *path)
|
||||
{
|
||||
YughInfo("Making the model from %s.", path);
|
||||
cpath = path;
|
||||
cgltf_options options = {0};
|
||||
cgltf_data *data = NULL;
|
||||
cgltf_result result = cgltf_parse_file(&options, path, &data);
|
||||
struct model *model = NULL;
|
||||
|
||||
if (result) {
|
||||
YughError("CGLTF could not parse file %s, err %d.", path, result);
|
||||
goto CLEAN;
|
||||
}
|
||||
|
||||
result = cgltf_load_buffers(&options, data, path);
|
||||
|
||||
if (result) {
|
||||
YughError("CGLTF could not load buffers for file %s, err %d.", path, result);
|
||||
goto CLEAN;
|
||||
}
|
||||
|
||||
cdata = data;
|
||||
|
||||
model = calloc(1, sizeof(*model));
|
||||
|
||||
arrsetlen(model->nodes, data->nodes_count);
|
||||
for (int i = 0; i < data->nodes_count; i++)
|
||||
model_process_node(model, data->nodes+i);
|
||||
|
||||
for (int i = 0; i < data->animations_count; i++)
|
||||
model_add_cgltf_anim(model, data->animations+i);
|
||||
|
||||
for (int i = 0; i < data->skins_count; i++)
|
||||
model_add_cgltf_skin(model, data->skins+i);
|
||||
|
||||
CLEAN:
|
||||
cgltf_free(data);
|
||||
return model;
|
||||
}
|
||||
|
||||
void model_free(model *m)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
sg_bindings primitive_bind(primitive *p)
|
||||
{
|
||||
sg_bindings b = {0};
|
||||
b.vertex_buffers[MAT_POS] = p->pos;
|
||||
b.vertex_buffers[MAT_UV] = p->uv;
|
||||
b.vertex_buffers[MAT_NORM] = p->norm;
|
||||
b.vertex_buffers[MAT_BONE] = p->bone;
|
||||
b.vertex_buffers[MAT_WEIGHT] = p->weight;
|
||||
b.vertex_buffers[MAT_COLOR] = p->color;
|
||||
b.index_buffer = p->index;
|
||||
b.fs.images[0] = p->mat->diffuse->id;
|
||||
b.fs.samplers[0] = tex_sampler;
|
||||
return b;
|
||||
}
|
||||
|
||||
void model_draw_go(model *model, transform *go)
|
||||
{
|
||||
HMM_Mat4 gom = transform2mat(go);
|
||||
|
||||
animation_run(&model->anim, apptime());
|
||||
|
||||
skin *sk = &model->skin;
|
||||
animation_run(sk->anim, apptime());
|
||||
for (int i = 0; i < arrlen(sk->joints); i++) {
|
||||
md5joint *md = sk->joints[i];
|
||||
HMM_Mat4 local = HMM_M4TRS(md->pos.xyz, md->rot, md->scale.xyz);
|
||||
md5joint *md = sk->joints+i;
|
||||
md->t = HMM_M4TRS(md->pos.xyz, md->rot, md->scale.xyz);
|
||||
if (md->parent)
|
||||
local = HMM_MulM4(md->parent->t, local);
|
||||
md->t = local;
|
||||
md->t = HMM_MulM4(md->parent->t, md->t);
|
||||
|
||||
sk->binds[i] = HMM_MulM4(md->t, sk->invbind[i]);
|
||||
}
|
||||
/*sg_apply_uniforms(SG_SHADERSTAGE_VS, SLOT_skinv, &(sg_range){
|
||||
.ptr = sk->binds,
|
||||
.size = sizeof(*sk->binds)*50
|
||||
});
|
||||
*/
|
||||
|
||||
for (int i = 0; i < arrlen(model->meshes); i++) {
|
||||
HMM_Mat4 mod = *model->meshes[i].m;
|
||||
mod = HMM_MulM4(mod, gom);
|
||||
mesh msh = model->meshes[i];
|
||||
for (int j = 0; j < arrlen(msh.primitives); j++) {
|
||||
sg_bindings b = primitive_bind(msh.primitives+j);
|
||||
sg_apply_bindings(&b);
|
||||
sg_draw(0, msh.primitives[j].idx_count, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int mat2type(int mat)
|
||||
{
|
||||
switch(mat) {
|
||||
case MAT_POS:
|
||||
case MAT_NORM:
|
||||
return SG_VERTEXFORMAT_FLOAT3;
|
||||
case MAT_PPOS:
|
||||
case MAT_WH:
|
||||
case MAT_ST:
|
||||
return SG_VERTEXFORMAT_FLOAT2;
|
||||
case MAT_UV:
|
||||
case MAT_TAN:
|
||||
return SG_VERTEXFORMAT_USHORT2N;
|
||||
return SG_VERTEXFORMAT_UINT10_N2;
|
||||
case MAT_BONE:
|
||||
return SG_VERTEXFORMAT_UBYTE4;
|
||||
case MAT_WEIGHT:
|
||||
case MAT_COLOR:
|
||||
return SG_VERTEXFORMAT_UBYTE4N;
|
||||
case MAT_ANGLE:
|
||||
case MAT_SCALE:
|
||||
return SG_VERTEXFORMAT_FLOAT;
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mat2step(int mat)
|
||||
{
|
||||
switch(mat) {
|
||||
case MAT_POS:
|
||||
case MAT_UV:
|
||||
case MAT_TAN:
|
||||
case MAT_NORM:
|
||||
case MAT_BONE:
|
||||
case MAT_WEIGHT:
|
||||
return SG_VERTEXSTEP_PER_VERTEX;
|
||||
};
|
||||
return SG_VERTEXSTEP_PER_INSTANCE;
|
||||
}
|
||||
|
||||
sg_buffer mat2buffer(int mat, primitive *p)
|
||||
{
|
||||
switch(mat) {
|
||||
case MAT_POS: return p->pos;
|
||||
case MAT_NORM: return p->norm;
|
||||
case MAT_UV: return p->uv;
|
||||
case MAT_BONE: return p->bone;
|
||||
case MAT_WEIGHT: return p->weight;
|
||||
case MAT_COLOR: return p->color;
|
||||
};
|
||||
|
||||
return p->pos;
|
||||
}
|
||||
|
||||
sg_bindings primitive_bindings(primitive *p, JSValue v)
|
||||
{
|
||||
sg_bindings b = {0};
|
||||
JSValue inputs = js_getpropstr(js_getpropstr(v, "vs"), "inputs");
|
||||
for (int i = 0; i < js_arrlen(inputs); i++) {
|
||||
JSValue attr = js_getpropidx(inputs, i);
|
||||
int mat = js2number(js_getpropstr(attr, "mat"));
|
||||
int slot = js2number(js_getpropstr(attr, "slot"));
|
||||
sg_buffer buf = mat2buffer(mat,p);
|
||||
if (!buf.id) {
|
||||
// ERROR
|
||||
}
|
||||
b.vertex_buffers[slot] = buf;
|
||||
}
|
||||
|
||||
b.index_buffer = p->index;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
void primitive_free(primitive *prim)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void material_free(material *mat)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "gameobject.h"
|
||||
#include "anim.h"
|
||||
#include "texture.h"
|
||||
#include "cgltf.h"
|
||||
|
||||
#define MAT_POS 0
|
||||
#define MAT_UV 1
|
||||
|
@ -20,44 +21,7 @@
|
|||
#define MAT_ST 9
|
||||
#define MAT_PPOS 10
|
||||
#define MAT_SCALE 11
|
||||
|
||||
typedef struct material {
|
||||
struct texture *diffuse;
|
||||
struct texture *metalrough;
|
||||
float metal;
|
||||
float rough;
|
||||
struct texture *normal;
|
||||
float nrm;
|
||||
struct texture *occlusion;
|
||||
float occl;
|
||||
struct texture *emissive;
|
||||
HMM_Vec3 emis;
|
||||
} material;
|
||||
|
||||
struct model;
|
||||
|
||||
typedef struct primitive {
|
||||
sg_buffer pos;
|
||||
sg_buffer norm;
|
||||
sg_buffer uv;
|
||||
sg_buffer bone;
|
||||
sg_buffer weight;
|
||||
sg_buffer color;
|
||||
sg_buffer index;
|
||||
material *mat;
|
||||
uint32_t idx_count;
|
||||
} primitive;
|
||||
|
||||
/* A single mesh */
|
||||
typedef struct mesh {
|
||||
primitive *primitives;
|
||||
HMM_Mat4 *m;
|
||||
} mesh;
|
||||
|
||||
typedef struct joint {
|
||||
int me;
|
||||
struct joint *children;
|
||||
} joint_t;
|
||||
#define MAT_INDEX 100
|
||||
|
||||
typedef struct md5joint {
|
||||
struct md5joint *parent;
|
||||
|
@ -68,29 +32,15 @@ typedef struct md5joint {
|
|||
} md5joint;
|
||||
|
||||
typedef struct skin {
|
||||
md5joint **joints;
|
||||
md5joint *joints;
|
||||
HMM_Mat4 *invbind;
|
||||
HMM_Mat4 binds[50]; /* binds = joint * invbind */
|
||||
md5joint *root;
|
||||
animation *anim;
|
||||
} skin;
|
||||
|
||||
/* A collection of meshes which create a full figure */
|
||||
typedef struct model {
|
||||
struct mesh *meshes;
|
||||
md5joint *nodes;
|
||||
material *mats;
|
||||
skin skin;
|
||||
struct animation anim;
|
||||
} model;
|
||||
|
||||
/* Make a Model struct */
|
||||
struct model *model_make(const char *path);
|
||||
void model_free(model *m);
|
||||
|
||||
void model_draw_go(model *m, transform *go);
|
||||
sg_bindings primitive_bindings(primitive *p, JSValue pipe);
|
||||
void primitive_gen_indices(primitive *prim);
|
||||
int mat2type(int mat);
|
||||
sg_buffer accessor2buffer(cgltf_accessor *a, int type);
|
||||
skin *make_gltf_skin(cgltf_skin *skin, cgltf_data *data);
|
||||
void skin_calculate(skin *sk);
|
||||
|
||||
sg_buffer float_buffer(float *f, int v);
|
||||
sg_buffer index_buffer(float *f, int verts);
|
||||
|
@ -101,9 +51,5 @@ sg_buffer ubyten_buffer(float *f, int v);
|
|||
sg_buffer ubyte_buffer(float *f, int v);
|
||||
sg_buffer joint_buf(float *f, int v);
|
||||
sg_buffer weight_buf(float *f, int v);
|
||||
void primitive_free(primitive *prim);
|
||||
|
||||
material *material_make();
|
||||
void material_free(material *mat);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -57,35 +57,29 @@ void trace_begin_pass(sg_pass pass, const sg_pass_action *action, void *data)
|
|||
void trace_alloc_##NAME (sg_##NAME id, void *data) \
|
||||
{ \
|
||||
sg_##NAME##_desc desc = sg_query_##NAME##_desc(id); \
|
||||
YughSpam("Alloc " #NAME " %d [%s]", id, desc.label); \
|
||||
} \
|
||||
\
|
||||
void trace_dealloc_##NAME(sg_##NAME id, void *data) \
|
||||
{ \
|
||||
sg_##NAME##_desc desc = sg_query_##NAME##_desc(id); \
|
||||
YughSpam("Dealloc " #NAME " %d [%s]", id, desc.label); \
|
||||
} \
|
||||
\
|
||||
void trace_make_##NAME(sg_##NAME##_desc *desc, void *data) \
|
||||
{ \
|
||||
YughSpam("Make " #NAME " [%s]", desc->label); \
|
||||
} \
|
||||
\
|
||||
void trace_destroy_##NAME(sg_##NAME id, void *data) \
|
||||
{ \
|
||||
sg_##NAME##_desc desc = sg_query_##NAME##_desc(id); \
|
||||
YughSpam("Destroy " #NAME " %d [%s]", id, desc.label); \
|
||||
} \
|
||||
\
|
||||
void trace_init_##NAME(sg_##NAME id, sg_##NAME##_desc *desc, void *data) \
|
||||
{ \
|
||||
YughSpam("Init " #NAME " %d [%s]", id, desc->label); \
|
||||
} \
|
||||
\
|
||||
void trace_uninit_##NAME(sg_##NAME id, void *data) \
|
||||
{ \
|
||||
sg_##NAME##_desc desc = sg_query_##NAME##_desc(id); \
|
||||
YughSpam("Init " #NAME " %d [%s]", id, desc.label); \
|
||||
} \
|
||||
\
|
||||
void trace_fail_##NAME(sg_##NAME id, void *data) \
|
||||
|
@ -132,7 +126,8 @@ void render_init() {
|
|||
sg_setup(&(sg_desc){
|
||||
.environment = sglue_environment(),
|
||||
.logger = { .func = sg_logging },
|
||||
.buffer_pool_size = 1024
|
||||
.buffer_pool_size = 1024,
|
||||
.image_pool_size = 1024,
|
||||
});
|
||||
|
||||
std_sampler = sg_make_sampler(&(sg_sampler_desc){});
|
||||
|
|
|
@ -159,7 +159,9 @@ time_t file_mod_secs(const char *file) {
|
|||
mz_uint index;
|
||||
mz_zip_archive_file_stat pstat;
|
||||
|
||||
if ((index = mz_zip_reader_locate_file(&game_cdb, file, NULL, 0)) != -1) {
|
||||
if (!stat(file,&attr))
|
||||
return attr.st_mtime;
|
||||
else if ((index = mz_zip_reader_locate_file(&game_cdb, file, NULL, 0)) != -1) {
|
||||
mz_zip_reader_file_stat(&game_cdb, index,&pstat);
|
||||
return pstat.m_time;
|
||||
}
|
||||
|
@ -167,10 +169,8 @@ time_t file_mod_secs(const char *file) {
|
|||
mz_zip_reader_file_stat(&corecdb, index, &pstat);
|
||||
return pstat.m_time;
|
||||
}
|
||||
else
|
||||
stat(file, &attr);
|
||||
|
||||
return attr.st_mtime;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO: Not reentrant
|
||||
|
|
|
@ -16,6 +16,8 @@ JSRuntime *rt = NULL;
|
|||
#define JS_EVAL_FLAGS JS_EVAL_FLAG_STRICT | JS_EVAL_FLAG_STRIP
|
||||
#endif
|
||||
|
||||
static JSValue report_gc;
|
||||
|
||||
void script_startup() {
|
||||
rt = JS_NewRuntime();
|
||||
js = JS_NewContext(rt);
|
||||
|
@ -44,6 +46,9 @@ return;
|
|||
}
|
||||
|
||||
void script_gc() { JS_RunGC(rt); }
|
||||
void script_mem_limit(size_t limit) { JS_SetMemoryLimit(rt, limit); }
|
||||
void script_gc_threshold(size_t threshold) { JS_SetGCThreshold(rt, threshold); }
|
||||
void script_max_stacksize(size_t size) { JS_SetMaxStackSize(rt, size); }
|
||||
|
||||
void js_stacktrace() {
|
||||
if (!js) return;
|
||||
|
@ -52,6 +57,7 @@ void js_stacktrace() {
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
void script_evalf(const char *format, ...)
|
||||
{
|
||||
JSValue obj;
|
||||
|
|
|
@ -30,6 +30,14 @@ JSValue script_eval(const char *file, const char *script);
|
|||
void script_call_sym(JSValue sym, int argc, JSValue *argv);
|
||||
|
||||
void script_gc();
|
||||
void script_mem_limit(size_t limit);
|
||||
void script_gc_threshold(size_t threshold);
|
||||
void script_max_stacksize(size_t size);
|
||||
|
||||
void _script_gcstart();
|
||||
void _script_gcend();
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -117,6 +117,8 @@ struct texture *texture_from_file(const char *path) {
|
|||
return NULL;
|
||||
|
||||
tex->data = data;
|
||||
tex->size = tex->width*tex->height*4;
|
||||
tex->gpusize = tex->size;
|
||||
|
||||
unsigned int nw = next_pow2(tex->width);
|
||||
unsigned int nh = next_pow2(tex->height);
|
||||
|
@ -142,6 +144,7 @@ struct texture *texture_from_file(const char *path) {
|
|||
mipdata[i] = malloc(w * h * 4);
|
||||
stbir_resize_uint8_linear(mipdata[i-1], mipw, miph, 0, mipdata[i], w, h, 0, 4);
|
||||
sg_img_data.subimage[0][i] = (sg_range){ .ptr = mipdata[i], .size = w*h*4 };
|
||||
tex->gpusize += w*h*4;
|
||||
|
||||
mipw = w;
|
||||
miph = h;
|
||||
|
@ -159,6 +162,8 @@ struct texture *texture_from_file(const char *path) {
|
|||
for (int i = 1; i < mips; i++)
|
||||
free(mipdata[i]);
|
||||
|
||||
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
|
@ -292,16 +297,21 @@ void texture_save(texture *tex, const char *file)
|
|||
stbi_write_jpg(file, tex->width, tex->height, 4, tex->data, 5);
|
||||
}
|
||||
|
||||
// all coordinates start at bottom left
|
||||
// src and dest, width, height are pixel buffers and their widths and heights
|
||||
// sx the x coordinate of the destination to copy to
|
||||
// sy the y coordinate of the destination to copy to
|
||||
// sw the width of the destination to take in pixels
|
||||
// sh the height of the destination to take in pixels
|
||||
void blit_image(uint8_t* src, uint8_t* dest, int src_width, int src_height, int dest_width, int dest_height, int sx, int sy, int sw, int sh) {
|
||||
if (sx + sw > dest_width) return;
|
||||
if (sy + sh > dest_height) return;
|
||||
int src_stride = src_width * 4;
|
||||
int dest_stride = dest_width * 4;
|
||||
// if (sx + sw > dest_width) return;
|
||||
// if (sy + sh > dest_height) return;
|
||||
|
||||
for (int y = 0; y < sw; y++) {
|
||||
for (int x = 0; x < sh; x++) {
|
||||
int src_index = (y * src_stride) + (x * 4);
|
||||
int dest_index = ((y + sy) * dest_stride) + ((x + sx) * 4);
|
||||
for (int x = 0; x < sw; x++) {
|
||||
for (int y = 0; y < sh; y++) {
|
||||
int src_index = ((y * src_width) + x ) * 4;
|
||||
int dest_index = ((y + sy) * dest_width) + (x + sx);
|
||||
dest_index *= 4;
|
||||
|
||||
// Calculate the alpha value for the source pixel
|
||||
uint8_t src_alpha = src[src_index + 3];
|
||||
|
@ -326,11 +336,10 @@ void blit_image(uint8_t* src, uint8_t* dest, int src_width, int src_height, int
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Function to draw source image pixels on top of a destination image
|
||||
// x,y are the pixel coordinates in the destination image, w,h are the amount of pixels to take from the src image.
|
||||
void texture_blit(texture *dest, texture *src, int x, int y, int w, int h) {
|
||||
blit_image(src->data, dest->data, src->width, src->height, dest->height, dest->width, x, y, w, h);
|
||||
blit_image(src->data, dest->data, src->width, src->height, dest->width, dest->height, x, y, w, h);
|
||||
}
|
||||
|
||||
void texture_flip(texture *tex, int y)
|
||||
|
|
|
@ -23,6 +23,8 @@ struct texture {
|
|||
int width;
|
||||
int height;
|
||||
unsigned char *data;
|
||||
int size;
|
||||
int gpusize;
|
||||
int frames;
|
||||
int *delays;
|
||||
};
|
||||
|
@ -44,7 +46,7 @@ struct texture *texture_fromdata(void *raw, long size);
|
|||
texture *texture_empty(int width, int height, int n);
|
||||
void texture_blit(texture *dest, texture *src, int x, int y, int w, int h);
|
||||
void texture_flip(texture *tex, int y);
|
||||
void texture_save(texture *tex, const char *file);
|
||||
void texture_save(texture *tex, const char *file); // save the texture data to the given file
|
||||
|
||||
double perlin(double x, double y, double z);
|
||||
|
||||
|
|
1111
source/engine/thirdparty/imgui/GraphEditor.cpp
vendored
Normal file
1111
source/engine/thirdparty/imgui/GraphEditor.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
151
source/engine/thirdparty/imgui/GraphEditor.h
vendored
Normal file
151
source/engine/thirdparty/imgui/GraphEditor.h
vendored
Normal file
|
@ -0,0 +1,151 @@
|
|||
// https://github.com/CedricGuillemet/ImGuizmo
|
||||
// v 1.89 WIP
|
||||
//
|
||||
// The MIT License(MIT)
|
||||
//
|
||||
// Copyright(c) 2021 Cedric Guillemet
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files(the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions :
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
|
||||
namespace GraphEditor {
|
||||
|
||||
typedef size_t NodeIndex;
|
||||
typedef size_t SlotIndex;
|
||||
typedef size_t LinkIndex;
|
||||
typedef size_t TemplateIndex;
|
||||
|
||||
// Force the view to be respositionned and zoom to fit nodes with Show function.
|
||||
// Parameter value will be changed to Fit_None by the function.
|
||||
enum FitOnScreen
|
||||
{
|
||||
Fit_None,
|
||||
Fit_AllNodes,
|
||||
Fit_SelectedNodes
|
||||
};
|
||||
|
||||
// Display options and colors
|
||||
struct Options
|
||||
{
|
||||
ImRect mMinimap{{0.75f, 0.8f, 0.99f, 0.99f}}; // rectangle coordinates of minimap
|
||||
ImU32 mBackgroundColor{ IM_COL32(40, 40, 40, 255) }; // full background color
|
||||
ImU32 mGridColor{ IM_COL32(0, 0, 0, 60) }; // grid lines color
|
||||
ImU32 mGridColor2{ IM_COL32(0, 0, 0, 160) }; // grid lines color every 10th
|
||||
ImU32 mSelectedNodeBorderColor{ IM_COL32(255, 130, 30, 255) }; // node border color when it's selected
|
||||
ImU32 mNodeBorderColor{ IM_COL32(100, 100, 100, 0) }; // node border color when it's not selected
|
||||
ImU32 mQuadSelection{ IM_COL32(255, 32, 32, 64) }; // quad selection inside color
|
||||
ImU32 mQuadSelectionBorder{ IM_COL32(255, 32, 32, 255) }; // quad selection border color
|
||||
ImU32 mDefaultSlotColor{ IM_COL32(128, 128, 128, 255) }; // when no color is provided in node template, use this value
|
||||
ImU32 mFrameFocus{ IM_COL32(64, 128, 255, 255) }; // rectangle border when graph editor has focus
|
||||
float mLineThickness{ 5 }; // links width in pixels when zoom value is 1
|
||||
float mGridSize{ 64.f }; // background grid size in pixels when zoom value is 1
|
||||
float mRounding{ 3.f }; // rounding at node corners
|
||||
float mZoomRatio{ 0.1f }; // factor per mouse wheel delta
|
||||
float mZoomLerpFactor{ 0.25f }; // the smaller, the smoother
|
||||
float mBorderSelectionThickness{ 6.f }; // thickness of selection border around nodes
|
||||
float mBorderThickness{ 6.f }; // thickness of selection border around nodes
|
||||
float mNodeSlotRadius{ 8.f }; // circle radius for inputs and outputs
|
||||
float mNodeSlotHoverFactor{ 1.2f }; // increase size when hovering
|
||||
float mMinZoom{ 0.2f }, mMaxZoom { 1.1f };
|
||||
float mSnap{ 5.f };
|
||||
bool mDisplayLinksAsCurves{ true }; // false is straight and 45deg lines
|
||||
bool mAllowQuadSelection{ true }; // multiple selection using drag and drop
|
||||
bool mRenderGrid{ true }; // grid or nothing
|
||||
bool mDrawIONameOnHover{ true }; // only draw node input/output when hovering
|
||||
};
|
||||
|
||||
// View state: scroll position and zoom factor
|
||||
struct ViewState
|
||||
{
|
||||
ImVec2 mPosition{0.0f, 0.0f}; // scroll position
|
||||
float mFactor{ 1.0f }; // current zoom factor
|
||||
float mFactorTarget{ 1.0f }; // targeted zoom factor interpolated using Options.mZoomLerpFactor
|
||||
};
|
||||
|
||||
struct Template
|
||||
{
|
||||
ImU32 mHeaderColor;
|
||||
ImU32 mBackgroundColor;
|
||||
ImU32 mBackgroundColorOver;
|
||||
ImU8 mInputCount;
|
||||
const char** mInputNames; // can be nullptr. No text displayed.
|
||||
ImU32* mInputColors; // can be nullptr, default slot color will be used.
|
||||
ImU8 mOutputCount;
|
||||
const char** mOutputNames; // can be nullptr. No text displayed.
|
||||
ImU32* mOutputColors; // can be nullptr, default slot color will be used.
|
||||
};
|
||||
|
||||
struct Node
|
||||
{
|
||||
const char* mName;
|
||||
TemplateIndex mTemplateIndex;
|
||||
ImRect mRect;
|
||||
bool mSelected{ false };
|
||||
};
|
||||
|
||||
struct Link
|
||||
{
|
||||
NodeIndex mInputNodeIndex;
|
||||
SlotIndex mInputSlotIndex;
|
||||
NodeIndex mOutputNodeIndex;
|
||||
SlotIndex mOutputSlotIndex;
|
||||
};
|
||||
|
||||
struct Delegate
|
||||
{
|
||||
virtual bool AllowedLink(NodeIndex from, NodeIndex to) = 0;
|
||||
|
||||
virtual void SelectNode(NodeIndex nodeIndex, bool selected) = 0;
|
||||
virtual void MoveSelectedNodes(const ImVec2 delta) = 0;
|
||||
|
||||
virtual void AddLink(NodeIndex inputNodeIndex, SlotIndex inputSlotIndex, NodeIndex outputNodeIndex, SlotIndex outputSlotIndex) = 0;
|
||||
virtual void DelLink(LinkIndex linkIndex) = 0;
|
||||
|
||||
// user is responsible for clipping
|
||||
virtual void CustomDraw(ImDrawList* drawList, ImRect rectangle, NodeIndex nodeIndex) = 0;
|
||||
|
||||
// use mouse position to open context menu
|
||||
// if nodeIndex != -1, right click happens on the specified node
|
||||
virtual void RightClick(NodeIndex nodeIndex, SlotIndex slotIndexInput, SlotIndex slotIndexOutput) = 0;
|
||||
|
||||
virtual const size_t GetTemplateCount() = 0;
|
||||
virtual const Template GetTemplate(TemplateIndex index) = 0;
|
||||
|
||||
virtual const size_t GetNodeCount() = 0;
|
||||
virtual const Node GetNode(NodeIndex index) = 0;
|
||||
|
||||
virtual const size_t GetLinkCount() = 0;
|
||||
virtual const Link GetLink(LinkIndex index) = 0;
|
||||
|
||||
virtual ~Delegate() = default;
|
||||
};
|
||||
|
||||
void Show(Delegate& delegate, const Options& options, ViewState& viewState, bool enabled, FitOnScreen* fit = nullptr);
|
||||
void GraphEditorClear();
|
||||
|
||||
bool EditOptions(Options& options);
|
||||
|
||||
} // namespace
|
457
source/engine/thirdparty/imgui/ImCurveEdit.cpp
vendored
Normal file
457
source/engine/thirdparty/imgui/ImCurveEdit.cpp
vendored
Normal file
|
@ -0,0 +1,457 @@
|
|||
// https://github.com/CedricGuillemet/ImGuizmo
|
||||
// v 1.89 WIP
|
||||
//
|
||||
// The MIT License(MIT)
|
||||
//
|
||||
// Copyright(c) 2021 Cedric Guillemet
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files(the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions :
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
#include "ImCurveEdit.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
#include <stdint.h>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)
|
||||
#define _malloca(x) alloca(x)
|
||||
#define _freea(x)
|
||||
#endif
|
||||
|
||||
namespace ImCurveEdit
|
||||
{
|
||||
|
||||
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
||||
static ImVec2 operator+(const ImVec2& a, const ImVec2& b) {
|
||||
return ImVec2(a.x + b.x, a.y + b.y);
|
||||
}
|
||||
|
||||
static ImVec2 operator-(const ImVec2& a, const ImVec2& b) {
|
||||
return ImVec2(a.x - b.x, a.y - b.y);
|
||||
}
|
||||
|
||||
static ImVec2 operator*(const ImVec2& a, const ImVec2& b) {
|
||||
return ImVec2(a.x * b.x, a.y * b.y);
|
||||
}
|
||||
|
||||
static ImVec2 operator/(const ImVec2& a, const ImVec2& b) {
|
||||
return ImVec2(a.x / b.x, a.y / b.y);
|
||||
}
|
||||
|
||||
static ImVec2 operator*(const ImVec2& a, const float b) {
|
||||
return ImVec2(a.x * b, a.y * b);
|
||||
}
|
||||
#endif
|
||||
|
||||
static float smoothstep(float edge0, float edge1, float x)
|
||||
{
|
||||
x = ImClamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
|
||||
return x * x * (3 - 2 * x);
|
||||
}
|
||||
|
||||
static float distance(float x, float y, float x1, float y1, float x2, float y2)
|
||||
{
|
||||
float A = x - x1;
|
||||
float B = y - y1;
|
||||
float C = x2 - x1;
|
||||
float D = y2 - y1;
|
||||
|
||||
float dot = A * C + B * D;
|
||||
float len_sq = C * C + D * D;
|
||||
float param = -1.f;
|
||||
if (len_sq > FLT_EPSILON)
|
||||
param = dot / len_sq;
|
||||
|
||||
float xx, yy;
|
||||
|
||||
if (param < 0.f) {
|
||||
xx = x1;
|
||||
yy = y1;
|
||||
}
|
||||
else if (param > 1.f) {
|
||||
xx = x2;
|
||||
yy = y2;
|
||||
}
|
||||
else {
|
||||
xx = x1 + param * C;
|
||||
yy = y1 + param * D;
|
||||
}
|
||||
|
||||
float dx = x - xx;
|
||||
float dy = y - yy;
|
||||
return sqrtf(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
static int DrawPoint(ImDrawList* draw_list, ImVec2 pos, const ImVec2 size, const ImVec2 offset, bool edited)
|
||||
{
|
||||
int ret = 0;
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
static const ImVec2 localOffsets[4] = { ImVec2(1,0), ImVec2(0,1), ImVec2(-1,0), ImVec2(0,-1) };
|
||||
ImVec2 offsets[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
offsets[i] = pos * size + localOffsets[i] * 4.5f + offset;
|
||||
}
|
||||
|
||||
const ImVec2 center = pos * size + offset;
|
||||
const ImRect anchor(center - ImVec2(5, 5), center + ImVec2(5, 5));
|
||||
draw_list->AddConvexPolyFilled(offsets, 4, 0xFF000000);
|
||||
if (anchor.Contains(io.MousePos))
|
||||
{
|
||||
ret = 1;
|
||||
if (io.MouseDown[0])
|
||||
ret = 2;
|
||||
}
|
||||
if (edited)
|
||||
draw_list->AddPolyline(offsets, 4, 0xFFFFFFFF, true, 3.0f);
|
||||
else if (ret)
|
||||
draw_list->AddPolyline(offsets, 4, 0xFF80B0FF, true, 2.0f);
|
||||
else
|
||||
draw_list->AddPolyline(offsets, 4, 0xFF0080FF, true, 2.0f);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Edit(Delegate& delegate, const ImVec2& size, unsigned int id, const ImRect* clippingRect, ImVector<EditPoint>* selectedPoints)
|
||||
{
|
||||
static bool selectingQuad = false;
|
||||
static ImVec2 quadSelection;
|
||||
static int overCurve = -1;
|
||||
static int movingCurve = -1;
|
||||
static bool scrollingV = false;
|
||||
static std::set<EditPoint> selection;
|
||||
static bool overSelectedPoint = false;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
|
||||
ImGui::PushStyleColor(ImGuiCol_Border, 0);
|
||||
ImGui::BeginChildFrame(id, size);
|
||||
delegate.focused = ImGui::IsWindowFocused();
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
if (clippingRect)
|
||||
draw_list->PushClipRect(clippingRect->Min, clippingRect->Max, true);
|
||||
|
||||
const ImVec2 offset = ImGui::GetCursorScreenPos() + ImVec2(0.f, size.y);
|
||||
const ImVec2 ssize(size.x, -size.y);
|
||||
const ImRect container(offset + ImVec2(0.f, ssize.y), offset + ImVec2(ssize.x, 0.f));
|
||||
ImVec2& min = delegate.GetMin();
|
||||
ImVec2& max = delegate.GetMax();
|
||||
|
||||
// handle zoom and VScroll
|
||||
if (container.Contains(io.MousePos))
|
||||
{
|
||||
if (fabsf(io.MouseWheel) > FLT_EPSILON)
|
||||
{
|
||||
const float r = (io.MousePos.y - offset.y) / ssize.y;
|
||||
float ratioY = ImLerp(min.y, max.y, r);
|
||||
auto scaleValue = [&](float v) {
|
||||
v -= ratioY;
|
||||
v *= (1.f - io.MouseWheel * 0.05f);
|
||||
v += ratioY;
|
||||
return v;
|
||||
};
|
||||
min.y = scaleValue(min.y);
|
||||
max.y = scaleValue(max.y);
|
||||
}
|
||||
if (!scrollingV && ImGui::IsMouseDown(2))
|
||||
{
|
||||
scrollingV = true;
|
||||
}
|
||||
}
|
||||
ImVec2 range = max - min + ImVec2(1.f, 0.f); // +1 because of inclusive last frame
|
||||
|
||||
const ImVec2 viewSize(size.x, -size.y);
|
||||
const ImVec2 sizeOfPixel = ImVec2(1.f, 1.f) / viewSize;
|
||||
const size_t curveCount = delegate.GetCurveCount();
|
||||
|
||||
if (scrollingV)
|
||||
{
|
||||
float deltaH = io.MouseDelta.y * range.y * sizeOfPixel.y;
|
||||
min.y -= deltaH;
|
||||
max.y -= deltaH;
|
||||
if (!ImGui::IsMouseDown(2))
|
||||
scrollingV = false;
|
||||
}
|
||||
|
||||
draw_list->AddRectFilled(offset, offset + ssize, delegate.GetBackgroundColor());
|
||||
|
||||
auto pointToRange = [&](ImVec2 pt) { return (pt - min) / range; };
|
||||
auto rangeToPoint = [&](ImVec2 pt) { return (pt * range) + min; };
|
||||
|
||||
draw_list->AddLine(ImVec2(-1.f, -min.y / range.y) * viewSize + offset, ImVec2(1.f, -min.y / range.y) * viewSize + offset, 0xFF000000, 1.5f);
|
||||
bool overCurveOrPoint = false;
|
||||
|
||||
int localOverCurve = -1;
|
||||
// make sure highlighted curve is rendered last
|
||||
int* curvesIndex = (int*)_malloca(sizeof(int) * curveCount);
|
||||
for (size_t c = 0; c < curveCount; c++)
|
||||
curvesIndex[c] = int(c);
|
||||
int highLightedCurveIndex = -1;
|
||||
if (overCurve != -1 && curveCount)
|
||||
{
|
||||
ImSwap(curvesIndex[overCurve], curvesIndex[curveCount - 1]);
|
||||
highLightedCurveIndex = overCurve;
|
||||
}
|
||||
|
||||
for (size_t cur = 0; cur < curveCount; cur++)
|
||||
{
|
||||
int c = curvesIndex[cur];
|
||||
if (!delegate.IsVisible(c))
|
||||
continue;
|
||||
const size_t ptCount = delegate.GetPointCount(c);
|
||||
if (ptCount < 1)
|
||||
continue;
|
||||
CurveType curveType = delegate.GetCurveType(c);
|
||||
if (curveType == CurveNone)
|
||||
continue;
|
||||
const ImVec2* pts = delegate.GetPoints(c);
|
||||
uint32_t curveColor = delegate.GetCurveColor(c);
|
||||
if ((c == highLightedCurveIndex && selection.empty() && !selectingQuad) || movingCurve == c)
|
||||
curveColor = 0xFFFFFFFF;
|
||||
|
||||
for (size_t p = 0; p < ptCount - 1; p++)
|
||||
{
|
||||
const ImVec2 p1 = pointToRange(pts[p]);
|
||||
const ImVec2 p2 = pointToRange(pts[p + 1]);
|
||||
|
||||
if (curveType == CurveSmooth || curveType == CurveLinear)
|
||||
{
|
||||
size_t subStepCount = (curveType == CurveSmooth) ? 20 : 2;
|
||||
float step = 1.f / float(subStepCount - 1);
|
||||
for (size_t substep = 0; substep < subStepCount - 1; substep++)
|
||||
{
|
||||
float t = float(substep) * step;
|
||||
|
||||
const ImVec2 sp1 = ImLerp(p1, p2, t);
|
||||
const ImVec2 sp2 = ImLerp(p1, p2, t + step);
|
||||
|
||||
const float rt1 = smoothstep(p1.x, p2.x, sp1.x);
|
||||
const float rt2 = smoothstep(p1.x, p2.x, sp2.x);
|
||||
|
||||
const ImVec2 pos1 = ImVec2(sp1.x, ImLerp(p1.y, p2.y, rt1)) * viewSize + offset;
|
||||
const ImVec2 pos2 = ImVec2(sp2.x, ImLerp(p1.y, p2.y, rt2)) * viewSize + offset;
|
||||
|
||||
if (distance(io.MousePos.x, io.MousePos.y, pos1.x, pos1.y, pos2.x, pos2.y) < 8.f && !scrollingV)
|
||||
{
|
||||
localOverCurve = int(c);
|
||||
overCurve = int(c);
|
||||
overCurveOrPoint = true;
|
||||
}
|
||||
|
||||
draw_list->AddLine(pos1, pos2, curveColor, 1.3f);
|
||||
} // substep
|
||||
}
|
||||
else if (curveType == CurveDiscrete)
|
||||
{
|
||||
ImVec2 dp1 = p1 * viewSize + offset;
|
||||
ImVec2 dp2 = ImVec2(p2.x, p1.y) * viewSize + offset;
|
||||
ImVec2 dp3 = p2 * viewSize + offset;
|
||||
draw_list->AddLine(dp1, dp2, curveColor, 1.3f);
|
||||
draw_list->AddLine(dp2, dp3, curveColor, 1.3f);
|
||||
|
||||
if ((distance(io.MousePos.x, io.MousePos.y, dp1.x, dp1.y, dp3.x, dp1.y) < 8.f ||
|
||||
distance(io.MousePos.x, io.MousePos.y, dp3.x, dp1.y, dp3.x, dp3.y) < 8.f)
|
||||
/*&& localOverCurve == -1*/)
|
||||
{
|
||||
localOverCurve = int(c);
|
||||
overCurve = int(c);
|
||||
overCurveOrPoint = true;
|
||||
}
|
||||
}
|
||||
} // point loop
|
||||
|
||||
for (size_t p = 0; p < ptCount; p++)
|
||||
{
|
||||
const int drawState = DrawPoint(draw_list, pointToRange(pts[p]), viewSize, offset, (selection.find({ int(c), int(p) }) != selection.end() && movingCurve == -1 && !scrollingV));
|
||||
if (drawState && movingCurve == -1 && !selectingQuad)
|
||||
{
|
||||
overCurveOrPoint = true;
|
||||
overSelectedPoint = true;
|
||||
overCurve = -1;
|
||||
if (drawState == 2)
|
||||
{
|
||||
if (!io.KeyShift && selection.find({ int(c), int(p) }) == selection.end())
|
||||
selection.clear();
|
||||
selection.insert({ int(c), int(p) });
|
||||
}
|
||||
}
|
||||
}
|
||||
} // curves loop
|
||||
|
||||
if (localOverCurve == -1)
|
||||
overCurve = -1;
|
||||
|
||||
// move selection
|
||||
static bool pointsMoved = false;
|
||||
static ImVec2 mousePosOrigin;
|
||||
static std::vector<ImVec2> originalPoints;
|
||||
if (overSelectedPoint && io.MouseDown[0])
|
||||
{
|
||||
if ((fabsf(io.MouseDelta.x) > 0.f || fabsf(io.MouseDelta.y) > 0.f) && !selection.empty())
|
||||
{
|
||||
if (!pointsMoved)
|
||||
{
|
||||
delegate.BeginEdit(0);
|
||||
mousePosOrigin = io.MousePos;
|
||||
originalPoints.resize(selection.size());
|
||||
int index = 0;
|
||||
for (auto& sel : selection)
|
||||
{
|
||||
const ImVec2* pts = delegate.GetPoints(sel.curveIndex);
|
||||
originalPoints[index++] = pts[sel.pointIndex];
|
||||
}
|
||||
}
|
||||
pointsMoved = true;
|
||||
ret = 1;
|
||||
auto prevSelection = selection;
|
||||
int originalIndex = 0;
|
||||
for (auto& sel : prevSelection)
|
||||
{
|
||||
const ImVec2 p = rangeToPoint(pointToRange(originalPoints[originalIndex]) + (io.MousePos - mousePosOrigin) * sizeOfPixel);
|
||||
const int newIndex = delegate.EditPoint(sel.curveIndex, sel.pointIndex, p);
|
||||
if (newIndex != sel.pointIndex)
|
||||
{
|
||||
selection.erase(sel);
|
||||
selection.insert({ sel.curveIndex, newIndex });
|
||||
}
|
||||
originalIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (overSelectedPoint && !io.MouseDown[0])
|
||||
{
|
||||
overSelectedPoint = false;
|
||||
if (pointsMoved)
|
||||
{
|
||||
pointsMoved = false;
|
||||
delegate.EndEdit();
|
||||
}
|
||||
}
|
||||
|
||||
// add point
|
||||
if (overCurve != -1 && io.MouseDoubleClicked[0])
|
||||
{
|
||||
const ImVec2 np = rangeToPoint((io.MousePos - offset) / viewSize);
|
||||
delegate.BeginEdit(overCurve);
|
||||
delegate.AddPoint(overCurve, np);
|
||||
delegate.EndEdit();
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
// move curve
|
||||
|
||||
if (movingCurve != -1)
|
||||
{
|
||||
const size_t ptCount = delegate.GetPointCount(movingCurve);
|
||||
const ImVec2* pts = delegate.GetPoints(movingCurve);
|
||||
if (!pointsMoved)
|
||||
{
|
||||
mousePosOrigin = io.MousePos;
|
||||
pointsMoved = true;
|
||||
originalPoints.resize(ptCount);
|
||||
for (size_t index = 0; index < ptCount; index++)
|
||||
{
|
||||
originalPoints[index] = pts[index];
|
||||
}
|
||||
}
|
||||
if (ptCount >= 1)
|
||||
{
|
||||
for (size_t p = 0; p < ptCount; p++)
|
||||
{
|
||||
delegate.EditPoint(movingCurve, int(p), rangeToPoint(pointToRange(originalPoints[p]) + (io.MousePos - mousePosOrigin) * sizeOfPixel));
|
||||
}
|
||||
ret = 1;
|
||||
}
|
||||
if (!io.MouseDown[0])
|
||||
{
|
||||
movingCurve = -1;
|
||||
pointsMoved = false;
|
||||
delegate.EndEdit();
|
||||
}
|
||||
}
|
||||
if (movingCurve == -1 && overCurve != -1 && ImGui::IsMouseClicked(0) && selection.empty() && !selectingQuad)
|
||||
{
|
||||
movingCurve = overCurve;
|
||||
delegate.BeginEdit(overCurve);
|
||||
}
|
||||
|
||||
// quad selection
|
||||
if (selectingQuad)
|
||||
{
|
||||
const ImVec2 bmin = ImMin(quadSelection, io.MousePos);
|
||||
const ImVec2 bmax = ImMax(quadSelection, io.MousePos);
|
||||
draw_list->AddRectFilled(bmin, bmax, 0x40FF0000, 1.f);
|
||||
draw_list->AddRect(bmin, bmax, 0xFFFF0000, 1.f);
|
||||
const ImRect selectionQuad(bmin, bmax);
|
||||
if (!io.MouseDown[0])
|
||||
{
|
||||
if (!io.KeyShift)
|
||||
selection.clear();
|
||||
// select everythnig is quad
|
||||
for (size_t c = 0; c < curveCount; c++)
|
||||
{
|
||||
if (!delegate.IsVisible(c))
|
||||
continue;
|
||||
|
||||
const size_t ptCount = delegate.GetPointCount(c);
|
||||
if (ptCount < 1)
|
||||
continue;
|
||||
|
||||
const ImVec2* pts = delegate.GetPoints(c);
|
||||
for (size_t p = 0; p < ptCount; p++)
|
||||
{
|
||||
const ImVec2 center = pointToRange(pts[p]) * viewSize + offset;
|
||||
if (selectionQuad.Contains(center))
|
||||
selection.insert({ int(c), int(p) });
|
||||
}
|
||||
}
|
||||
// done
|
||||
selectingQuad = false;
|
||||
}
|
||||
}
|
||||
if (!overCurveOrPoint && ImGui::IsMouseClicked(0) && !selectingQuad && movingCurve == -1 && !overSelectedPoint && container.Contains(io.MousePos))
|
||||
{
|
||||
selectingQuad = true;
|
||||
quadSelection = io.MousePos;
|
||||
}
|
||||
if (clippingRect)
|
||||
draw_list->PopClipRect();
|
||||
|
||||
ImGui::EndChildFrame();
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::PopStyleColor(1);
|
||||
|
||||
if (selectedPoints)
|
||||
{
|
||||
selectedPoints->resize(int(selection.size()));
|
||||
int index = 0;
|
||||
for (auto& point : selection)
|
||||
(*selectedPoints)[index++] = point;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
82
source/engine/thirdparty/imgui/ImCurveEdit.h
vendored
Normal file
82
source/engine/thirdparty/imgui/ImCurveEdit.h
vendored
Normal file
|
@ -0,0 +1,82 @@
|
|||
// https://github.com/CedricGuillemet/ImGuizmo
|
||||
// v 1.89 WIP
|
||||
//
|
||||
// The MIT License(MIT)
|
||||
//
|
||||
// Copyright(c) 2021 Cedric Guillemet
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files(the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions :
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "imgui.h"
|
||||
|
||||
struct ImRect;
|
||||
|
||||
namespace ImCurveEdit
|
||||
{
|
||||
enum CurveType
|
||||
{
|
||||
CurveNone,
|
||||
CurveDiscrete,
|
||||
CurveLinear,
|
||||
CurveSmooth,
|
||||
CurveBezier,
|
||||
};
|
||||
|
||||
struct EditPoint
|
||||
{
|
||||
int curveIndex;
|
||||
int pointIndex;
|
||||
bool operator <(const EditPoint& other) const
|
||||
{
|
||||
if (curveIndex < other.curveIndex)
|
||||
return true;
|
||||
if (curveIndex > other.curveIndex)
|
||||
return false;
|
||||
|
||||
if (pointIndex < other.pointIndex)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct Delegate
|
||||
{
|
||||
bool focused = false;
|
||||
virtual size_t GetCurveCount() = 0;
|
||||
virtual bool IsVisible(size_t /*curveIndex*/) { return true; }
|
||||
virtual CurveType GetCurveType(size_t /*curveIndex*/) const { return CurveLinear; }
|
||||
virtual ImVec2& GetMin() = 0;
|
||||
virtual ImVec2& GetMax() = 0;
|
||||
virtual size_t GetPointCount(size_t curveIndex) = 0;
|
||||
virtual uint32_t GetCurveColor(size_t curveIndex) = 0;
|
||||
virtual ImVec2* GetPoints(size_t curveIndex) = 0;
|
||||
virtual int EditPoint(size_t curveIndex, int pointIndex, ImVec2 value) = 0;
|
||||
virtual void AddPoint(size_t curveIndex, ImVec2 value) = 0;
|
||||
virtual unsigned int GetBackgroundColor() { return 0xFF202020; }
|
||||
// handle undo/redo thru this functions
|
||||
virtual void BeginEdit(int /*index*/) {}
|
||||
virtual void EndEdit() {}
|
||||
|
||||
virtual ~Delegate() = default;
|
||||
};
|
||||
|
||||
int Edit(Delegate& delegate, const ImVec2& size, unsigned int id, const ImRect* clippingRect = NULL, ImVector<EditPoint>* selectedPoints = NULL);
|
||||
}
|
116
source/engine/thirdparty/imgui/ImGradient.cpp
vendored
Normal file
116
source/engine/thirdparty/imgui/ImGradient.cpp
vendored
Normal file
|
@ -0,0 +1,116 @@
|
|||
// https://github.com/CedricGuillemet/ImGuizmo
|
||||
// v 1.89 WIP
|
||||
//
|
||||
// The MIT License(MIT)
|
||||
//
|
||||
// Copyright(c) 2021 Cedric Guillemet
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files(the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions :
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
#include "ImGradient.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
|
||||
namespace ImGradient
|
||||
{
|
||||
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
||||
static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); }
|
||||
static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); }
|
||||
static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); }
|
||||
static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); }
|
||||
static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
|
||||
static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); }
|
||||
#endif
|
||||
|
||||
static int DrawPoint(ImDrawList* draw_list, ImVec4 color, const ImVec2 size, bool editing, ImVec2 pos)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImVec2 p1 = ImLerp(pos, ImVec2(pos + ImVec2(size.x - size.y, 0.f)), color.w) + ImVec2(3, 3);
|
||||
ImVec2 p2 = ImLerp(pos + ImVec2(size.y, size.y), ImVec2(pos + size), color.w) - ImVec2(3, 3);
|
||||
ImRect rc(p1, p2);
|
||||
|
||||
color.w = 1.f;
|
||||
draw_list->AddRectFilled(p1, p2, ImColor(color));
|
||||
if (editing)
|
||||
draw_list->AddRect(p1, p2, 0xFFFFFFFF, 2.f, 15, 2.5f);
|
||||
else
|
||||
draw_list->AddRect(p1, p2, 0x80FFFFFF, 2.f, 15, 1.25f);
|
||||
|
||||
if (rc.Contains(io.MousePos))
|
||||
{
|
||||
if (io.MouseClicked[0])
|
||||
return 2;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Edit(Delegate& delegate, const ImVec2& size, int& selection)
|
||||
{
|
||||
bool ret = false;
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
|
||||
ImGui::BeginChildFrame(137, size);
|
||||
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
const ImVec2 offset = ImGui::GetCursorScreenPos();
|
||||
|
||||
const ImVec4* pts = delegate.GetPoints();
|
||||
static int currentSelection = -1;
|
||||
static int movingPt = -1;
|
||||
if (currentSelection >= int(delegate.GetPointCount()))
|
||||
currentSelection = -1;
|
||||
if (movingPt != -1)
|
||||
{
|
||||
ImVec4 current = pts[movingPt];
|
||||
current.w += io.MouseDelta.x / size.x;
|
||||
current.w = ImClamp(current.w, 0.f, 1.f);
|
||||
delegate.EditPoint(movingPt, current);
|
||||
ret = true;
|
||||
if (!io.MouseDown[0])
|
||||
movingPt = -1;
|
||||
}
|
||||
for (size_t i = 0; i < delegate.GetPointCount(); i++)
|
||||
{
|
||||
int ptSel = DrawPoint(draw_list, pts[i], size, i == currentSelection, offset);
|
||||
if (ptSel == 2)
|
||||
{
|
||||
currentSelection = int(i);
|
||||
ret = true;
|
||||
}
|
||||
if (ptSel == 1 && io.MouseDown[0] && movingPt == -1)
|
||||
{
|
||||
movingPt = int(i);
|
||||
}
|
||||
}
|
||||
ImRect rc(offset, offset + size);
|
||||
if (rc.Contains(io.MousePos) && io.MouseDoubleClicked[0])
|
||||
{
|
||||
float t = (io.MousePos.x - offset.x) / size.x;
|
||||
delegate.AddPoint(delegate.GetPoint(t));
|
||||
ret = true;
|
||||
}
|
||||
ImGui::EndChildFrame();
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
selection = currentSelection;
|
||||
return ret;
|
||||
}
|
||||
}
|
45
source/engine/thirdparty/imgui/ImGradient.h
vendored
Normal file
45
source/engine/thirdparty/imgui/ImGradient.h
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
// https://github.com/CedricGuillemet/ImGuizmo
|
||||
// v 1.89 WIP
|
||||
//
|
||||
// The MIT License(MIT)
|
||||
//
|
||||
// Copyright(c) 2021 Cedric Guillemet
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files(the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions :
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
#pragma once
|
||||
#include <cstddef>
|
||||
|
||||
struct ImVec4;
|
||||
struct ImVec2;
|
||||
|
||||
namespace ImGradient
|
||||
{
|
||||
struct Delegate
|
||||
{
|
||||
virtual size_t GetPointCount() = 0;
|
||||
virtual ImVec4* GetPoints() = 0;
|
||||
virtual int EditPoint(int pointIndex, ImVec4 value) = 0;
|
||||
virtual ImVec4 GetPoint(float t) = 0;
|
||||
virtual void AddPoint(ImVec4 value) = 0;
|
||||
virtual ~Delegate() = default;
|
||||
};
|
||||
|
||||
bool Edit(Delegate& delegate, const ImVec2& size, int& selection);
|
||||
}
|
2996
source/engine/thirdparty/imgui/ImGuizmo.cpp
vendored
Executable file
2996
source/engine/thirdparty/imgui/ImGuizmo.cpp
vendored
Executable file
File diff suppressed because it is too large
Load diff
272
source/engine/thirdparty/imgui/ImGuizmo.h
vendored
Normal file
272
source/engine/thirdparty/imgui/ImGuizmo.h
vendored
Normal file
|
@ -0,0 +1,272 @@
|
|||
// https://github.com/CedricGuillemet/ImGuizmo
|
||||
// v 1.89 WIP
|
||||
//
|
||||
// The MIT License(MIT)
|
||||
//
|
||||
// Copyright(c) 2021 Cedric Guillemet
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files(the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions :
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// History :
|
||||
// 2019/11/03 View gizmo
|
||||
// 2016/09/11 Behind camera culling. Scaling Delta matrix not multiplied by source matrix scales. local/world rotation and translation fixed. Display message is incorrect (X: ... Y:...) in local mode.
|
||||
// 2016/09/09 Hatched negative axis. Snapping. Documentation update.
|
||||
// 2016/09/04 Axis switch and translation plan autohiding. Scale transform stability improved
|
||||
// 2016/09/01 Mogwai changed to Manipulate. Draw debug cube. Fixed inverted scale. Mixing scale and translation/rotation gives bad results.
|
||||
// 2016/08/31 First version
|
||||
//
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// Future (no order):
|
||||
//
|
||||
// - Multi view
|
||||
// - display rotation/translation/scale infos in local/world space and not only local
|
||||
// - finish local/world matrix application
|
||||
// - OPERATION as bitmask
|
||||
//
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// Example
|
||||
#if 0
|
||||
void EditTransform(const Camera& camera, matrix_t& matrix)
|
||||
{
|
||||
static ImGuizmo::OPERATION mCurrentGizmoOperation(ImGuizmo::ROTATE);
|
||||
static ImGuizmo::MODE mCurrentGizmoMode(ImGuizmo::WORLD);
|
||||
if (ImGui::IsKeyPressed(90))
|
||||
mCurrentGizmoOperation = ImGuizmo::TRANSLATE;
|
||||
if (ImGui::IsKeyPressed(69))
|
||||
mCurrentGizmoOperation = ImGuizmo::ROTATE;
|
||||
if (ImGui::IsKeyPressed(82)) // r Key
|
||||
mCurrentGizmoOperation = ImGuizmo::SCALE;
|
||||
if (ImGui::RadioButton("Translate", mCurrentGizmoOperation == ImGuizmo::TRANSLATE))
|
||||
mCurrentGizmoOperation = ImGuizmo::TRANSLATE;
|
||||
ImGui::SameLine();
|
||||
if (ImGui::RadioButton("Rotate", mCurrentGizmoOperation == ImGuizmo::ROTATE))
|
||||
mCurrentGizmoOperation = ImGuizmo::ROTATE;
|
||||
ImGui::SameLine();
|
||||
if (ImGui::RadioButton("Scale", mCurrentGizmoOperation == ImGuizmo::SCALE))
|
||||
mCurrentGizmoOperation = ImGuizmo::SCALE;
|
||||
float matrixTranslation[3], matrixRotation[3], matrixScale[3];
|
||||
ImGuizmo::DecomposeMatrixToComponents(matrix.m16, matrixTranslation, matrixRotation, matrixScale);
|
||||
ImGui::InputFloat3("Tr", matrixTranslation, 3);
|
||||
ImGui::InputFloat3("Rt", matrixRotation, 3);
|
||||
ImGui::InputFloat3("Sc", matrixScale, 3);
|
||||
ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, matrix.m16);
|
||||
|
||||
if (mCurrentGizmoOperation != ImGuizmo::SCALE)
|
||||
{
|
||||
if (ImGui::RadioButton("Local", mCurrentGizmoMode == ImGuizmo::LOCAL))
|
||||
mCurrentGizmoMode = ImGuizmo::LOCAL;
|
||||
ImGui::SameLine();
|
||||
if (ImGui::RadioButton("World", mCurrentGizmoMode == ImGuizmo::WORLD))
|
||||
mCurrentGizmoMode = ImGuizmo::WORLD;
|
||||
}
|
||||
static bool useSnap(false);
|
||||
if (ImGui::IsKeyPressed(83))
|
||||
useSnap = !useSnap;
|
||||
ImGui::Checkbox("", &useSnap);
|
||||
ImGui::SameLine();
|
||||
vec_t snap;
|
||||
switch (mCurrentGizmoOperation)
|
||||
{
|
||||
case ImGuizmo::TRANSLATE:
|
||||
snap = config.mSnapTranslation;
|
||||
ImGui::InputFloat3("Snap", &snap.x);
|
||||
break;
|
||||
case ImGuizmo::ROTATE:
|
||||
snap = config.mSnapRotation;
|
||||
ImGui::InputFloat("Angle Snap", &snap.x);
|
||||
break;
|
||||
case ImGuizmo::SCALE:
|
||||
snap = config.mSnapScale;
|
||||
ImGui::InputFloat("Scale Snap", &snap.x);
|
||||
break;
|
||||
}
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y);
|
||||
ImGuizmo::Manipulate(camera.mView.m16, camera.mProjection.m16, mCurrentGizmoOperation, mCurrentGizmoMode, matrix.m16, NULL, useSnap ? &snap.x : NULL);
|
||||
}
|
||||
#endif
|
||||
#pragma once
|
||||
|
||||
#ifdef USE_IMGUI_API
|
||||
#include "imconfig.h"
|
||||
#endif
|
||||
#ifndef IMGUI_API
|
||||
#define IMGUI_API
|
||||
#endif
|
||||
|
||||
#ifndef IMGUIZMO_NAMESPACE
|
||||
#define IMGUIZMO_NAMESPACE ImGuizmo
|
||||
#endif
|
||||
|
||||
namespace IMGUIZMO_NAMESPACE
|
||||
{
|
||||
// call inside your own window and before Manipulate() in order to draw gizmo to that window.
|
||||
// Or pass a specific ImDrawList to draw to (e.g. ImGui::GetForegroundDrawList()).
|
||||
IMGUI_API void SetDrawlist(ImDrawList* drawlist = nullptr);
|
||||
|
||||
// call BeginFrame right after ImGui_XXXX_NewFrame();
|
||||
IMGUI_API void BeginFrame();
|
||||
|
||||
// this is necessary because when imguizmo is compiled into a dll, and imgui into another
|
||||
// globals are not shared between them.
|
||||
// More details at https://stackoverflow.com/questions/19373061/what-happens-to-global-and-static-variables-in-a-shared-library-when-it-is-dynam
|
||||
// expose method to set imgui context
|
||||
IMGUI_API void SetImGuiContext(ImGuiContext* ctx);
|
||||
|
||||
// return true if mouse cursor is over any gizmo control (axis, plan or screen component)
|
||||
IMGUI_API bool IsOver();
|
||||
|
||||
// return true if mouse IsOver or if the gizmo is in moving state
|
||||
IMGUI_API bool IsUsing();
|
||||
|
||||
// return true if any gizmo is in moving state
|
||||
IMGUI_API bool IsUsingAny();
|
||||
|
||||
// enable/disable the gizmo. Stay in the state until next call to Enable.
|
||||
// gizmo is rendered with gray half transparent color when disabled
|
||||
IMGUI_API void Enable(bool enable);
|
||||
|
||||
// helper functions for manualy editing translation/rotation/scale with an input float
|
||||
// translation, rotation and scale float points to 3 floats each
|
||||
// Angles are in degrees (more suitable for human editing)
|
||||
// example:
|
||||
// float matrixTranslation[3], matrixRotation[3], matrixScale[3];
|
||||
// ImGuizmo::DecomposeMatrixToComponents(gizmoMatrix.m16, matrixTranslation, matrixRotation, matrixScale);
|
||||
// ImGui::InputFloat3("Tr", matrixTranslation, 3);
|
||||
// ImGui::InputFloat3("Rt", matrixRotation, 3);
|
||||
// ImGui::InputFloat3("Sc", matrixScale, 3);
|
||||
// ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, gizmoMatrix.m16);
|
||||
//
|
||||
// These functions have some numerical stability issues for now. Use with caution.
|
||||
IMGUI_API void DecomposeMatrixToComponents(const float* matrix, float* translation, float* rotation, float* scale);
|
||||
IMGUI_API void RecomposeMatrixFromComponents(const float* translation, const float* rotation, const float* scale, float* matrix);
|
||||
|
||||
IMGUI_API void SetRect(float x, float y, float width, float height);
|
||||
// default is false
|
||||
IMGUI_API void SetOrthographic(bool isOrthographic);
|
||||
|
||||
// Render a cube with face color corresponding to face normal. Usefull for debug/tests
|
||||
IMGUI_API void DrawCubes(const float* view, const float* projection, const float* matrices, int matrixCount);
|
||||
IMGUI_API void DrawGrid(const float* view, const float* projection, const float* matrix, const float gridSize);
|
||||
|
||||
// call it when you want a gizmo
|
||||
// Needs view and projection matrices.
|
||||
// matrix parameter is the source matrix (where will be gizmo be drawn) and might be transformed by the function. Return deltaMatrix is optional
|
||||
// translation is applied in world space
|
||||
enum OPERATION
|
||||
{
|
||||
TRANSLATE_X = (1u << 0),
|
||||
TRANSLATE_Y = (1u << 1),
|
||||
TRANSLATE_Z = (1u << 2),
|
||||
ROTATE_X = (1u << 3),
|
||||
ROTATE_Y = (1u << 4),
|
||||
ROTATE_Z = (1u << 5),
|
||||
ROTATE_SCREEN = (1u << 6),
|
||||
SCALE_X = (1u << 7),
|
||||
SCALE_Y = (1u << 8),
|
||||
SCALE_Z = (1u << 9),
|
||||
BOUNDS = (1u << 10),
|
||||
SCALE_XU = (1u << 11),
|
||||
SCALE_YU = (1u << 12),
|
||||
SCALE_ZU = (1u << 13),
|
||||
|
||||
TRANSLATE = TRANSLATE_X | TRANSLATE_Y | TRANSLATE_Z,
|
||||
ROTATE = ROTATE_X | ROTATE_Y | ROTATE_Z | ROTATE_SCREEN,
|
||||
SCALE = SCALE_X | SCALE_Y | SCALE_Z,
|
||||
SCALEU = SCALE_XU | SCALE_YU | SCALE_ZU, // universal
|
||||
UNIVERSAL = TRANSLATE | ROTATE | SCALEU
|
||||
};
|
||||
|
||||
inline OPERATION operator|(OPERATION lhs, OPERATION rhs)
|
||||
{
|
||||
return static_cast<OPERATION>(static_cast<int>(lhs) | static_cast<int>(rhs));
|
||||
}
|
||||
|
||||
enum MODE
|
||||
{
|
||||
LOCAL,
|
||||
WORLD
|
||||
};
|
||||
|
||||
IMGUI_API bool Manipulate(const float* view, const float* projection, OPERATION operation, MODE mode, float* matrix, float* deltaMatrix = NULL, const float* snap = NULL, const float* localBounds = NULL, const float* boundsSnap = NULL);
|
||||
//
|
||||
// Please note that this cubeview is patented by Autodesk : https://patents.google.com/patent/US7782319B2/en
|
||||
// It seems to be a defensive patent in the US. I don't think it will bring troubles using it as
|
||||
// other software are using the same mechanics. But just in case, you are now warned!
|
||||
//
|
||||
IMGUI_API void ViewManipulate(float* view, float length, ImVec2 position, ImVec2 size, ImU32 backgroundColor);
|
||||
|
||||
// use this version if you did not call Manipulate before and you are just using ViewManipulate
|
||||
IMGUI_API void ViewManipulate(float* view, const float* projection, OPERATION operation, MODE mode, float* matrix, float length, ImVec2 position, ImVec2 size, ImU32 backgroundColor);
|
||||
|
||||
IMGUI_API void SetID(int id);
|
||||
|
||||
// return true if the cursor is over the operation's gizmo
|
||||
IMGUI_API bool IsOver(OPERATION op);
|
||||
IMGUI_API void SetGizmoSizeClipSpace(float value);
|
||||
|
||||
// Allow axis to flip
|
||||
// When true (default), the guizmo axis flip for better visibility
|
||||
// When false, they always stay along the positive world/local axis
|
||||
IMGUI_API void AllowAxisFlip(bool value);
|
||||
|
||||
// Configure the limit where axis are hidden
|
||||
IMGUI_API void SetAxisLimit(float value);
|
||||
// Configure the limit where planes are hiden
|
||||
IMGUI_API void SetPlaneLimit(float value);
|
||||
|
||||
enum COLOR
|
||||
{
|
||||
DIRECTION_X, // directionColor[0]
|
||||
DIRECTION_Y, // directionColor[1]
|
||||
DIRECTION_Z, // directionColor[2]
|
||||
PLANE_X, // planeColor[0]
|
||||
PLANE_Y, // planeColor[1]
|
||||
PLANE_Z, // planeColor[2]
|
||||
SELECTION, // selectionColor
|
||||
INACTIVE, // inactiveColor
|
||||
TRANSLATION_LINE, // translationLineColor
|
||||
SCALE_LINE,
|
||||
ROTATION_USING_BORDER,
|
||||
ROTATION_USING_FILL,
|
||||
HATCHED_AXIS_LINES,
|
||||
TEXT,
|
||||
TEXT_SHADOW,
|
||||
COUNT
|
||||
};
|
||||
|
||||
struct Style
|
||||
{
|
||||
IMGUI_API Style();
|
||||
|
||||
float TranslationLineThickness; // Thickness of lines for translation gizmo
|
||||
float TranslationLineArrowSize; // Size of arrow at the end of lines for translation gizmo
|
||||
float RotationLineThickness; // Thickness of lines for rotation gizmo
|
||||
float RotationOuterLineThickness; // Thickness of line surrounding the rotation gizmo
|
||||
float ScaleLineThickness; // Thickness of lines for scale gizmo
|
||||
float ScaleLineCircleSize; // Size of circle at the end of lines for scale gizmo
|
||||
float HatchedAxisLineThickness; // Thickness of hatched axis lines
|
||||
float CenterCircleSize; // Size of circle at the center of the translate/scale gizmo
|
||||
|
||||
ImVec4 Colors[COLOR::COUNT];
|
||||
};
|
||||
|
||||
IMGUI_API Style& GetStyle();
|
||||
}
|
695
source/engine/thirdparty/imgui/ImSequencer.cpp
vendored
Normal file
695
source/engine/thirdparty/imgui/ImSequencer.cpp
vendored
Normal file
|
@ -0,0 +1,695 @@
|
|||
// https://github.com/CedricGuillemet/ImGuizmo
|
||||
// v 1.89 WIP
|
||||
//
|
||||
// The MIT License(MIT)
|
||||
//
|
||||
// Copyright(c) 2021 Cedric Guillemet
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files(the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions :
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
#include "ImSequencer.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
#include <cstdlib>
|
||||
|
||||
namespace ImSequencer
|
||||
{
|
||||
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
||||
static ImVec2 operator+(const ImVec2& a, const ImVec2& b) {
|
||||
return ImVec2(a.x + b.x, a.y + b.y);
|
||||
}
|
||||
#endif
|
||||
static bool SequencerAddDelButton(ImDrawList* draw_list, ImVec2 pos, bool add = true)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImRect btnRect(pos, ImVec2(pos.x + 16, pos.y + 16));
|
||||
bool overBtn = btnRect.Contains(io.MousePos);
|
||||
bool containedClick = overBtn && btnRect.Contains(io.MouseClickedPos[0]);
|
||||
bool clickedBtn = containedClick && io.MouseReleased[0];
|
||||
int btnColor = overBtn ? 0xAAEAFFAA : 0x77A3B2AA;
|
||||
if (containedClick && io.MouseDownDuration[0] > 0)
|
||||
btnRect.Expand(2.0f);
|
||||
|
||||
float midy = pos.y + 16 / 2 - 0.5f;
|
||||
float midx = pos.x + 16 / 2 - 0.5f;
|
||||
draw_list->AddRect(btnRect.Min, btnRect.Max, btnColor, 4);
|
||||
draw_list->AddLine(ImVec2(btnRect.Min.x + 3, midy), ImVec2(btnRect.Max.x - 3, midy), btnColor, 2);
|
||||
if (add)
|
||||
draw_list->AddLine(ImVec2(midx, btnRect.Min.y + 3), ImVec2(midx, btnRect.Max.y - 3), btnColor, 2);
|
||||
return clickedBtn;
|
||||
}
|
||||
|
||||
bool Sequencer(SequenceInterface* sequence, int* currentFrame, bool* expanded, int* selectedEntry, int* firstFrame, int sequenceOptions)
|
||||
{
|
||||
bool ret = false;
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
int cx = (int)(io.MousePos.x);
|
||||
int cy = (int)(io.MousePos.y);
|
||||
static float framePixelWidth = 10.f;
|
||||
static float framePixelWidthTarget = 10.f;
|
||||
int legendWidth = 200;
|
||||
|
||||
static int movingEntry = -1;
|
||||
static int movingPos = -1;
|
||||
static int movingPart = -1;
|
||||
int delEntry = -1;
|
||||
int dupEntry = -1;
|
||||
int ItemHeight = 20;
|
||||
|
||||
bool popupOpened = false;
|
||||
int sequenceCount = sequence->GetItemCount();
|
||||
if (!sequenceCount)
|
||||
return false;
|
||||
ImGui::BeginGroup();
|
||||
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
ImVec2 canvas_pos = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates!
|
||||
ImVec2 canvas_size = ImGui::GetContentRegionAvail(); // Resize canvas to what's available
|
||||
int firstFrameUsed = firstFrame ? *firstFrame : 0;
|
||||
|
||||
|
||||
int controlHeight = sequenceCount * ItemHeight;
|
||||
for (int i = 0; i < sequenceCount; i++)
|
||||
controlHeight += int(sequence->GetCustomHeight(i));
|
||||
int frameCount = ImMax(sequence->GetFrameMax() - sequence->GetFrameMin(), 1);
|
||||
|
||||
static bool MovingScrollBar = false;
|
||||
static bool MovingCurrentFrame = false;
|
||||
struct CustomDraw
|
||||
{
|
||||
int index;
|
||||
ImRect customRect;
|
||||
ImRect legendRect;
|
||||
ImRect clippingRect;
|
||||
ImRect legendClippingRect;
|
||||
};
|
||||
ImVector<CustomDraw> customDraws;
|
||||
ImVector<CustomDraw> compactCustomDraws;
|
||||
// zoom in/out
|
||||
const int visibleFrameCount = (int)floorf((canvas_size.x - legendWidth) / framePixelWidth);
|
||||
const float barWidthRatio = ImMin(visibleFrameCount / (float)frameCount, 1.f);
|
||||
const float barWidthInPixels = barWidthRatio * (canvas_size.x - legendWidth);
|
||||
|
||||
ImRect regionRect(canvas_pos, canvas_pos + canvas_size);
|
||||
|
||||
static bool panningView = false;
|
||||
static ImVec2 panningViewSource;
|
||||
static int panningViewFrame;
|
||||
if (ImGui::IsWindowFocused() && io.KeyAlt && io.MouseDown[2])
|
||||
{
|
||||
if (!panningView)
|
||||
{
|
||||
panningViewSource = io.MousePos;
|
||||
panningView = true;
|
||||
panningViewFrame = *firstFrame;
|
||||
}
|
||||
*firstFrame = panningViewFrame - int((io.MousePos.x - panningViewSource.x) / framePixelWidth);
|
||||
*firstFrame = ImClamp(*firstFrame, sequence->GetFrameMin(), sequence->GetFrameMax() - visibleFrameCount);
|
||||
}
|
||||
if (panningView && !io.MouseDown[2])
|
||||
{
|
||||
panningView = false;
|
||||
}
|
||||
framePixelWidthTarget = ImClamp(framePixelWidthTarget, 0.1f, 50.f);
|
||||
|
||||
framePixelWidth = ImLerp(framePixelWidth, framePixelWidthTarget, 0.33f);
|
||||
|
||||
frameCount = sequence->GetFrameMax() - sequence->GetFrameMin();
|
||||
if (visibleFrameCount >= frameCount && firstFrame)
|
||||
*firstFrame = sequence->GetFrameMin();
|
||||
|
||||
|
||||
// --
|
||||
if (expanded && !*expanded)
|
||||
{
|
||||
ImGui::InvisibleButton("canvas", ImVec2(canvas_size.x - canvas_pos.x, (float)ItemHeight));
|
||||
draw_list->AddRectFilled(canvas_pos, ImVec2(canvas_size.x + canvas_pos.x, canvas_pos.y + ItemHeight), 0xFF3D3837, 0);
|
||||
char tmps[512];
|
||||
ImFormatString(tmps, IM_ARRAYSIZE(tmps), sequence->GetCollapseFmt(), frameCount, sequenceCount);
|
||||
draw_list->AddText(ImVec2(canvas_pos.x + 26, canvas_pos.y + 2), 0xFFFFFFFF, tmps);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool hasScrollBar(true);
|
||||
/*
|
||||
int framesPixelWidth = int(frameCount * framePixelWidth);
|
||||
if ((framesPixelWidth + legendWidth) >= canvas_size.x)
|
||||
{
|
||||
hasScrollBar = true;
|
||||
}
|
||||
*/
|
||||
// test scroll area
|
||||
ImVec2 headerSize(canvas_size.x, (float)ItemHeight);
|
||||
ImVec2 scrollBarSize(canvas_size.x, 14.f);
|
||||
ImGui::InvisibleButton("topBar", headerSize);
|
||||
draw_list->AddRectFilled(canvas_pos, canvas_pos + headerSize, 0xFFFF0000, 0);
|
||||
ImVec2 childFramePos = ImGui::GetCursorScreenPos();
|
||||
ImVec2 childFrameSize(canvas_size.x, canvas_size.y - 8.f - headerSize.y - (hasScrollBar ? scrollBarSize.y : 0));
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, 0);
|
||||
ImGui::BeginChildFrame(889, childFrameSize);
|
||||
sequence->focused = ImGui::IsWindowFocused();
|
||||
ImGui::InvisibleButton("contentBar", ImVec2(canvas_size.x, float(controlHeight)));
|
||||
const ImVec2 contentMin = ImGui::GetItemRectMin();
|
||||
const ImVec2 contentMax = ImGui::GetItemRectMax();
|
||||
const ImRect contentRect(contentMin, contentMax);
|
||||
const float contentHeight = contentMax.y - contentMin.y;
|
||||
|
||||
// full background
|
||||
draw_list->AddRectFilled(canvas_pos, canvas_pos + canvas_size, 0xFF242424, 0);
|
||||
|
||||
// current frame top
|
||||
ImRect topRect(ImVec2(canvas_pos.x + legendWidth, canvas_pos.y), ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + ItemHeight));
|
||||
|
||||
if (!MovingCurrentFrame && !MovingScrollBar && movingEntry == -1 && sequenceOptions & SEQUENCER_CHANGE_FRAME && currentFrame && *currentFrame >= 0 && topRect.Contains(io.MousePos) && io.MouseDown[0])
|
||||
{
|
||||
MovingCurrentFrame = true;
|
||||
}
|
||||
if (MovingCurrentFrame)
|
||||
{
|
||||
if (frameCount)
|
||||
{
|
||||
*currentFrame = (int)((io.MousePos.x - topRect.Min.x) / framePixelWidth) + firstFrameUsed;
|
||||
if (*currentFrame < sequence->GetFrameMin())
|
||||
*currentFrame = sequence->GetFrameMin();
|
||||
if (*currentFrame >= sequence->GetFrameMax())
|
||||
*currentFrame = sequence->GetFrameMax();
|
||||
}
|
||||
if (!io.MouseDown[0])
|
||||
MovingCurrentFrame = false;
|
||||
}
|
||||
|
||||
//header
|
||||
draw_list->AddRectFilled(canvas_pos, ImVec2(canvas_size.x + canvas_pos.x, canvas_pos.y + ItemHeight), 0xFF3D3837, 0);
|
||||
if (sequenceOptions & SEQUENCER_ADD)
|
||||
{
|
||||
if (SequencerAddDelButton(draw_list, ImVec2(canvas_pos.x + legendWidth - ItemHeight, canvas_pos.y + 2), true))
|
||||
ImGui::OpenPopup("addEntry");
|
||||
|
||||
if (ImGui::BeginPopup("addEntry"))
|
||||
{
|
||||
for (int i = 0; i < sequence->GetItemTypeCount(); i++)
|
||||
if (ImGui::Selectable(sequence->GetItemTypeName(i)))
|
||||
{
|
||||
sequence->Add(i);
|
||||
*selectedEntry = sequence->GetItemCount() - 1;
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
popupOpened = true;
|
||||
}
|
||||
}
|
||||
|
||||
//header frame number and lines
|
||||
int modFrameCount = 10;
|
||||
int frameStep = 1;
|
||||
while ((modFrameCount * framePixelWidth) < 150)
|
||||
{
|
||||
modFrameCount *= 2;
|
||||
frameStep *= 2;
|
||||
};
|
||||
int halfModFrameCount = modFrameCount / 2;
|
||||
|
||||
auto drawLine = [&](int i, int regionHeight) {
|
||||
bool baseIndex = ((i % modFrameCount) == 0) || (i == sequence->GetFrameMax() || i == sequence->GetFrameMin());
|
||||
bool halfIndex = (i % halfModFrameCount) == 0;
|
||||
int px = (int)canvas_pos.x + int(i * framePixelWidth) + legendWidth - int(firstFrameUsed * framePixelWidth);
|
||||
int tiretStart = baseIndex ? 4 : (halfIndex ? 10 : 14);
|
||||
int tiretEnd = baseIndex ? regionHeight : ItemHeight;
|
||||
|
||||
if (px <= (canvas_size.x + canvas_pos.x) && px >= (canvas_pos.x + legendWidth))
|
||||
{
|
||||
draw_list->AddLine(ImVec2((float)px, canvas_pos.y + (float)tiretStart), ImVec2((float)px, canvas_pos.y + (float)tiretEnd - 1), 0xFF606060, 1);
|
||||
|
||||
draw_list->AddLine(ImVec2((float)px, canvas_pos.y + (float)ItemHeight), ImVec2((float)px, canvas_pos.y + (float)regionHeight - 1), 0x30606060, 1);
|
||||
}
|
||||
|
||||
if (baseIndex && px > (canvas_pos.x + legendWidth))
|
||||
{
|
||||
char tmps[512];
|
||||
ImFormatString(tmps, IM_ARRAYSIZE(tmps), "%d", i);
|
||||
draw_list->AddText(ImVec2((float)px + 3.f, canvas_pos.y), 0xFFBBBBBB, tmps);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
auto drawLineContent = [&](int i, int /*regionHeight*/) {
|
||||
int px = (int)canvas_pos.x + int(i * framePixelWidth) + legendWidth - int(firstFrameUsed * framePixelWidth);
|
||||
int tiretStart = int(contentMin.y);
|
||||
int tiretEnd = int(contentMax.y);
|
||||
|
||||
if (px <= (canvas_size.x + canvas_pos.x) && px >= (canvas_pos.x + legendWidth))
|
||||
{
|
||||
//draw_list->AddLine(ImVec2((float)px, canvas_pos.y + (float)tiretStart), ImVec2((float)px, canvas_pos.y + (float)tiretEnd - 1), 0xFF606060, 1);
|
||||
|
||||
draw_list->AddLine(ImVec2(float(px), float(tiretStart)), ImVec2(float(px), float(tiretEnd)), 0x30606060, 1);
|
||||
}
|
||||
};
|
||||
for (int i = sequence->GetFrameMin(); i <= sequence->GetFrameMax(); i += frameStep)
|
||||
{
|
||||
drawLine(i, ItemHeight);
|
||||
}
|
||||
drawLine(sequence->GetFrameMin(), ItemHeight);
|
||||
drawLine(sequence->GetFrameMax(), ItemHeight);
|
||||
/*
|
||||
draw_list->AddLine(canvas_pos, ImVec2(canvas_pos.x, canvas_pos.y + controlHeight), 0xFF000000, 1);
|
||||
draw_list->AddLine(ImVec2(canvas_pos.x, canvas_pos.y + ItemHeight), ImVec2(canvas_size.x, canvas_pos.y + ItemHeight), 0xFF000000, 1);
|
||||
*/
|
||||
// clip content
|
||||
|
||||
draw_list->PushClipRect(childFramePos, childFramePos + childFrameSize, true);
|
||||
|
||||
// draw item names in the legend rect on the left
|
||||
size_t customHeight = 0;
|
||||
for (int i = 0; i < sequenceCount; i++)
|
||||
{
|
||||
int type;
|
||||
sequence->Get(i, NULL, NULL, &type, NULL);
|
||||
ImVec2 tpos(contentMin.x + 3, contentMin.y + i * ItemHeight + 2 + customHeight);
|
||||
draw_list->AddText(tpos, 0xFFFFFFFF, sequence->GetItemLabel(i));
|
||||
|
||||
if (sequenceOptions & SEQUENCER_DEL)
|
||||
{
|
||||
if (SequencerAddDelButton(draw_list, ImVec2(contentMin.x + legendWidth - ItemHeight + 2 - 10, tpos.y + 2), false))
|
||||
delEntry = i;
|
||||
|
||||
if (SequencerAddDelButton(draw_list, ImVec2(contentMin.x + legendWidth - ItemHeight - ItemHeight + 2 - 10, tpos.y + 2), true))
|
||||
dupEntry = i;
|
||||
}
|
||||
customHeight += sequence->GetCustomHeight(i);
|
||||
}
|
||||
|
||||
// slots background
|
||||
customHeight = 0;
|
||||
for (int i = 0; i < sequenceCount; i++)
|
||||
{
|
||||
unsigned int col = (i & 1) ? 0xFF3A3636 : 0xFF413D3D;
|
||||
|
||||
size_t localCustomHeight = sequence->GetCustomHeight(i);
|
||||
ImVec2 pos = ImVec2(contentMin.x + legendWidth, contentMin.y + ItemHeight * i + 1 + customHeight);
|
||||
ImVec2 sz = ImVec2(canvas_size.x + canvas_pos.x, pos.y + ItemHeight - 1 + localCustomHeight);
|
||||
if (!popupOpened && cy >= pos.y && cy < pos.y + (ItemHeight + localCustomHeight) && movingEntry == -1 && cx>contentMin.x && cx < contentMin.x + canvas_size.x)
|
||||
{
|
||||
col += 0x80201008;
|
||||
pos.x -= legendWidth;
|
||||
}
|
||||
draw_list->AddRectFilled(pos, sz, col, 0);
|
||||
customHeight += localCustomHeight;
|
||||
}
|
||||
|
||||
draw_list->PushClipRect(childFramePos + ImVec2(float(legendWidth), 0.f), childFramePos + childFrameSize, true);
|
||||
|
||||
// vertical frame lines in content area
|
||||
for (int i = sequence->GetFrameMin(); i <= sequence->GetFrameMax(); i += frameStep)
|
||||
{
|
||||
drawLineContent(i, int(contentHeight));
|
||||
}
|
||||
drawLineContent(sequence->GetFrameMin(), int(contentHeight));
|
||||
drawLineContent(sequence->GetFrameMax(), int(contentHeight));
|
||||
|
||||
// selection
|
||||
bool selected = selectedEntry && (*selectedEntry >= 0);
|
||||
if (selected)
|
||||
{
|
||||
customHeight = 0;
|
||||
for (int i = 0; i < *selectedEntry; i++)
|
||||
customHeight += sequence->GetCustomHeight(i);
|
||||
draw_list->AddRectFilled(ImVec2(contentMin.x, contentMin.y + ItemHeight * *selectedEntry + customHeight), ImVec2(contentMin.x + canvas_size.x, contentMin.y + ItemHeight * (*selectedEntry + 1) + customHeight), 0x801080FF, 1.f);
|
||||
}
|
||||
|
||||
// slots
|
||||
customHeight = 0;
|
||||
for (int i = 0; i < sequenceCount; i++)
|
||||
{
|
||||
int* start, * end;
|
||||
unsigned int color;
|
||||
sequence->Get(i, &start, &end, NULL, &color);
|
||||
size_t localCustomHeight = sequence->GetCustomHeight(i);
|
||||
|
||||
ImVec2 pos = ImVec2(contentMin.x + legendWidth - firstFrameUsed * framePixelWidth, contentMin.y + ItemHeight * i + 1 + customHeight);
|
||||
ImVec2 slotP1(pos.x + *start * framePixelWidth, pos.y + 2);
|
||||
ImVec2 slotP2(pos.x + *end * framePixelWidth + framePixelWidth, pos.y + ItemHeight - 2);
|
||||
ImVec2 slotP3(pos.x + *end * framePixelWidth + framePixelWidth, pos.y + ItemHeight - 2 + localCustomHeight);
|
||||
unsigned int slotColor = color | 0xFF000000;
|
||||
unsigned int slotColorHalf = (color & 0xFFFFFF) | 0x40000000;
|
||||
|
||||
if (slotP1.x <= (canvas_size.x + contentMin.x) && slotP2.x >= (contentMin.x + legendWidth))
|
||||
{
|
||||
draw_list->AddRectFilled(slotP1, slotP3, slotColorHalf, 2);
|
||||
draw_list->AddRectFilled(slotP1, slotP2, slotColor, 2);
|
||||
}
|
||||
if (ImRect(slotP1, slotP2).Contains(io.MousePos) && io.MouseDoubleClicked[0])
|
||||
{
|
||||
sequence->DoubleClick(i);
|
||||
}
|
||||
// Ensure grabbable handles
|
||||
const float max_handle_width = slotP2.x - slotP1.x / 3.0f;
|
||||
const float min_handle_width = ImMin(10.0f, max_handle_width);
|
||||
const float handle_width = ImClamp(framePixelWidth / 2.0f, min_handle_width, max_handle_width);
|
||||
ImRect rects[3] = { ImRect(slotP1, ImVec2(slotP1.x + handle_width, slotP2.y))
|
||||
, ImRect(ImVec2(slotP2.x - handle_width, slotP1.y), slotP2)
|
||||
, ImRect(slotP1, slotP2) };
|
||||
|
||||
const unsigned int quadColor[] = { 0xFFFFFFFF, 0xFFFFFFFF, slotColor + (selected ? 0 : 0x202020) };
|
||||
if (movingEntry == -1 && (sequenceOptions & SEQUENCER_EDIT_STARTEND))// TODOFOCUS && backgroundRect.Contains(io.MousePos))
|
||||
{
|
||||
for (int j = 2; j >= 0; j--)
|
||||
{
|
||||
ImRect& rc = rects[j];
|
||||
if (!rc.Contains(io.MousePos))
|
||||
continue;
|
||||
draw_list->AddRectFilled(rc.Min, rc.Max, quadColor[j], 2);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
ImRect& rc = rects[j];
|
||||
if (!rc.Contains(io.MousePos))
|
||||
continue;
|
||||
if (!ImRect(childFramePos, childFramePos + childFrameSize).Contains(io.MousePos))
|
||||
continue;
|
||||
if (ImGui::IsMouseClicked(0) && !MovingScrollBar && !MovingCurrentFrame)
|
||||
{
|
||||
movingEntry = i;
|
||||
movingPos = cx;
|
||||
movingPart = j + 1;
|
||||
sequence->BeginEdit(movingEntry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// custom draw
|
||||
if (localCustomHeight > 0)
|
||||
{
|
||||
ImVec2 rp(canvas_pos.x, contentMin.y + ItemHeight * i + 1 + customHeight);
|
||||
ImRect customRect(rp + ImVec2(legendWidth - (firstFrameUsed - sequence->GetFrameMin() - 0.5f) * framePixelWidth, float(ItemHeight)),
|
||||
rp + ImVec2(legendWidth + (sequence->GetFrameMax() - firstFrameUsed - 0.5f + 2.f) * framePixelWidth, float(localCustomHeight + ItemHeight)));
|
||||
ImRect clippingRect(rp + ImVec2(float(legendWidth), float(ItemHeight)), rp + ImVec2(canvas_size.x, float(localCustomHeight + ItemHeight)));
|
||||
|
||||
ImRect legendRect(rp + ImVec2(0.f, float(ItemHeight)), rp + ImVec2(float(legendWidth), float(localCustomHeight)));
|
||||
ImRect legendClippingRect(canvas_pos + ImVec2(0.f, float(ItemHeight)), canvas_pos + ImVec2(float(legendWidth), float(localCustomHeight + ItemHeight)));
|
||||
customDraws.push_back({ i, customRect, legendRect, clippingRect, legendClippingRect });
|
||||
}
|
||||
else
|
||||
{
|
||||
ImVec2 rp(canvas_pos.x, contentMin.y + ItemHeight * i + customHeight);
|
||||
ImRect customRect(rp + ImVec2(legendWidth - (firstFrameUsed - sequence->GetFrameMin() - 0.5f) * framePixelWidth, float(0.f)),
|
||||
rp + ImVec2(legendWidth + (sequence->GetFrameMax() - firstFrameUsed - 0.5f + 2.f) * framePixelWidth, float(ItemHeight)));
|
||||
ImRect clippingRect(rp + ImVec2(float(legendWidth), float(0.f)), rp + ImVec2(canvas_size.x, float(ItemHeight)));
|
||||
|
||||
compactCustomDraws.push_back({ i, customRect, ImRect(), clippingRect, ImRect() });
|
||||
}
|
||||
customHeight += localCustomHeight;
|
||||
}
|
||||
|
||||
|
||||
// moving
|
||||
if (/*backgroundRect.Contains(io.MousePos) && */movingEntry >= 0)
|
||||
{
|
||||
#if IMGUI_VERSION_NUM >= 18723
|
||||
ImGui::SetNextFrameWantCaptureMouse(true);
|
||||
#else
|
||||
ImGui::CaptureMouseFromApp();
|
||||
#endif
|
||||
int diffFrame = int((cx - movingPos) / framePixelWidth);
|
||||
if (std::abs(diffFrame) > 0)
|
||||
{
|
||||
int* start, * end;
|
||||
sequence->Get(movingEntry, &start, &end, NULL, NULL);
|
||||
if (selectedEntry)
|
||||
*selectedEntry = movingEntry;
|
||||
int& l = *start;
|
||||
int& r = *end;
|
||||
if (movingPart & 1)
|
||||
l += diffFrame;
|
||||
if (movingPart & 2)
|
||||
r += diffFrame;
|
||||
if (l < 0)
|
||||
{
|
||||
if (movingPart & 2)
|
||||
r -= l;
|
||||
l = 0;
|
||||
}
|
||||
if (movingPart & 1 && l > r)
|
||||
l = r;
|
||||
if (movingPart & 2 && r < l)
|
||||
r = l;
|
||||
movingPos += int(diffFrame * framePixelWidth);
|
||||
}
|
||||
if (!io.MouseDown[0])
|
||||
{
|
||||
// single select
|
||||
if (!diffFrame && movingPart && selectedEntry)
|
||||
{
|
||||
*selectedEntry = movingEntry;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
movingEntry = -1;
|
||||
sequence->EndEdit();
|
||||
}
|
||||
}
|
||||
|
||||
// cursor
|
||||
if (currentFrame && firstFrame && *currentFrame >= *firstFrame && *currentFrame <= sequence->GetFrameMax())
|
||||
{
|
||||
static const float cursorWidth = 8.f;
|
||||
float cursorOffset = contentMin.x + legendWidth + (*currentFrame - firstFrameUsed) * framePixelWidth + framePixelWidth / 2 - cursorWidth * 0.5f;
|
||||
draw_list->AddLine(ImVec2(cursorOffset, canvas_pos.y), ImVec2(cursorOffset, contentMax.y), 0xA02A2AFF, cursorWidth);
|
||||
char tmps[512];
|
||||
ImFormatString(tmps, IM_ARRAYSIZE(tmps), "%d", *currentFrame);
|
||||
draw_list->AddText(ImVec2(cursorOffset + 10, canvas_pos.y + 2), 0xFF2A2AFF, tmps);
|
||||
}
|
||||
|
||||
draw_list->PopClipRect();
|
||||
draw_list->PopClipRect();
|
||||
|
||||
for (auto& customDraw : customDraws)
|
||||
sequence->CustomDraw(customDraw.index, draw_list, customDraw.customRect, customDraw.legendRect, customDraw.clippingRect, customDraw.legendClippingRect);
|
||||
for (auto& customDraw : compactCustomDraws)
|
||||
sequence->CustomDrawCompact(customDraw.index, draw_list, customDraw.customRect, customDraw.clippingRect);
|
||||
|
||||
// copy paste
|
||||
if (sequenceOptions & SEQUENCER_COPYPASTE)
|
||||
{
|
||||
ImRect rectCopy(ImVec2(contentMin.x + 100, canvas_pos.y + 2)
|
||||
, ImVec2(contentMin.x + 100 + 30, canvas_pos.y + ItemHeight - 2));
|
||||
bool inRectCopy = rectCopy.Contains(io.MousePos);
|
||||
unsigned int copyColor = inRectCopy ? 0xFF1080FF : 0xFF000000;
|
||||
draw_list->AddText(rectCopy.Min, copyColor, "Copy");
|
||||
|
||||
ImRect rectPaste(ImVec2(contentMin.x + 140, canvas_pos.y + 2)
|
||||
, ImVec2(contentMin.x + 140 + 30, canvas_pos.y + ItemHeight - 2));
|
||||
bool inRectPaste = rectPaste.Contains(io.MousePos);
|
||||
unsigned int pasteColor = inRectPaste ? 0xFF1080FF : 0xFF000000;
|
||||
draw_list->AddText(rectPaste.Min, pasteColor, "Paste");
|
||||
|
||||
if (inRectCopy && io.MouseReleased[0])
|
||||
{
|
||||
sequence->Copy();
|
||||
}
|
||||
if (inRectPaste && io.MouseReleased[0])
|
||||
{
|
||||
sequence->Paste();
|
||||
}
|
||||
}
|
||||
//
|
||||
|
||||
ImGui::EndChildFrame();
|
||||
ImGui::PopStyleColor();
|
||||
if (hasScrollBar)
|
||||
{
|
||||
ImGui::InvisibleButton("scrollBar", scrollBarSize);
|
||||
ImVec2 scrollBarMin = ImGui::GetItemRectMin();
|
||||
ImVec2 scrollBarMax = ImGui::GetItemRectMax();
|
||||
|
||||
// ratio = number of frames visible in control / number to total frames
|
||||
|
||||
float startFrameOffset = ((float)(firstFrameUsed - sequence->GetFrameMin()) / (float)frameCount) * (canvas_size.x - legendWidth);
|
||||
ImVec2 scrollBarA(scrollBarMin.x + legendWidth, scrollBarMin.y - 2);
|
||||
ImVec2 scrollBarB(scrollBarMin.x + canvas_size.x, scrollBarMax.y - 1);
|
||||
draw_list->AddRectFilled(scrollBarA, scrollBarB, 0xFF222222, 0);
|
||||
|
||||
ImRect scrollBarRect(scrollBarA, scrollBarB);
|
||||
bool inScrollBar = scrollBarRect.Contains(io.MousePos);
|
||||
|
||||
draw_list->AddRectFilled(scrollBarA, scrollBarB, 0xFF101010, 8);
|
||||
|
||||
|
||||
ImVec2 scrollBarC(scrollBarMin.x + legendWidth + startFrameOffset, scrollBarMin.y);
|
||||
ImVec2 scrollBarD(scrollBarMin.x + legendWidth + barWidthInPixels + startFrameOffset, scrollBarMax.y - 2);
|
||||
draw_list->AddRectFilled(scrollBarC, scrollBarD, (inScrollBar || MovingScrollBar) ? 0xFF606060 : 0xFF505050, 6);
|
||||
|
||||
ImRect barHandleLeft(scrollBarC, ImVec2(scrollBarC.x + 14, scrollBarD.y));
|
||||
ImRect barHandleRight(ImVec2(scrollBarD.x - 14, scrollBarC.y), scrollBarD);
|
||||
|
||||
bool onLeft = barHandleLeft.Contains(io.MousePos);
|
||||
bool onRight = barHandleRight.Contains(io.MousePos);
|
||||
|
||||
static bool sizingRBar = false;
|
||||
static bool sizingLBar = false;
|
||||
|
||||
draw_list->AddRectFilled(barHandleLeft.Min, barHandleLeft.Max, (onLeft || sizingLBar) ? 0xFFAAAAAA : 0xFF666666, 6);
|
||||
draw_list->AddRectFilled(barHandleRight.Min, barHandleRight.Max, (onRight || sizingRBar) ? 0xFFAAAAAA : 0xFF666666, 6);
|
||||
|
||||
ImRect scrollBarThumb(scrollBarC, scrollBarD);
|
||||
static const float MinBarWidth = 44.f;
|
||||
if (sizingRBar)
|
||||
{
|
||||
if (!io.MouseDown[0])
|
||||
{
|
||||
sizingRBar = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
float barNewWidth = ImMax(barWidthInPixels + io.MouseDelta.x, MinBarWidth);
|
||||
float barRatio = barNewWidth / barWidthInPixels;
|
||||
framePixelWidthTarget = framePixelWidth = framePixelWidth / barRatio;
|
||||
int newVisibleFrameCount = int((canvas_size.x - legendWidth) / framePixelWidthTarget);
|
||||
int lastFrame = *firstFrame + newVisibleFrameCount;
|
||||
if (lastFrame > sequence->GetFrameMax())
|
||||
{
|
||||
framePixelWidthTarget = framePixelWidth = (canvas_size.x - legendWidth) / float(sequence->GetFrameMax() - *firstFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sizingLBar)
|
||||
{
|
||||
if (!io.MouseDown[0])
|
||||
{
|
||||
sizingLBar = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fabsf(io.MouseDelta.x) > FLT_EPSILON)
|
||||
{
|
||||
float barNewWidth = ImMax(barWidthInPixels - io.MouseDelta.x, MinBarWidth);
|
||||
float barRatio = barNewWidth / barWidthInPixels;
|
||||
float previousFramePixelWidthTarget = framePixelWidthTarget;
|
||||
framePixelWidthTarget = framePixelWidth = framePixelWidth / barRatio;
|
||||
int newVisibleFrameCount = int(visibleFrameCount / barRatio);
|
||||
int newFirstFrame = *firstFrame + newVisibleFrameCount - visibleFrameCount;
|
||||
newFirstFrame = ImClamp(newFirstFrame, sequence->GetFrameMin(), ImMax(sequence->GetFrameMax() - visibleFrameCount, sequence->GetFrameMin()));
|
||||
if (newFirstFrame == *firstFrame)
|
||||
{
|
||||
framePixelWidth = framePixelWidthTarget = previousFramePixelWidthTarget;
|
||||
}
|
||||
else
|
||||
{
|
||||
*firstFrame = newFirstFrame;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MovingScrollBar)
|
||||
{
|
||||
if (!io.MouseDown[0])
|
||||
{
|
||||
MovingScrollBar = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
float framesPerPixelInBar = barWidthInPixels / (float)visibleFrameCount;
|
||||
*firstFrame = int((io.MousePos.x - panningViewSource.x) / framesPerPixelInBar) - panningViewFrame;
|
||||
*firstFrame = ImClamp(*firstFrame, sequence->GetFrameMin(), ImMax(sequence->GetFrameMax() - visibleFrameCount, sequence->GetFrameMin()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (scrollBarThumb.Contains(io.MousePos) && ImGui::IsMouseClicked(0) && firstFrame && !MovingCurrentFrame && movingEntry == -1)
|
||||
{
|
||||
MovingScrollBar = true;
|
||||
panningViewSource = io.MousePos;
|
||||
panningViewFrame = -*firstFrame;
|
||||
}
|
||||
if (!sizingRBar && onRight && ImGui::IsMouseClicked(0))
|
||||
sizingRBar = true;
|
||||
if (!sizingLBar && onLeft && ImGui::IsMouseClicked(0))
|
||||
sizingLBar = true;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndGroup();
|
||||
|
||||
if (regionRect.Contains(io.MousePos))
|
||||
{
|
||||
bool overCustomDraw = false;
|
||||
for (auto& custom : customDraws)
|
||||
{
|
||||
if (custom.customRect.Contains(io.MousePos))
|
||||
{
|
||||
overCustomDraw = true;
|
||||
}
|
||||
}
|
||||
if (overCustomDraw)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
#if 0
|
||||
frameOverCursor = *firstFrame + (int)(visibleFrameCount * ((io.MousePos.x - (float)legendWidth - canvas_pos.x) / (canvas_size.x - legendWidth)));
|
||||
//frameOverCursor = max(min(*firstFrame - visibleFrameCount / 2, frameCount - visibleFrameCount), 0);
|
||||
|
||||
/**firstFrame -= frameOverCursor;
|
||||
*firstFrame *= framePixelWidthTarget / framePixelWidth;
|
||||
*firstFrame += frameOverCursor;*/
|
||||
if (io.MouseWheel < -FLT_EPSILON)
|
||||
{
|
||||
*firstFrame -= frameOverCursor;
|
||||
*firstFrame = int(*firstFrame * 1.1f);
|
||||
framePixelWidthTarget *= 0.9f;
|
||||
*firstFrame += frameOverCursor;
|
||||
}
|
||||
|
||||
if (io.MouseWheel > FLT_EPSILON)
|
||||
{
|
||||
*firstFrame -= frameOverCursor;
|
||||
*firstFrame = int(*firstFrame * 0.9f);
|
||||
framePixelWidthTarget *= 1.1f;
|
||||
*firstFrame += frameOverCursor;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (expanded)
|
||||
{
|
||||
if (SequencerAddDelButton(draw_list, ImVec2(canvas_pos.x + 2, canvas_pos.y + 2), !*expanded))
|
||||
*expanded = !*expanded;
|
||||
}
|
||||
|
||||
if (delEntry != -1)
|
||||
{
|
||||
sequence->Del(delEntry);
|
||||
if (selectedEntry && (*selectedEntry == delEntry || *selectedEntry >= sequence->GetItemCount()))
|
||||
*selectedEntry = -1;
|
||||
}
|
||||
|
||||
if (dupEntry != -1)
|
||||
{
|
||||
sequence->Duplicate(dupEntry);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
79
source/engine/thirdparty/imgui/ImSequencer.h
vendored
Normal file
79
source/engine/thirdparty/imgui/ImSequencer.h
vendored
Normal file
|
@ -0,0 +1,79 @@
|
|||
// https://github.com/CedricGuillemet/ImGuizmo
|
||||
// v 1.89 WIP
|
||||
//
|
||||
// The MIT License(MIT)
|
||||
//
|
||||
// Copyright(c) 2021 Cedric Guillemet
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files(the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions :
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
struct ImDrawList;
|
||||
struct ImRect;
|
||||
namespace ImSequencer
|
||||
{
|
||||
enum SEQUENCER_OPTIONS
|
||||
{
|
||||
SEQUENCER_EDIT_NONE = 0,
|
||||
SEQUENCER_EDIT_STARTEND = 1 << 1,
|
||||
SEQUENCER_CHANGE_FRAME = 1 << 3,
|
||||
SEQUENCER_ADD = 1 << 4,
|
||||
SEQUENCER_DEL = 1 << 5,
|
||||
SEQUENCER_COPYPASTE = 1 << 6,
|
||||
SEQUENCER_EDIT_ALL = SEQUENCER_EDIT_STARTEND | SEQUENCER_CHANGE_FRAME
|
||||
};
|
||||
|
||||
struct SequenceInterface
|
||||
{
|
||||
bool focused = false;
|
||||
virtual int GetFrameMin() const = 0;
|
||||
virtual int GetFrameMax() const = 0;
|
||||
virtual int GetItemCount() const = 0;
|
||||
|
||||
virtual void BeginEdit(int /*index*/) {}
|
||||
virtual void EndEdit() {}
|
||||
virtual int GetItemTypeCount() const { return 0; }
|
||||
virtual const char* GetItemTypeName(int /*typeIndex*/) const { return ""; }
|
||||
virtual const char* GetItemLabel(int /*index*/) const { return ""; }
|
||||
virtual const char* GetCollapseFmt() const { return "%d Frames / %d entries"; }
|
||||
|
||||
virtual void Get(int index, int** start, int** end, int* type, unsigned int* color) = 0;
|
||||
virtual void Add(int /*type*/) {}
|
||||
virtual void Del(int /*index*/) {}
|
||||
virtual void Duplicate(int /*index*/) {}
|
||||
|
||||
virtual void Copy() {}
|
||||
virtual void Paste() {}
|
||||
|
||||
virtual size_t GetCustomHeight(int /*index*/) { return 0; }
|
||||
virtual void DoubleClick(int /*index*/) {}
|
||||
virtual void CustomDraw(int /*index*/, ImDrawList* /*draw_list*/, const ImRect& /*rc*/, const ImRect& /*legendRect*/, const ImRect& /*clippingRect*/, const ImRect& /*legendClippingRect*/) {}
|
||||
virtual void CustomDrawCompact(int /*index*/, ImDrawList* /*draw_list*/, const ImRect& /*rc*/, const ImRect& /*clippingRect*/) {}
|
||||
|
||||
virtual ~SequenceInterface() = default;
|
||||
};
|
||||
|
||||
|
||||
// return true if selection is made
|
||||
bool Sequencer(SequenceInterface* sequence, int* currentFrame, bool* expanded, int* selectedEntry, int* firstFrame, int sequenceOptions);
|
||||
|
||||
}
|
245
source/engine/thirdparty/imgui/ImZoomSlider.h
vendored
Normal file
245
source/engine/thirdparty/imgui/ImZoomSlider.h
vendored
Normal file
|
@ -0,0 +1,245 @@
|
|||
// https://github.com/CedricGuillemet/ImGuizmo
|
||||
// v 1.89 WIP
|
||||
//
|
||||
// The MIT License(MIT)
|
||||
//
|
||||
// Copyright(c) 2021 Cedric Guillemet
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files(the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions :
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
namespace ImZoomSlider
|
||||
{
|
||||
typedef int ImGuiZoomSliderFlags;
|
||||
enum ImGuiPopupFlags_
|
||||
{
|
||||
ImGuiZoomSliderFlags_None = 0,
|
||||
ImGuiZoomSliderFlags_Vertical = 1,
|
||||
ImGuiZoomSliderFlags_NoAnchors = 2,
|
||||
ImGuiZoomSliderFlags_NoMiddleCarets = 4,
|
||||
ImGuiZoomSliderFlags_NoWheel = 8,
|
||||
};
|
||||
|
||||
template<typename T> bool ImZoomSlider(const T lower, const T higher, T& viewLower, T& viewHigher, float wheelRatio = 0.01f, ImGuiZoomSliderFlags flags = ImGuiZoomSliderFlags_None)
|
||||
{
|
||||
bool interacted = false;
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
|
||||
static const float handleSize = 12;
|
||||
static const float roundRadius = 3.f;
|
||||
static const char* controlName = "ImZoomSlider";
|
||||
|
||||
static bool movingScrollBarSvg = false;
|
||||
static bool sizingRBarSvg = false;
|
||||
static bool sizingLBarSvg = false;
|
||||
static ImGuiID editingId = (ImGuiID)-1;
|
||||
static float scrollingSource = 0.f;
|
||||
static float saveViewLower;
|
||||
static float saveViewHigher;
|
||||
|
||||
const bool isVertical = flags & ImGuiZoomSliderFlags_Vertical;
|
||||
const ImVec2 canvasPos = ImGui::GetCursorScreenPos();
|
||||
const ImVec2 canvasSize = ImGui::GetContentRegionAvail();
|
||||
const float canvasSizeLength = isVertical ? ImGui::GetItemRectSize().y : canvasSize.x;
|
||||
const ImVec2 scrollBarSize = isVertical ? ImVec2(14.f, canvasSizeLength) : ImVec2(canvasSizeLength, 14.f);
|
||||
|
||||
ImGui::InvisibleButton(controlName, scrollBarSize);
|
||||
const ImGuiID currentId = ImGui::GetID(controlName);
|
||||
|
||||
const bool usingEditingId = currentId == editingId;
|
||||
const bool canUseControl = usingEditingId || editingId == -1;
|
||||
const bool movingScrollBar = usingEditingId ? movingScrollBarSvg : false;
|
||||
const bool sizingRBar = usingEditingId ? sizingRBarSvg : false;
|
||||
const bool sizingLBar = usingEditingId ? sizingLBarSvg : false;
|
||||
const int componentIndex = isVertical ? 1 : 0;
|
||||
const ImVec2 scrollBarMin = ImGui::GetItemRectMin();
|
||||
const ImVec2 scrollBarMax = ImGui::GetItemRectMax();
|
||||
const ImVec2 scrollBarA = ImVec2(scrollBarMin.x, scrollBarMin.y) - (isVertical ? ImVec2(2,0) : ImVec2(0,2));
|
||||
const ImVec2 scrollBarB = isVertical ? ImVec2(scrollBarMax.x - 1.f, scrollBarMin.y + canvasSizeLength) : ImVec2(scrollBarMin.x + canvasSizeLength, scrollBarMax.y - 1.f);
|
||||
const float scrollStart = ((viewLower - lower) / (higher - lower)) * canvasSizeLength + scrollBarMin[componentIndex];
|
||||
const float scrollEnd = ((viewHigher - lower) / (higher - lower)) * canvasSizeLength + scrollBarMin[componentIndex];
|
||||
const float screenSize = scrollEnd - scrollStart;
|
||||
const ImVec2 scrollTopLeft = isVertical ? ImVec2(scrollBarMin.x, scrollStart) : ImVec2(scrollStart, scrollBarMin.y);
|
||||
const ImVec2 scrollBottomRight = isVertical ? ImVec2(scrollBarMax.x - 2.f, scrollEnd) : ImVec2(scrollEnd, scrollBarMax.y - 2.f);
|
||||
const bool inScrollBar = canUseControl && ImRect(scrollTopLeft, scrollBottomRight).Contains(io.MousePos);
|
||||
const ImRect scrollBarRect(scrollBarA, scrollBarB);
|
||||
const float deltaScreen = io.MousePos[componentIndex] - scrollingSource;
|
||||
const float deltaView = ((higher - lower) / canvasSizeLength) * deltaScreen;
|
||||
const uint32_t barColor = ImGui::GetColorU32((inScrollBar || movingScrollBar) ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
|
||||
const float middleCoord = (scrollStart + scrollEnd) * 0.5f;
|
||||
const bool insideControl = canUseControl && ImRect(scrollBarMin, scrollBarMax).Contains(io.MousePos);
|
||||
const bool hasAnchors = !(flags & ImGuiZoomSliderFlags_NoAnchors);
|
||||
const float viewMinSize = ((3.f * handleSize) / canvasSizeLength) * (higher - lower);
|
||||
const auto ClipView = [lower, higher, &viewLower, &viewHigher]() {
|
||||
if (viewLower < lower)
|
||||
{
|
||||
const float deltaClip = lower - viewLower;
|
||||
viewLower += deltaClip;
|
||||
viewHigher += deltaClip;
|
||||
}
|
||||
if (viewHigher > higher)
|
||||
{
|
||||
const float deltaClip = viewHigher - higher;
|
||||
viewLower -= deltaClip;
|
||||
viewHigher -= deltaClip;
|
||||
}
|
||||
};
|
||||
|
||||
bool onLeft = false;
|
||||
bool onRight = false;
|
||||
|
||||
draw_list->AddRectFilled(scrollBarA, scrollBarB, 0xFF101010, roundRadius);
|
||||
draw_list->AddRectFilled(scrollBarA, scrollBarB, 0xFF222222, 0);
|
||||
draw_list->AddRectFilled(scrollTopLeft, scrollBottomRight, barColor, roundRadius);
|
||||
|
||||
if (!(flags & ImGuiZoomSliderFlags_NoMiddleCarets))
|
||||
{
|
||||
for (float i = 0.5f; i < 3.f; i += 1.f)
|
||||
{
|
||||
const float coordA = middleCoord - handleSize * 0.5f;
|
||||
const float coordB = middleCoord + handleSize * 0.5f;
|
||||
ImVec2 base = scrollBarMin;
|
||||
base.x += scrollBarSize.x * 0.25f * i;
|
||||
base.y += scrollBarSize.y * 0.25f * i;
|
||||
|
||||
if (isVertical)
|
||||
{
|
||||
draw_list->AddLine(ImVec2(base.x, coordA), ImVec2(base.x, coordB), ImGui::GetColorU32(ImGuiCol_SliderGrab));
|
||||
}
|
||||
else
|
||||
{
|
||||
draw_list->AddLine(ImVec2(coordA, base.y), ImVec2(coordB, base.y), ImGui::GetColorU32(ImGuiCol_SliderGrab));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mouse wheel
|
||||
if (io.MouseClicked[0] && insideControl && !inScrollBar)
|
||||
{
|
||||
const float ratio = (io.MousePos[componentIndex] - scrollBarMin[componentIndex]) / (scrollBarMax[componentIndex] - scrollBarMin[componentIndex]);
|
||||
const float size = (higher - lower);
|
||||
const float halfViewSize = (viewHigher - viewLower) * 0.5f;
|
||||
const float middle = ratio * size + lower;
|
||||
viewLower = middle - halfViewSize;
|
||||
viewHigher = middle + halfViewSize;
|
||||
ClipView();
|
||||
interacted = true;
|
||||
}
|
||||
|
||||
if (!(flags & ImGuiZoomSliderFlags_NoWheel) && inScrollBar && fabsf(io.MouseWheel) > 0.f)
|
||||
{
|
||||
const float ratio = (io.MousePos[componentIndex] - scrollStart) / (scrollEnd - scrollStart);
|
||||
const float amount = io.MouseWheel * wheelRatio * (viewHigher - viewLower);
|
||||
|
||||
viewLower -= ratio * amount;
|
||||
viewHigher += (1.f - ratio) * amount;
|
||||
ClipView();
|
||||
interacted = true;
|
||||
}
|
||||
|
||||
if (screenSize > handleSize * 2.f && hasAnchors)
|
||||
{
|
||||
const ImRect barHandleLeft(scrollTopLeft, isVertical ? ImVec2(scrollBottomRight.x, scrollTopLeft.y + handleSize) : ImVec2(scrollTopLeft.x + handleSize, scrollBottomRight.y));
|
||||
const ImRect barHandleRight(isVertical ? ImVec2(scrollTopLeft.x, scrollBottomRight.y - handleSize) : ImVec2(scrollBottomRight.x - handleSize, scrollTopLeft.y), scrollBottomRight);
|
||||
|
||||
onLeft = barHandleLeft.Contains(io.MousePos);
|
||||
onRight = barHandleRight.Contains(io.MousePos);
|
||||
|
||||
draw_list->AddRectFilled(barHandleLeft.Min, barHandleLeft.Max, ImGui::GetColorU32((onLeft || sizingLBar) ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), roundRadius);
|
||||
draw_list->AddRectFilled(barHandleRight.Min, barHandleRight.Max, ImGui::GetColorU32((onRight || sizingRBar) ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), roundRadius);
|
||||
}
|
||||
|
||||
if (sizingRBar)
|
||||
{
|
||||
if (!io.MouseDown[0])
|
||||
{
|
||||
sizingRBarSvg = false;
|
||||
editingId = (ImGuiID)-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
viewHigher = ImMin(saveViewHigher + deltaView, higher);
|
||||
}
|
||||
}
|
||||
else if (sizingLBar)
|
||||
{
|
||||
if (!io.MouseDown[0])
|
||||
{
|
||||
sizingLBarSvg = false;
|
||||
editingId = (ImGuiID)-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
viewLower = ImMax(saveViewLower + deltaView, lower);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (movingScrollBar)
|
||||
{
|
||||
if (!io.MouseDown[0])
|
||||
{
|
||||
movingScrollBarSvg = false;
|
||||
editingId = (ImGuiID)-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
viewLower = saveViewLower + deltaView;
|
||||
viewHigher = saveViewHigher + deltaView;
|
||||
ClipView();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (inScrollBar && ImGui::IsMouseClicked(0))
|
||||
{
|
||||
movingScrollBarSvg = true;
|
||||
scrollingSource = io.MousePos[componentIndex];
|
||||
saveViewLower = viewLower;
|
||||
saveViewHigher = viewHigher;
|
||||
editingId = currentId;
|
||||
}
|
||||
if (!sizingRBar && onRight && ImGui::IsMouseClicked(0) && hasAnchors)
|
||||
{
|
||||
sizingRBarSvg = true;
|
||||
editingId = currentId;
|
||||
}
|
||||
if (!sizingLBar && onLeft && ImGui::IsMouseClicked(0) && hasAnchors)
|
||||
{
|
||||
sizingLBarSvg = true;
|
||||
editingId = currentId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// minimal size check
|
||||
if ((viewHigher - viewLower) < viewMinSize)
|
||||
{
|
||||
const float middle = (viewLower + viewHigher) * 0.5f;
|
||||
viewLower = middle - viewMinSize * 0.5f;
|
||||
viewHigher = middle + viewMinSize * 0.5f;
|
||||
ClipView();
|
||||
}
|
||||
|
||||
return movingScrollBar || sizingRBar || sizingLBar || interacted;
|
||||
}
|
||||
|
||||
} // namespace
|
11
source/engine/thirdparty/imgui/imconfig.h
vendored
11
source/engine/thirdparty/imgui/imconfig.h
vendored
|
@ -21,10 +21,11 @@
|
|||
|
||||
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
|
||||
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
|
||||
// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
|
||||
// - Windows DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
|
||||
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
|
||||
//#define IMGUI_API __declspec( dllexport )
|
||||
//#define IMGUI_API __declspec( dllimport )
|
||||
//#define IMGUI_API __declspec(dllexport) // MSVC Windows: DLL export
|
||||
//#define IMGUI_API __declspec(dllimport) // MSVC Windows: DLL import
|
||||
//#define IMGUI_API __attribute__((visibility("default"))) // GCC/Clang: override visibility when set is hidden
|
||||
|
||||
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
|
||||
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
|
@ -42,6 +43,7 @@
|
|||
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
|
||||
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
|
||||
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
|
||||
//#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS // Don't implement default platform_io.Platform_OpenInShellFn() handler (Win32: ShellExecute(), require shell32.lib/.a, Mac/Linux: use system("")).
|
||||
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
|
||||
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
|
||||
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
|
||||
|
@ -49,6 +51,9 @@
|
|||
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
||||
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
|
||||
|
||||
//---- Enable Test Engine / Automation features.
|
||||
//#define IMGUI_ENABLE_TEST_ENGINE // Enable imgui_test_engine hooks. Generally set automatically by include "imgui_te_config.h", see Test Engine for details.
|
||||
|
||||
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
||||
// May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.
|
||||
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||
|
|
897
source/engine/thirdparty/imgui/imgui.cpp
vendored
897
source/engine/thirdparty/imgui/imgui.cpp
vendored
File diff suppressed because it is too large
Load diff
550
source/engine/thirdparty/imgui/imgui.h
vendored
550
source/engine/thirdparty/imgui/imgui.h
vendored
File diff suppressed because it is too large
Load diff
51
source/engine/thirdparty/imgui/imgui_draw.cpp
vendored
51
source/engine/thirdparty/imgui/imgui_draw.cpp
vendored
|
@ -1,4 +1,4 @@
|
|||
// dear imgui, v1.90.8 WIP
|
||||
// dear imgui, v1.91.1
|
||||
// (drawing and font code)
|
||||
|
||||
/*
|
||||
|
@ -211,11 +211,13 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst)
|
|||
colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.20f);
|
||||
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
|
||||
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
|
||||
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
|
||||
colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
|
||||
colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
|
||||
colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
|
||||
colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
|
||||
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
|
||||
colors[ImGuiCol_TabSelected] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
|
||||
colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive];
|
||||
colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
|
||||
colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f);
|
||||
colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
|
||||
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
|
||||
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
|
||||
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
||||
|
@ -225,6 +227,7 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst)
|
|||
colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f); // Prefer using Alpha=1.0 here
|
||||
colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
||||
colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f);
|
||||
colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive];
|
||||
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
|
||||
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
|
||||
colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
|
||||
|
@ -271,11 +274,13 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst)
|
|||
colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.10f);
|
||||
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f);
|
||||
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f);
|
||||
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
|
||||
colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
|
||||
colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
|
||||
colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
|
||||
colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
|
||||
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
|
||||
colors[ImGuiCol_TabSelected] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
|
||||
colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive];
|
||||
colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
|
||||
colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f);
|
||||
colors[ImGuiCol_TabDimmedSelectedOverline] = colors[ImGuiCol_HeaderActive];
|
||||
colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
|
||||
colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
||||
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
||||
|
@ -285,6 +290,7 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst)
|
|||
colors[ImGuiCol_TableBorderLight] = ImVec4(0.26f, 0.26f, 0.28f, 1.00f); // Prefer using Alpha=1.0 here
|
||||
colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
||||
colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.07f);
|
||||
colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive];
|
||||
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f);
|
||||
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
|
||||
colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered];
|
||||
|
@ -332,11 +338,13 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst)
|
|||
colors[ImGuiCol_ResizeGrip] = ImVec4(0.35f, 0.35f, 0.35f, 0.17f);
|
||||
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
|
||||
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
|
||||
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f);
|
||||
colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
|
||||
colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
|
||||
colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
|
||||
colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
|
||||
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f);
|
||||
colors[ImGuiCol_TabSelected] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
|
||||
colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive];
|
||||
colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
|
||||
colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f);
|
||||
colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.26f, 0.59f, 1.00f, 1.00f);
|
||||
colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
|
||||
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
|
||||
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
||||
|
@ -346,6 +354,7 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst)
|
|||
colors[ImGuiCol_TableBorderLight] = ImVec4(0.68f, 0.68f, 0.74f, 1.00f); // Prefer using Alpha=1.0 here
|
||||
colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
||||
colors[ImGuiCol_TableRowBgAlt] = ImVec4(0.30f, 0.30f, 0.30f, 0.09f);
|
||||
colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive];
|
||||
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
|
||||
colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
|
||||
colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered];
|
||||
|
@ -517,7 +526,6 @@ void ImDrawList::_OnChangedClipRect()
|
|||
CmdBuffer.pop_back();
|
||||
return;
|
||||
}
|
||||
|
||||
curr_cmd->ClipRect = _CmdHeader.ClipRect;
|
||||
}
|
||||
|
||||
|
@ -540,7 +548,6 @@ void ImDrawList::_OnChangedTextureID()
|
|||
CmdBuffer.pop_back();
|
||||
return;
|
||||
}
|
||||
|
||||
curr_cmd->TextureId = _CmdHeader.TextureId;
|
||||
}
|
||||
|
||||
|
@ -616,6 +623,15 @@ void ImDrawList::PopTextureID()
|
|||
_OnChangedTextureID();
|
||||
}
|
||||
|
||||
// This is used by ImGui::PushFont()/PopFont(). It works because we never use _TextureIdStack[] elsewhere than in PushTextureID()/PopTextureID().
|
||||
void ImDrawList::_SetTextureID(ImTextureID texture_id)
|
||||
{
|
||||
if (_CmdHeader.TextureId == texture_id)
|
||||
return;
|
||||
_CmdHeader.TextureId = texture_id;
|
||||
_OnChangedTextureID();
|
||||
}
|
||||
|
||||
// Reserve space for a number of vertices and indices.
|
||||
// You must finish filling your reserved data before calling PrimReserve() again, as it may reallocate or
|
||||
// submit the intermediate results. PrimUnreserve() can be used to release unused allocations.
|
||||
|
@ -2806,8 +2822,9 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
|||
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
|
||||
{
|
||||
// Check for valid range. This may also help detect *some* dangling pointers, because a common
|
||||
// user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent.
|
||||
IM_ASSERT(src_range[0] <= src_range[1]);
|
||||
// user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent,
|
||||
// or to forget to zero-terminate the glyph range array.
|
||||
IM_ASSERT(src_range[0] <= src_range[1] && "Invalid range: is your glyph range array persistent? it is zero-terminated?");
|
||||
src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]);
|
||||
}
|
||||
dst_tmp.SrcCount++;
|
||||
|
|
374
source/engine/thirdparty/imgui/imgui_internal.h
vendored
374
source/engine/thirdparty/imgui/imgui_internal.h
vendored
|
@ -1,4 +1,4 @@
|
|||
// dear imgui, v1.90.8 WIP
|
||||
// dear imgui, v1.91.1
|
||||
// (internal structures/api)
|
||||
|
||||
// You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility.
|
||||
|
@ -14,14 +14,15 @@ Index of this file:
|
|||
// [SECTION] Macros
|
||||
// [SECTION] Generic helpers
|
||||
// [SECTION] ImDrawList support
|
||||
// [SECTION] Widgets support: flags, enums, data structures
|
||||
// [SECTION] Data types support
|
||||
// [SECTION] Widgets support: flags, enums, data structures
|
||||
// [SECTION] Popup support
|
||||
// [SECTION] Inputs support
|
||||
// [SECTION] Clipper support
|
||||
// [SECTION] Navigation support
|
||||
// [SECTION] Typing-select support
|
||||
// [SECTION] Columns support
|
||||
// [SECTION] Box-select support
|
||||
// [SECTION] Multi-select support
|
||||
// [SECTION] Docking support
|
||||
// [SECTION] Viewport support
|
||||
|
@ -93,6 +94,7 @@ Index of this file:
|
|||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||
#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated
|
||||
#endif
|
||||
|
||||
// In 1.89.4, we moved the implementation of "courtesy maths operators" from imgui_internal.h in imgui.h
|
||||
|
@ -123,6 +125,7 @@ struct ImBitVector; // Store 1-bit per value
|
|||
struct ImRect; // An axis-aligned rectangle (2 points)
|
||||
struct ImDrawDataBuilder; // Helper to build a ImDrawData instance
|
||||
struct ImDrawListSharedData; // Data shared between all ImDrawList instances
|
||||
struct ImGuiBoxSelectState; // Box-selection state (currently used by multi-selection, could potentially be used by others)
|
||||
struct ImGuiColorMod; // Stacked color modifier, backup of modified data so we can restore it
|
||||
struct ImGuiContext; // Main Dear ImGui context
|
||||
struct ImGuiContextHook; // Hook for extensions like ImGuiTestEngine
|
||||
|
@ -134,8 +137,9 @@ struct ImGuiInputTextDeactivateData;// Short term storage to backup text of a de
|
|||
struct ImGuiLastItemData; // Status storage for last submitted items
|
||||
struct ImGuiLocEntry; // A localization entry.
|
||||
struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only
|
||||
struct ImGuiMultiSelectState; // Multi-selection persistent state (for focused selection).
|
||||
struct ImGuiMultiSelectTempData; // Multi-selection temporary state (while traversing).
|
||||
struct ImGuiNavItemData; // Result of a gamepad/keyboard directional navigation move query result
|
||||
struct ImGuiNavTreeNodeData; // Temporary storage for last TreeNode() being a Left arrow landing candidate.
|
||||
struct ImGuiMetricsConfig; // Storage for ShowMetricsWindow() and DebugNodeXXX() functions
|
||||
struct ImGuiNextWindowData; // Storage for SetNextWindow** functions
|
||||
struct ImGuiNextItemData; // Storage for SetNextItem** functions
|
||||
|
@ -154,6 +158,7 @@ struct ImGuiTableInstanceData; // Storage for one instance of a same table
|
|||
struct ImGuiTableTempData; // Temporary storage for one table (one per table in the stack), shared between tables.
|
||||
struct ImGuiTableSettings; // Storage for a table .ini settings
|
||||
struct ImGuiTableColumnsSettings; // Storage for a column .ini settings
|
||||
struct ImGuiTreeNodeStackData; // Temporary storage for TreeNode().
|
||||
struct ImGuiTypingSelectState; // Storage for GetTypingSelectRequest()
|
||||
struct ImGuiTypingSelectRequest; // Storage for GetTypingSelectRequest() (aimed to be public)
|
||||
struct ImGuiWindow; // Storage for one window
|
||||
|
@ -169,7 +174,6 @@ typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // E
|
|||
typedef int ImGuiActivateFlags; // -> enum ImGuiActivateFlags_ // Flags: for navigation/focus function (will be for ActivateItem() later)
|
||||
typedef int ImGuiDebugLogFlags; // -> enum ImGuiDebugLogFlags_ // Flags: for ShowDebugLogWindow(), g.DebugLogFlags
|
||||
typedef int ImGuiFocusRequestFlags; // -> enum ImGuiFocusRequestFlags_ // Flags: for FocusWindow();
|
||||
typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag(), g.LastItemData.InFlags
|
||||
typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for g.LastItemData.StatusFlags
|
||||
typedef int ImGuiOldColumnFlags; // -> enum ImGuiOldColumnFlags_ // Flags: for BeginColumns()
|
||||
typedef int ImGuiNavHighlightFlags; // -> enum ImGuiNavHighlightFlags_ // Flags: for RenderNavHighlight()
|
||||
|
@ -348,6 +352,7 @@ namespace ImStb
|
|||
// - Helper: ImPool<>
|
||||
// - Helper: ImChunkStream<>
|
||||
// - Helper: ImGuiTextIndex
|
||||
// - Helper: ImGuiStorage
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Helpers: Hashing
|
||||
|
@ -384,6 +389,7 @@ IM_MSVC_RUNTIME_CHECKS_OFF
|
|||
static inline char ImToUpper(char c) { return (c >= 'a' && c <= 'z') ? c &= ~32 : c; }
|
||||
static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; }
|
||||
static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; }
|
||||
static inline bool ImCharIsXdigitA(char c) { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); }
|
||||
IM_MSVC_RUNTIME_CHECKS_RESTORE
|
||||
|
||||
// Helpers: Formatting
|
||||
|
@ -488,6 +494,7 @@ static inline int ImModPositive(int a, int b)
|
|||
static inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; }
|
||||
static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); }
|
||||
static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; }
|
||||
static inline float ImLinearRemapClamp(float s0, float s1, float d0, float d1, float x) { return ImSaturate((x - s0) / (s1 - s0)) * (d1 - d0) + d0; }
|
||||
static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
|
||||
static inline bool ImIsFloatAboveGuaranteedIntegerPrecision(float f) { return f <= -16777216 || f >= 16777216; }
|
||||
static inline float ImExponentialMovingAverage(float avg, float sample, int n) { avg -= avg / n; avg += sample / n; return avg; }
|
||||
|
@ -722,7 +729,7 @@ struct ImChunkStream
|
|||
void swap(ImChunkStream<T>& rhs) { rhs.Buf.swap(Buf); }
|
||||
};
|
||||
|
||||
// Helper: ImGuiTextIndex<>
|
||||
// Helper: ImGuiTextIndex
|
||||
// Maintain a line index for a text buffer. This is a strong candidate to be moved into the public API.
|
||||
struct ImGuiTextIndex
|
||||
{
|
||||
|
@ -736,6 +743,8 @@ struct ImGuiTextIndex
|
|||
void append(const char* base, int old_size, int new_size);
|
||||
};
|
||||
|
||||
// Helper: ImGuiStorage
|
||||
IMGUI_API ImGuiStoragePair* ImLowerBound(ImGuiStoragePair* in_begin, ImGuiStoragePair* in_end, ImGuiID key);
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] ImDrawList support
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -772,6 +781,7 @@ struct IMGUI_API ImDrawListSharedData
|
|||
ImVec2 TexUvWhitePixel; // UV of white pixel in the atlas
|
||||
ImFont* Font; // Current/default font (optional, for simplified AddText overload)
|
||||
float FontSize; // Current/default font size (optional, for simplified AddText overload)
|
||||
float FontScale; // Current/default font scale (== FontSize / Font->FontSize)
|
||||
float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo()
|
||||
float CircleSegmentMaxError; // Number of circle segments to use per pixel of radius for AddCircle() etc
|
||||
ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen()
|
||||
|
@ -798,33 +808,65 @@ struct ImDrawDataBuilder
|
|||
ImDrawDataBuilder() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Data types support
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct ImGuiDataVarInfo
|
||||
{
|
||||
ImGuiDataType Type;
|
||||
ImU32 Count; // 1+
|
||||
ImU32 Offset; // Offset in parent structure
|
||||
void* GetVarPtr(void* parent) const { return (void*)((unsigned char*)parent + Offset); }
|
||||
};
|
||||
|
||||
struct ImGuiDataTypeStorage
|
||||
{
|
||||
ImU8 Data[8]; // Opaque storage to fit any data up to ImGuiDataType_COUNT
|
||||
};
|
||||
|
||||
// Type information associated to one ImGuiDataType. Retrieve with DataTypeGetInfo().
|
||||
struct ImGuiDataTypeInfo
|
||||
{
|
||||
size_t Size; // Size in bytes
|
||||
const char* Name; // Short descriptive name for the type, for debugging
|
||||
const char* PrintFmt; // Default printf format for the type
|
||||
const char* ScanFmt; // Default scanf format for the type
|
||||
};
|
||||
|
||||
// Extend ImGuiDataType_
|
||||
enum ImGuiDataTypePrivate_
|
||||
{
|
||||
ImGuiDataType_String = ImGuiDataType_COUNT + 1,
|
||||
ImGuiDataType_Pointer,
|
||||
ImGuiDataType_ID,
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Widgets support: flags, enums, data structures
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Flags used by upcoming items
|
||||
// Extend ImGuiItemFlags
|
||||
// - input: PushItemFlag() manipulates g.CurrentItemFlags, ItemAdd() calls may add extra flags.
|
||||
// - output: stored in g.LastItemData.InFlags
|
||||
// Current window shared by all windows.
|
||||
// This is going to be exposed in imgui.h when stabilized enough.
|
||||
enum ImGuiItemFlags_
|
||||
enum ImGuiItemFlagsPrivate_
|
||||
{
|
||||
// Controlled by user
|
||||
ImGuiItemFlags_None = 0,
|
||||
ImGuiItemFlags_NoTabStop = 1 << 0, // false // Disable keyboard tabbing. This is a "lighter" version of ImGuiItemFlags_NoNav.
|
||||
ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings.
|
||||
ImGuiItemFlags_Disabled = 1 << 2, // false // Disable interactions but doesn't affect visuals. See BeginDisabled()/EndDisabled(). See github.com/ocornut/imgui/issues/211
|
||||
ImGuiItemFlags_NoNav = 1 << 3, // false // Disable any form of focusing (keyboard/gamepad directional navigation and SetKeyboardFocusHere() calls)
|
||||
ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false // Disable item being a candidate for default focus (e.g. used by title bar items)
|
||||
ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // Disable MenuItem/Selectable() automatically closing their popup window
|
||||
ImGuiItemFlags_MixedValue = 1 << 6, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets)
|
||||
ImGuiItemFlags_ReadOnly = 1 << 7, // false // [ALPHA] Allow hovering interactions but underlying value is not changed.
|
||||
ImGuiItemFlags_NoWindowHoverableCheck = 1 << 8, // false // Disable hoverable check in ItemHoverable()
|
||||
ImGuiItemFlags_AllowOverlap = 1 << 9, // false // Allow being overlapped by another widget. Not-hovered to Hovered transition deferred by a frame.
|
||||
ImGuiItemFlags_Disabled = 1 << 10, // false // Disable interactions (DOES NOT affect visuals, see BeginDisabled()/EndDisabled() for full disable feature, and github #211).
|
||||
ImGuiItemFlags_ReadOnly = 1 << 11, // false // [ALPHA] Allow hovering interactions but underlying value is not changed.
|
||||
ImGuiItemFlags_MixedValue = 1 << 12, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets)
|
||||
ImGuiItemFlags_NoWindowHoverableCheck = 1 << 13, // false // Disable hoverable check in ItemHoverable()
|
||||
ImGuiItemFlags_AllowOverlap = 1 << 14, // false // Allow being overlapped by another widget. Not-hovered to Hovered transition deferred by a frame.
|
||||
|
||||
// Controlled by widget code
|
||||
ImGuiItemFlags_Inputable = 1 << 10, // false // [WIP] Auto-activate input mode when tab focused. Currently only used and supported by a few items before it becomes a generic feature.
|
||||
ImGuiItemFlags_HasSelectionUserData = 1 << 11, // false // Set by SetNextItemSelectionUserData()
|
||||
ImGuiItemFlags_Inputable = 1 << 20, // false // [WIP] Auto-activate input mode when tab focused. Currently only used and supported by a few items before it becomes a generic feature.
|
||||
ImGuiItemFlags_HasSelectionUserData = 1 << 21, // false // Set by SetNextItemSelectionUserData()
|
||||
ImGuiItemFlags_IsMultiSelect = 1 << 22, // false // Set by SetNextItemSelectionUserData()
|
||||
|
||||
ImGuiItemFlags_Default_ = ImGuiItemFlags_AutoClosePopups, // Please don't change, use PushItemFlag() instead.
|
||||
|
||||
// Obsolete
|
||||
//ImGuiItemFlags_SelectableDontClosePopup = !ImGuiItemFlags_AutoClosePopups, // Can't have a redirect as we inverted the behavior
|
||||
};
|
||||
|
||||
// Status flags for an already submitted item
|
||||
|
@ -927,8 +969,9 @@ enum ImGuiSelectableFlagsPrivate_
|
|||
// Extend ImGuiTreeNodeFlags_
|
||||
enum ImGuiTreeNodeFlagsPrivate_
|
||||
{
|
||||
ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 20,
|
||||
ImGuiTreeNodeFlags_UpsideDownArrow = 1 << 21,// (FIXME-WIP) Turn Down arrow into an Up arrow, but reversed trees (#6517)
|
||||
ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 28,// FIXME-WIP: Hard-coded for CollapsingHeader()
|
||||
ImGuiTreeNodeFlags_UpsideDownArrow = 1 << 29,// FIXME-WIP: Turn Down arrow into an Up arrow, but reversed trees (#6517)
|
||||
ImGuiTreeNodeFlags_OpenOnMask_ = ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_OpenOnArrow,
|
||||
};
|
||||
|
||||
enum ImGuiSeparatorFlags_
|
||||
|
@ -1079,7 +1122,7 @@ struct IMGUI_API ImGuiInputTextState
|
|||
ImVector<char> InitialTextA; // value to revert to when pressing Escape = backup of end-user buffer at the time of focus (in UTF-8, unaltered)
|
||||
bool TextAIsValid; // temporary UTF8 buffer is not initially valid before we make the widget active (until then we pull the data from user argument)
|
||||
int BufCapacityA; // end-user buffer capacity
|
||||
float ScrollX; // horizontal scrolling/offset
|
||||
ImVec2 Scroll; // horizontal offset (managed manually) + vertical scrolling (pulled from child window's own Scroll.y)
|
||||
ImStb::STB_TexteditState Stb; // state for stb_textedit.h
|
||||
float CursorAnim; // timer for cursor blink, reset on every user action so the cursor reappears immediately
|
||||
bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!)
|
||||
|
@ -1167,29 +1210,30 @@ struct ImGuiNextWindowData
|
|||
inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; }
|
||||
};
|
||||
|
||||
// Multi-Selection item index or identifier when using SetNextItemSelectionUserData()/BeginMultiSelect()
|
||||
// (Most users are likely to use this store an item INDEX but this may be used to store a POINTER as well.)
|
||||
typedef ImS64 ImGuiSelectionUserData;
|
||||
|
||||
enum ImGuiNextItemDataFlags_
|
||||
{
|
||||
ImGuiNextItemDataFlags_None = 0,
|
||||
ImGuiNextItemDataFlags_HasWidth = 1 << 0,
|
||||
ImGuiNextItemDataFlags_HasOpen = 1 << 1,
|
||||
ImGuiNextItemDataFlags_HasShortcut = 1 << 2,
|
||||
ImGuiNextItemDataFlags_HasRefVal = 1 << 3,
|
||||
ImGuiNextItemDataFlags_HasStorageID = 1 << 4,
|
||||
};
|
||||
|
||||
struct ImGuiNextItemData
|
||||
{
|
||||
ImGuiNextItemDataFlags Flags;
|
||||
ImGuiItemFlags ItemFlags; // Currently only tested/used for ImGuiItemFlags_AllowOverlap.
|
||||
ImGuiItemFlags ItemFlags; // Currently only tested/used for ImGuiItemFlags_AllowOverlap and ImGuiItemFlags_HasSelectionUserData.
|
||||
// Non-flags members are NOT cleared by ItemAdd() meaning they are still valid during NavProcessItem()
|
||||
ImGuiID FocusScopeId; // Set by SetNextItemSelectionUserData()
|
||||
ImGuiSelectionUserData SelectionUserData; // Set by SetNextItemSelectionUserData() (note that NULL/0 is a valid value, we use -1 == ImGuiSelectionUserData_Invalid to mark invalid values)
|
||||
float Width; // Set by SetNextItemWidth()
|
||||
ImGuiKeyChord Shortcut; // Set by SetNextItemShortcut()
|
||||
ImGuiInputFlags ShortcutFlags; // Set by SetNextItemShortcut()
|
||||
bool OpenVal; // Set by SetNextItemOpen()
|
||||
ImGuiCond OpenCond : 8;
|
||||
ImU8 OpenCond; // Set by SetNextItemOpen()
|
||||
ImGuiDataTypeStorage RefVal; // Not exposed yet, for ImGuiInputTextFlags_ParseEmptyAsRefVal
|
||||
ImGuiID StorageId; // Set by SetNextItemStorageID()
|
||||
|
||||
ImGuiNextItemData() { memset(this, 0, sizeof(*this)); SelectionUserData = -1; }
|
||||
inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; ItemFlags = ImGuiItemFlags_None; } // Also cleared manually by ItemAdd()!
|
||||
|
@ -1211,14 +1255,16 @@ struct ImGuiLastItemData
|
|||
ImGuiLastItemData() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
// Store data emitted by TreeNode() for usage by TreePop() to implement ImGuiTreeNodeFlags_NavLeftJumpsBackHere.
|
||||
// This is the minimum amount of data that we need to perform the equivalent of NavApplyItemToResult() and which we can't infer in TreePop()
|
||||
// Store data emitted by TreeNode() for usage by TreePop()
|
||||
// - To implement ImGuiTreeNodeFlags_NavLeftJumpsBackHere: store the minimum amount of data
|
||||
// which we can't infer in TreePop(), to perform the equivalent of NavApplyItemToResult().
|
||||
// Only stored when the node is a potential candidate for landing on a Left arrow jump.
|
||||
struct ImGuiNavTreeNodeData
|
||||
struct ImGuiTreeNodeStackData
|
||||
{
|
||||
ImGuiID ID;
|
||||
ImGuiItemFlags InFlags;
|
||||
ImRect NavRect;
|
||||
ImGuiTreeNodeFlags TreeFlags;
|
||||
ImGuiItemFlags InFlags; // Used for nav landing
|
||||
ImRect NavRect; // Used for nav landing
|
||||
};
|
||||
|
||||
struct IMGUI_API ImGuiStackSizes
|
||||
|
@ -1263,40 +1309,6 @@ struct ImGuiPtrOrIndex
|
|||
ImGuiPtrOrIndex(int index) { Ptr = NULL; Index = index; }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Data types support
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct ImGuiDataVarInfo
|
||||
{
|
||||
ImGuiDataType Type;
|
||||
ImU32 Count; // 1+
|
||||
ImU32 Offset; // Offset in parent structure
|
||||
void* GetVarPtr(void* parent) const { return (void*)((unsigned char*)parent + Offset); }
|
||||
};
|
||||
|
||||
struct ImGuiDataTypeTempStorage
|
||||
{
|
||||
ImU8 Data[8]; // Can fit any data up to ImGuiDataType_COUNT
|
||||
};
|
||||
|
||||
// Type information associated to one ImGuiDataType. Retrieve with DataTypeGetInfo().
|
||||
struct ImGuiDataTypeInfo
|
||||
{
|
||||
size_t Size; // Size in bytes
|
||||
const char* Name; // Short descriptive name for the type, for debugging
|
||||
const char* PrintFmt; // Default printf format for the type
|
||||
const char* ScanFmt; // Default scanf format for the type
|
||||
};
|
||||
|
||||
// Extend ImGuiDataType_
|
||||
enum ImGuiDataTypePrivate_
|
||||
{
|
||||
ImGuiDataType_String = ImGuiDataType_COUNT + 1,
|
||||
ImGuiDataType_Pointer,
|
||||
ImGuiDataType_ID,
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Popup support
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -1347,8 +1359,8 @@ typedef ImBitArray<ImGuiKey_NamedKey_COUNT, -ImGuiKey_NamedKey_BEGIN> ImBitAr
|
|||
#define ImGuiKey_NavKeyboardTweakFast ImGuiMod_Shift
|
||||
#define ImGuiKey_NavGamepadTweakSlow ImGuiKey_GamepadL1
|
||||
#define ImGuiKey_NavGamepadTweakFast ImGuiKey_GamepadR1
|
||||
#define ImGuiKey_NavGamepadActivate ImGuiKey_GamepadFaceDown
|
||||
#define ImGuiKey_NavGamepadCancel ImGuiKey_GamepadFaceRight
|
||||
#define ImGuiKey_NavGamepadActivate (g.IO.ConfigNavSwapGamepadButtons ? ImGuiKey_GamepadFaceRight : ImGuiKey_GamepadFaceDown)
|
||||
#define ImGuiKey_NavGamepadCancel (g.IO.ConfigNavSwapGamepadButtons ? ImGuiKey_GamepadFaceDown : ImGuiKey_GamepadFaceRight)
|
||||
#define ImGuiKey_NavGamepadMenu ImGuiKey_GamepadFaceLeft
|
||||
#define ImGuiKey_NavGamepadInput ImGuiKey_GamepadFaceUp
|
||||
|
||||
|
@ -1594,7 +1606,7 @@ struct ImGuiNavItemData
|
|||
float DistBox; // Move // Best candidate box distance to current NavId
|
||||
float DistCenter; // Move // Best candidate center distance to current NavId
|
||||
float DistAxial; // Move // Best candidate axial distance to current NavId
|
||||
ImGuiSelectionUserData SelectionUserData;//I+Mov // Best candidate SetNextItemSelectionData() value.
|
||||
ImGuiSelectionUserData SelectionUserData;//I+Mov // Best candidate SetNextItemSelectionUserData() value. Valid if (InFlags & ImGuiItemFlags_HasSelectionUserData)
|
||||
|
||||
ImGuiNavItemData() { Clear(); }
|
||||
void Clear() { Window = NULL; ID = FocusScopeId = 0; InFlags = 0; SelectionUserData = -1; DistBox = DistCenter = DistAxial = FLT_MAX; }
|
||||
|
@ -1700,6 +1712,34 @@ struct ImGuiOldColumns
|
|||
ImGuiOldColumns() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Box-select support
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct ImGuiBoxSelectState
|
||||
{
|
||||
// Active box-selection data (persistent, 1 active at a time)
|
||||
ImGuiID ID;
|
||||
bool IsActive;
|
||||
bool IsStarting;
|
||||
bool IsStartedFromVoid; // Starting click was not from an item.
|
||||
bool IsStartedSetNavIdOnce;
|
||||
bool RequestClear;
|
||||
ImGuiKeyChord KeyMods : 16; // Latched key-mods for box-select logic.
|
||||
ImVec2 StartPosRel; // Start position in window-contents relative space (to support scrolling)
|
||||
ImVec2 EndPosRel; // End position in window-contents relative space
|
||||
ImVec2 ScrollAccum; // Scrolling accumulator (to behave at high-frame spaces)
|
||||
ImGuiWindow* Window;
|
||||
|
||||
// Temporary/Transient data
|
||||
bool UnclipMode; // (Temp/Transient, here in hot area). Set/cleared by the BeginMultiSelect()/EndMultiSelect() owning active box-select.
|
||||
ImRect UnclipRect; // Rectangle where ItemAdd() clipping may be temporarily disabled. Need support by multi-select supporting widgets.
|
||||
ImRect BoxSelectRectPrev; // Selection rectangle in absolute coordinates (derived every frame from BoxSelectStartPosRel and MousePos)
|
||||
ImRect BoxSelectRectCurr;
|
||||
|
||||
ImGuiBoxSelectState() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Multi-select support
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -1707,9 +1747,45 @@ struct ImGuiOldColumns
|
|||
// We always assume that -1 is an invalid value (which works for indices and pointers)
|
||||
#define ImGuiSelectionUserData_Invalid ((ImGuiSelectionUserData)-1)
|
||||
|
||||
#ifdef IMGUI_HAS_MULTI_SELECT
|
||||
// <this is filled in 'range_select' branch>
|
||||
#endif // #ifdef IMGUI_HAS_MULTI_SELECT
|
||||
// Temporary storage for multi-select
|
||||
struct IMGUI_API ImGuiMultiSelectTempData
|
||||
{
|
||||
ImGuiMultiSelectIO IO; // MUST BE FIRST FIELD. Requests are set and returned by BeginMultiSelect()/EndMultiSelect() + written to by user during the loop.
|
||||
ImGuiMultiSelectState* Storage;
|
||||
ImGuiID FocusScopeId; // Copied from g.CurrentFocusScopeId (unless another selection scope was pushed manually)
|
||||
ImGuiMultiSelectFlags Flags;
|
||||
ImVec2 ScopeRectMin;
|
||||
ImVec2 BackupCursorMaxPos;
|
||||
ImGuiSelectionUserData LastSubmittedItem; // Copy of last submitted item data, used to merge output ranges.
|
||||
ImGuiID BoxSelectId;
|
||||
ImGuiKeyChord KeyMods;
|
||||
ImS8 LoopRequestSetAll; // -1: no operation, 0: clear all, 1: select all.
|
||||
bool IsEndIO; // Set when switching IO from BeginMultiSelect() to EndMultiSelect() state.
|
||||
bool IsFocused; // Set if currently focusing the selection scope (any item of the selection). May be used if you have custom shortcut associated to selection.
|
||||
bool IsKeyboardSetRange; // Set by BeginMultiSelect() when using Shift+Navigation. Because scrolling may be affected we can't afford a frame of lag with Shift+Navigation.
|
||||
bool NavIdPassedBy;
|
||||
bool RangeSrcPassedBy; // Set by the item that matches RangeSrcItem.
|
||||
bool RangeDstPassedBy; // Set by the item that matches NavJustMovedToId when IsSetRange is set.
|
||||
|
||||
ImGuiMultiSelectTempData() { Clear(); }
|
||||
void Clear() { size_t io_sz = sizeof(IO); ClearIO(); memset((void*)(&IO + 1), 0, sizeof(*this) - io_sz); } // Zero-clear except IO as we preserve IO.Requests[] buffer allocation.
|
||||
void ClearIO() { IO.Requests.resize(0); IO.RangeSrcItem = IO.NavIdItem = ImGuiSelectionUserData_Invalid; IO.NavIdSelected = IO.RangeSrcReset = false; }
|
||||
};
|
||||
|
||||
// Persistent storage for multi-select (as long as selection is alive)
|
||||
struct IMGUI_API ImGuiMultiSelectState
|
||||
{
|
||||
ImGuiWindow* Window;
|
||||
ImGuiID ID;
|
||||
int LastFrameActive; // Last used frame-count, for GC.
|
||||
int LastSelectionSize; // Set by BeginMultiSelect() based on optional info provided by user. May be -1 if unknown.
|
||||
ImS8 RangeSelected; // -1 (don't have) or true/false
|
||||
ImS8 NavIdSelected; // -1 (don't have) or true/false
|
||||
ImGuiSelectionUserData RangeSrcItem; //
|
||||
ImGuiSelectionUserData NavIdItem; // SetNextItemSelectionUserData() value for NavId (if part of submitted items)
|
||||
|
||||
ImGuiMultiSelectState() { Window = NULL; ID = 0; LastFrameActive = LastSelectionSize = 0; RangeSelected = NavIdSelected = -1; RangeSrcItem = NavIdItem = ImGuiSelectionUserData_Invalid; }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Docking support
|
||||
|
@ -1731,23 +1807,28 @@ struct ImGuiViewportP : public ImGuiViewport
|
|||
ImDrawList* BgFgDrawLists[2]; // Convenience background (0) and foreground (1) draw lists. We use them to draw software mouser cursor when io.MouseDrawCursor is set and to draw most debug overlays.
|
||||
ImDrawData DrawDataP;
|
||||
ImDrawDataBuilder DrawDataBuilder; // Temporary data while building final ImDrawData
|
||||
ImVec2 WorkOffsetMin; // Work Area: Offset from Pos to top-left corner of Work Area. Generally (0,0) or (0,+main_menu_bar_height). Work Area is Full Area but without menu-bars/status-bars (so WorkArea always fit inside Pos/Size!)
|
||||
ImVec2 WorkOffsetMax; // Work Area: Offset from Pos+Size to bottom-right corner of Work Area. Generally (0,0) or (0,-status_bar_height).
|
||||
ImVec2 BuildWorkOffsetMin; // Work Area: Offset being built during current frame. Generally >= 0.0f.
|
||||
ImVec2 BuildWorkOffsetMax; // Work Area: Offset being built during current frame. Generally <= 0.0f.
|
||||
|
||||
// Per-viewport work area
|
||||
// - Insets are >= 0.0f values, distance from viewport corners to work area.
|
||||
// - BeginMainMenuBar() and DockspaceOverViewport() tend to use work area to avoid stepping over existing contents.
|
||||
// - Generally 'safeAreaInsets' in iOS land, 'DisplayCutout' in Android land.
|
||||
ImVec2 WorkInsetMin; // Work Area inset locked for the frame. GetWorkRect() always fits within GetMainRect().
|
||||
ImVec2 WorkInsetMax; // "
|
||||
ImVec2 BuildWorkInsetMin; // Work Area inset accumulator for current frame, to become next frame's WorkInset
|
||||
ImVec2 BuildWorkInsetMax; // "
|
||||
|
||||
ImGuiViewportP() { BgFgDrawListsLastFrame[0] = BgFgDrawListsLastFrame[1] = -1; BgFgDrawLists[0] = BgFgDrawLists[1] = NULL; }
|
||||
~ImGuiViewportP() { if (BgFgDrawLists[0]) IM_DELETE(BgFgDrawLists[0]); if (BgFgDrawLists[1]) IM_DELETE(BgFgDrawLists[1]); }
|
||||
|
||||
// Calculate work rect pos/size given a set of offset (we have 1 pair of offset for rect locked from last frame data, and 1 pair for currently building rect)
|
||||
ImVec2 CalcWorkRectPos(const ImVec2& off_min) const { return ImVec2(Pos.x + off_min.x, Pos.y + off_min.y); }
|
||||
ImVec2 CalcWorkRectSize(const ImVec2& off_min, const ImVec2& off_max) const { return ImVec2(ImMax(0.0f, Size.x - off_min.x + off_max.x), ImMax(0.0f, Size.y - off_min.y + off_max.y)); }
|
||||
void UpdateWorkRect() { WorkPos = CalcWorkRectPos(WorkOffsetMin); WorkSize = CalcWorkRectSize(WorkOffsetMin, WorkOffsetMax); } // Update public fields
|
||||
ImVec2 CalcWorkRectPos(const ImVec2& inset_min) const { return ImVec2(Pos.x + inset_min.x, Pos.y + inset_min.y); }
|
||||
ImVec2 CalcWorkRectSize(const ImVec2& inset_min, const ImVec2& inset_max) const { return ImVec2(ImMax(0.0f, Size.x - inset_min.x - inset_max.x), ImMax(0.0f, Size.y - inset_min.y - inset_max.y)); }
|
||||
void UpdateWorkRect() { WorkPos = CalcWorkRectPos(WorkInsetMin); WorkSize = CalcWorkRectSize(WorkInsetMin, WorkInsetMax); } // Update public fields
|
||||
|
||||
// Helpers to retrieve ImRect (we don't need to store BuildWorkRect as every access tend to change it, hence the code asymmetry)
|
||||
ImRect GetMainRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }
|
||||
ImRect GetWorkRect() const { return ImRect(WorkPos.x, WorkPos.y, WorkPos.x + WorkSize.x, WorkPos.y + WorkSize.y); }
|
||||
ImRect GetBuildWorkRect() const { ImVec2 pos = CalcWorkRectPos(BuildWorkOffsetMin); ImVec2 size = CalcWorkRectSize(BuildWorkOffsetMin, BuildWorkOffsetMax); return ImRect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); }
|
||||
ImRect GetBuildWorkRect() const { ImVec2 pos = CalcWorkRectPos(BuildWorkInsetMin); ImVec2 size = CalcWorkRectSize(BuildWorkInsetMin, BuildWorkInsetMax); return ImRect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -1801,6 +1882,7 @@ enum ImGuiLocKey : int
|
|||
ImGuiLocKey_WindowingMainMenuBar,
|
||||
ImGuiLocKey_WindowingPopup,
|
||||
ImGuiLocKey_WindowingUntitled,
|
||||
ImGuiLocKey_CopyLink,
|
||||
ImGuiLocKey_COUNT
|
||||
};
|
||||
|
||||
|
@ -1918,10 +2000,12 @@ struct ImGuiContext
|
|||
bool Initialized;
|
||||
bool FontAtlasOwnedByContext; // IO.Fonts-> is owned by the ImGuiContext and will be destructed along with it.
|
||||
ImGuiIO IO;
|
||||
ImGuiPlatformIO PlatformIO;
|
||||
ImGuiStyle Style;
|
||||
ImFont* Font; // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back()
|
||||
float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window.
|
||||
float FontBaseSize; // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Base text height.
|
||||
float FontScale; // == FontSize / Font->FontSize
|
||||
float CurrentDpiScale; // Current window/viewport DpiScale
|
||||
ImDrawListSharedData DrawListSharedData;
|
||||
double Time;
|
||||
|
@ -1934,6 +2018,7 @@ struct ImGuiContext
|
|||
bool GcCompactAll; // Request full GC
|
||||
bool TestEngineHookItems; // Will call test engine hooks: ImGuiTestEngineHook_ItemAdd(), ImGuiTestEngineHook_ItemInfo(), ImGuiTestEngineHook_Log()
|
||||
void* TestEngine; // Test engine user data
|
||||
char ContextName[16]; // Storage for a context name (to facilitate debugging multi-context setups)
|
||||
|
||||
// Inputs
|
||||
ImVector<ImGuiInputEvent> InputEventsQueue; // Input events which will be trickled/written into IO structure.
|
||||
|
@ -1953,6 +2038,7 @@ struct ImGuiContext
|
|||
ImGuiWindow* CurrentWindow; // Window being drawn into
|
||||
ImGuiWindow* HoveredWindow; // Window the mouse is hovering. Will typically catch mouse inputs.
|
||||
ImGuiWindow* HoveredWindowUnderMovingWindow; // Hovered window ignoring MovingWindow. Only set if MovingWindow is set.
|
||||
ImGuiWindow* HoveredWindowBeforeClear; // Window the mouse is hovering. Filled even with _NoMouse. This is currently useful for multi-context compositors.
|
||||
ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actual window that is moved is generally MovingWindow->RootWindow.
|
||||
ImGuiWindow* WheelingWindow; // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window.
|
||||
ImVec2 WheelingWindowRefMousePos;
|
||||
|
@ -1969,7 +2055,7 @@ struct ImGuiContext
|
|||
float HoveredIdTimer; // Measure contiguous hovering time
|
||||
float HoveredIdNotActiveTimer; // Measure contiguous hovering time where the item has not been active
|
||||
bool HoveredIdAllowOverlap;
|
||||
bool HoveredIdDisabled; // At least one widget passed the rect test, but has been discarded by disabled flag or popup inhibit. May be true even if HoveredId == 0.
|
||||
bool HoveredIdIsDisabled; // At least one widget passed the rect test, but has been discarded by disabled flag or popup inhibit. May be true even if HoveredId == 0.
|
||||
bool ItemUnclipByLog; // Disable ItemAdd() clipping, essentially a memory-locality friendly copy of LogEnabled
|
||||
ImGuiID ActiveId; // Active widget
|
||||
ImGuiID ActiveIdIsAlive; // Active widget has been seen this frame (we can't use a bool as the ActiveId may change within the frame)
|
||||
|
@ -2003,11 +2089,9 @@ struct ImGuiContext
|
|||
ImGuiKeyOwnerData KeysOwnerData[ImGuiKey_NamedKey_COUNT];
|
||||
ImGuiKeyRoutingTable KeysRoutingTable;
|
||||
ImU32 ActiveIdUsingNavDirMask; // Active widget will want to read those nav move requests (e.g. can activate a button and move away from it)
|
||||
bool ActiveIdUsingAllKeyboardKeys; // Active widget will want to read all keyboard keys inputs. (FIXME: This is a shortcut for not taking ownership of 100+ keys but perhaps best to not have the inconsistency)
|
||||
bool ActiveIdUsingAllKeyboardKeys; // Active widget will want to read all keyboard keys inputs. (this is a shortcut for not taking ownership of 100+ keys, frequently used by drag operations)
|
||||
ImGuiKeyChord DebugBreakInShortcutRouting; // Set to break in SetShortcutRouting()/Shortcut() calls.
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
|
||||
ImU32 ActiveIdUsingNavInputMask; // If you used this. Since (IMGUI_VERSION_NUM >= 18804) : 'g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel);' becomes 'SetKeyOwner(ImGuiKey_Escape, g.ActiveId) and/or SetKeyOwner(ImGuiKey_NavGamepadCancel, g.ActiveId);'
|
||||
#endif
|
||||
//ImU32 ActiveIdUsingNavInputMask; // [OBSOLETE] Since (IMGUI_VERSION_NUM >= 18804) : 'g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel);' becomes --> 'SetKeyOwner(ImGuiKey_Escape, g.ActiveId) and/or SetKeyOwner(ImGuiKey_NavGamepadCancel, g.ActiveId);'
|
||||
|
||||
// Next window/item data
|
||||
ImGuiID CurrentFocusScopeId; // Value for currently appending items == g.FocusScopeStack.back(). Not to be mistaken with g.NavFocusScopeId.
|
||||
|
@ -2028,7 +2112,7 @@ struct ImGuiContext
|
|||
ImVector<ImGuiGroupData> GroupStack; // Stack for BeginGroup()/EndGroup() - not inherited by Begin()
|
||||
ImVector<ImGuiPopupData> OpenPopupStack; // Which popups are open (persistent)
|
||||
ImVector<ImGuiPopupData> BeginPopupStack; // Which level of BeginPopup() we are in (reset every frame)
|
||||
ImVector<ImGuiNavTreeNodeData> NavTreeNodeStack; // Stack for TreeNode() when a NavLeft requested is emitted.
|
||||
ImVector<ImGuiTreeNodeStackData>TreeNodeStack; // Stack for TreeNode()
|
||||
|
||||
// Viewports
|
||||
ImVector<ImGuiViewportP*> Viewports; // Active viewports (Size==1 in 'master' branch). Each viewports hold their copy of ImDrawData.
|
||||
|
@ -2037,6 +2121,7 @@ struct ImGuiContext
|
|||
ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusedWindow'
|
||||
ImGuiID NavId; // Focused item for navigation
|
||||
ImGuiID NavFocusScopeId; // Focused focus scope (e.g. selection code often wants to "clear other items" when landing on an item of the same scope)
|
||||
ImGuiNavLayer NavLayer; // Focused layer (main scrolling layer, or menu/title bar layer)
|
||||
ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && (IsKeyPressed(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate)) ? NavId : 0, also set when calling ActivateItem()
|
||||
ImGuiID NavActivateDownId; // ~~ IsKeyDown(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyDown(ImGuiKey_NavGamepadActivate) ? NavId : 0
|
||||
ImGuiID NavActivatePressedId; // ~~ IsKeyPressed(ImGuiKey_Space) || IsKeyPressed(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate) ? NavId : 0 (no repeat)
|
||||
|
@ -2044,13 +2129,9 @@ struct ImGuiContext
|
|||
ImVector<ImGuiFocusScopeData> NavFocusRoute; // Reversed copy focus scope stack for NavId (should contains NavFocusScopeId). This essentially follow the window->ParentWindowForFocusRoute chain.
|
||||
ImGuiID NavHighlightActivatedId;
|
||||
float NavHighlightActivatedTimer;
|
||||
ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest).
|
||||
ImGuiID NavJustMovedToFocusScopeId; // Just navigated to this focus scope id (result of a successfully MoveRequest).
|
||||
ImGuiKeyChord NavJustMovedToKeyMods;
|
||||
ImGuiID NavNextActivateId; // Set by ActivateItem(), queued until next frame.
|
||||
ImGuiActivateFlags NavNextActivateFlags;
|
||||
ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS CAN ONLY BE ImGuiInputSource_Keyboard or ImGuiInputSource_Mouse
|
||||
ImGuiNavLayer NavLayer; // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later.
|
||||
ImGuiSelectionUserData NavLastValidSelectionUserData; // Last valid data passed to SetNextItemSelectionUser(), or -1. For current window. Not reset when focusing an item that doesn't have selection data.
|
||||
bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRectRel is valid
|
||||
bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default)
|
||||
|
@ -2081,6 +2162,14 @@ struct ImGuiContext
|
|||
ImGuiNavItemData NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag)
|
||||
ImGuiNavItemData NavTabbingResultFirst; // First tabbing request candidate within NavWindow and flattened hierarchy
|
||||
|
||||
// Navigation: record of last move request
|
||||
ImGuiID NavJustMovedFromFocusScopeId; // Just navigated from this focus scope id (result of a successfully MoveRequest).
|
||||
ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest).
|
||||
ImGuiID NavJustMovedToFocusScopeId; // Just navigated to this focus scope id (result of a successfully MoveRequest).
|
||||
ImGuiKeyChord NavJustMovedToKeyMods;
|
||||
bool NavJustMovedToIsTabbing; // Copy of ImGuiNavMoveFlags_IsTabbing. Maybe we should store whole flags.
|
||||
bool NavJustMovedToHasSelectionData; // Copy of move result's InFlags & ImGuiItemFlags_HasSelectionUserData). Maybe we should just store ImGuiNavItemData.
|
||||
|
||||
// Navigation: Windowing (CTRL+TAB for list, or Menu button + keys or directional pads to move/resize)
|
||||
ImGuiKeyChord ConfigNavWindowingKeyNext; // = ImGuiMod_Ctrl | ImGuiKey_Tab (or ImGuiMod_Super | ImGuiKey_Tab on OS X). For reconfiguration (see #4828)
|
||||
ImGuiKeyChord ConfigNavWindowingKeyPrev; // = ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab (or ImGuiMod_Super | ImGuiMod_Shift | ImGuiKey_Tab on OS X)
|
||||
|
@ -2136,6 +2225,13 @@ struct ImGuiContext
|
|||
ImVector<ImGuiPtrOrIndex> CurrentTabBarStack;
|
||||
ImVector<ImGuiShrinkWidthItem> ShrinkWidthBuffer;
|
||||
|
||||
// Multi-Select state
|
||||
ImGuiBoxSelectState BoxSelectState;
|
||||
ImGuiMultiSelectTempData* CurrentMultiSelect;
|
||||
int MultiSelectTempDataStacked; // Temporary multi-select data size (because we leave previous instances undestructed, we generally don't use MultiSelectTempData.Size)
|
||||
ImVector<ImGuiMultiSelectTempData> MultiSelectTempData;
|
||||
ImPool<ImGuiMultiSelectState> MultiSelectStorage;
|
||||
|
||||
// Hover Delay system
|
||||
ImGuiID HoverItemDelayId;
|
||||
ImGuiID HoverItemDelayIdPreviousFrame;
|
||||
|
@ -2154,6 +2250,7 @@ struct ImGuiContext
|
|||
ImGuiInputTextDeactivatedState InputTextDeactivatedState;
|
||||
ImFont InputTextPasswordFont;
|
||||
ImGuiID TempInputId; // Temporary text input when CTRL+clicking on a slider, etc.
|
||||
ImGuiDataTypeStorage DataTypeZeroValue; // 0 for all data types
|
||||
int BeginMenuDepth;
|
||||
int BeginComboDepth;
|
||||
ImGuiColorEditFlags ColorEditOptions; // Store user options for color edit widgets
|
||||
|
@ -2184,7 +2281,7 @@ struct ImGuiContext
|
|||
|
||||
// Platform support
|
||||
ImGuiPlatformImeData PlatformImeData; // Data updated by current frame
|
||||
ImGuiPlatformImeData PlatformImeDataPrev; // Previous frame data (when changing we will call io.SetPlatformImeDataFn
|
||||
ImGuiPlatformImeData PlatformImeDataPrev; // Previous frame data. When changed we call the platform_io.Platform_SetImeDataFn() handler.
|
||||
|
||||
// Settings
|
||||
bool SettingsLoaded;
|
||||
|
@ -2251,7 +2348,7 @@ struct ImGuiContext
|
|||
Initialized = false;
|
||||
FontAtlasOwnedByContext = shared_font_atlas ? false : true;
|
||||
Font = NULL;
|
||||
FontSize = FontBaseSize = CurrentDpiScale = 0.0f;
|
||||
FontSize = FontBaseSize = FontScale = CurrentDpiScale = 0.0f;
|
||||
IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)();
|
||||
Time = 0.0f;
|
||||
FrameCount = 0;
|
||||
|
@ -2260,6 +2357,7 @@ struct ImGuiContext
|
|||
GcCompactAll = false;
|
||||
TestEngineHookItems = false;
|
||||
TestEngine = NULL;
|
||||
memset(ContextName, 0, sizeof(ContextName));
|
||||
|
||||
InputEventsNextMouseSource = ImGuiMouseSource_Mouse;
|
||||
InputEventsNextEventId = 1;
|
||||
|
@ -2268,6 +2366,7 @@ struct ImGuiContext
|
|||
CurrentWindow = NULL;
|
||||
HoveredWindow = NULL;
|
||||
HoveredWindowUnderMovingWindow = NULL;
|
||||
HoveredWindowBeforeClear = NULL;
|
||||
MovingWindow = NULL;
|
||||
WheelingWindow = NULL;
|
||||
WheelingWindowStartFrame = WheelingWindowScrolledFrame = -1;
|
||||
|
@ -2276,7 +2375,7 @@ struct ImGuiContext
|
|||
DebugHookIdInfo = 0;
|
||||
HoveredId = HoveredIdPreviousFrame = 0;
|
||||
HoveredIdAllowOverlap = false;
|
||||
HoveredIdDisabled = false;
|
||||
HoveredIdIsDisabled = false;
|
||||
HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f;
|
||||
ItemUnclipByLog = false;
|
||||
ActiveId = 0;
|
||||
|
@ -2304,9 +2403,6 @@ struct ImGuiContext
|
|||
|
||||
ActiveIdUsingNavDirMask = 0x00;
|
||||
ActiveIdUsingAllKeyboardKeys = false;
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
|
||||
ActiveIdUsingNavInputMask = 0x00;
|
||||
#endif
|
||||
|
||||
CurrentFocusScopeId = 0;
|
||||
CurrentItemFlags = ImGuiItemFlags_None;
|
||||
|
@ -2314,18 +2410,18 @@ struct ImGuiContext
|
|||
|
||||
NavWindow = NULL;
|
||||
NavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = 0;
|
||||
NavJustMovedToId = NavJustMovedToFocusScopeId = NavNextActivateId = 0;
|
||||
NavLayer = ImGuiNavLayer_Main;
|
||||
NavNextActivateId = 0;
|
||||
NavActivateFlags = NavNextActivateFlags = ImGuiActivateFlags_None;
|
||||
NavHighlightActivatedId = 0;
|
||||
NavHighlightActivatedTimer = 0.0f;
|
||||
NavJustMovedToKeyMods = ImGuiMod_None;
|
||||
NavInputSource = ImGuiInputSource_Keyboard;
|
||||
NavLayer = ImGuiNavLayer_Main;
|
||||
NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid;
|
||||
NavIdIsAlive = false;
|
||||
NavMousePosDirty = false;
|
||||
NavDisableHighlight = true;
|
||||
NavDisableMouseHover = false;
|
||||
|
||||
NavAnyRequest = false;
|
||||
NavInitRequest = false;
|
||||
NavInitRequestFromMove = false;
|
||||
|
@ -2340,6 +2436,11 @@ struct ImGuiContext
|
|||
NavTabbingDir = 0;
|
||||
NavTabbingCounter = 0;
|
||||
|
||||
NavJustMovedFromFocusScopeId = NavJustMovedToId = NavJustMovedToFocusScopeId = 0;
|
||||
NavJustMovedToKeyMods = ImGuiMod_None;
|
||||
NavJustMovedToIsTabbing = false;
|
||||
NavJustMovedToHasSelectionData = false;
|
||||
|
||||
// All platforms use Ctrl+Tab but Ctrl<>Super are swapped on Mac...
|
||||
// FIXME: Because this value is stored, it annoyingly interfere with toggling io.ConfigMacOSXBehaviors updating this..
|
||||
ConfigNavWindowingKeyNext = IO.ConfigMacOSXBehaviors ? (ImGuiMod_Super | ImGuiKey_Tab) : (ImGuiMod_Ctrl | ImGuiKey_Tab);
|
||||
|
@ -2368,6 +2469,8 @@ struct ImGuiContext
|
|||
CurrentTable = NULL;
|
||||
TablesTempDataStacked = 0;
|
||||
CurrentTabBar = NULL;
|
||||
CurrentMultiSelect = NULL;
|
||||
MultiSelectTempDataStacked = 0;
|
||||
|
||||
HoverItemDelayId = HoverItemDelayIdPreviousFrame = HoverItemUnlockedStationaryId = HoverWindowUnlockedStationaryId = 0;
|
||||
HoverItemDelayTimer = HoverItemDelayClearTimer = 0.0f;
|
||||
|
@ -2376,6 +2479,7 @@ struct ImGuiContext
|
|||
MouseStationaryTimer = 0.0f;
|
||||
|
||||
TempInputId = 0;
|
||||
memset(&DataTypeZeroValue, 0, sizeof(DataTypeZeroValue));
|
||||
BeginMenuDepth = BeginComboDepth = 0;
|
||||
ColorEditOptions = ImGuiColorEditFlags_DefaultOptions_;
|
||||
ColorEditCurrentID = ColorEditSavedID = 0;
|
||||
|
@ -2479,7 +2583,7 @@ struct IMGUI_API ImGuiWindowTempData
|
|||
ImVec2 MenuBarOffset; // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs.
|
||||
ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items measurement
|
||||
int TreeDepth; // Current tree depth.
|
||||
ImU32 TreeJumpToParentOnPopMask; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31.. Could be turned into a ImU64 if necessary.
|
||||
ImU32 TreeHasStackDataDepthMask; // Store whether given depth has ImGuiTreeNodeStackData data. Could be turned into a ImU64 if necessary.
|
||||
ImVector<ImGuiWindow*> ChildWindows;
|
||||
ImGuiStorage* StateStorage; // Current persistent per-window storage (store e.g. tree node open/close state)
|
||||
ImGuiOldColumns* CurrentColumns; // Current columns set
|
||||
|
@ -2514,7 +2618,7 @@ struct IMGUI_API ImGuiWindow
|
|||
ImVec2 WindowPadding; // Window padding at the time of Begin().
|
||||
float WindowRounding; // Window rounding at the time of Begin(). May be clamped lower to avoid rendering artifacts with title bar, menu bar etc.
|
||||
float WindowBorderSize; // Window border size at the time of Begin().
|
||||
float TitleBarHeight, MenuBarHeight;
|
||||
float TitleBarHeight, MenuBarHeight; // Note that those used to be function before 2024/05/28. If you have old code calling TitleBarHeight() you can change it to TitleBarHeight.
|
||||
float DecoOuterSizeX1, DecoOuterSizeY1; // Left/Up offsets. Sum of non-scrolling outer decorations (X1 generally == 0.0f. Y1 generally = TitleBarHeight + MenuBarHeight). Locked during Begin().
|
||||
float DecoOuterSizeX2, DecoOuterSizeY2; // Right/Down offsets (X2 generally == ScrollbarSize.x, Y2 == ScrollbarSizes.y).
|
||||
float DecoInnerSizeX1, DecoInnerSizeY1; // Applied AFTER/OVER InnerRect. Specialized for Tables as they use specialized form of clipping and frozen rows/columns are inside InnerRect (and not part of regular decoration sizes).
|
||||
|
@ -2611,6 +2715,7 @@ public:
|
|||
ImGuiID GetID(const char* str, const char* str_end = NULL);
|
||||
ImGuiID GetID(const void* ptr);
|
||||
ImGuiID GetID(int n);
|
||||
ImGuiID GetIDFromPos(const ImVec2& p_abs);
|
||||
ImGuiID GetIDFromRectangle(const ImRect& r_abs);
|
||||
|
||||
// We don't use g.FontSize because the window may be != g.CurrentWindow.
|
||||
|
@ -2722,6 +2827,7 @@ struct ImGuiTableColumn
|
|||
float MaxX;
|
||||
float WidthRequest; // Master width absolute value when !(Flags & _WidthStretch). When Stretch this is derived every frame from StretchWeight in TableUpdateLayout()
|
||||
float WidthAuto; // Automatic width
|
||||
float WidthMax; // Maximum width (FIXME: overwritten by each instance)
|
||||
float StretchWeight; // Master width weight when (Flags & _WidthStretch). Often around ~1.0f initially.
|
||||
float InitStretchWeightOrWidth; // Value passed to TableSetupColumn(). For Width it is a content width (_without padding_).
|
||||
ImRect ClipRect; // Clipping rectangle for the column
|
||||
|
@ -3020,6 +3126,7 @@ namespace ImGui
|
|||
inline void SetWindowParentWindowForFocusRoute(ImGuiWindow* window, ImGuiWindow* parent_window) { window->ParentWindowForFocusRoute = parent_window; }
|
||||
inline ImRect WindowRectAbsToRel(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x - off.x, r.Min.y - off.y, r.Max.x - off.x, r.Max.y - off.y); }
|
||||
inline ImRect WindowRectRelToAbs(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x + off.x, r.Min.y + off.y, r.Max.x + off.x, r.Max.y + off.y); }
|
||||
inline ImVec2 WindowPosAbsToRel(ImGuiWindow* window, const ImVec2& p) { ImVec2 off = window->DC.CursorStartPos; return ImVec2(p.x - off.x, p.y - off.y); }
|
||||
inline ImVec2 WindowPosRelToAbs(ImGuiWindow* window, const ImVec2& p) { ImVec2 off = window->DC.CursorStartPos; return ImVec2(p.x + off.x, p.y + off.y); }
|
||||
|
||||
// Windows: Display Order and Focus Order
|
||||
|
@ -3122,13 +3229,9 @@ namespace ImGui
|
|||
IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h);
|
||||
IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x);
|
||||
IMGUI_API void PushMultiItemsWidths(int components, float width_full);
|
||||
IMGUI_API bool IsItemToggledSelection(); // Was the last item selection toggled? (after Selectable(), TreeNode() etc. We only returns toggle _event_ in order to handle clipping correctly)
|
||||
IMGUI_API ImVec2 GetContentRegionMaxAbs();
|
||||
IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess);
|
||||
|
||||
// Parameter stacks (shared)
|
||||
IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled);
|
||||
IMGUI_API void PopItemFlag();
|
||||
IMGUI_API const ImGuiDataVarInfo* GetStyleVarInfo(ImGuiStyleVar idx);
|
||||
IMGUI_API void BeginDisabledOverrideReenable();
|
||||
IMGUI_API void EndDisabledOverrideReenable();
|
||||
|
@ -3139,16 +3242,16 @@ namespace ImGui
|
|||
IMGUI_API void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL);
|
||||
IMGUI_API void LogSetNextTextDecoration(const char* prefix, const char* suffix);
|
||||
|
||||
// Popups, Modals, Tooltips
|
||||
// Childs
|
||||
IMGUI_API bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags);
|
||||
|
||||
// Popups, Modals
|
||||
IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_window_flags);
|
||||
IMGUI_API void OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags = ImGuiPopupFlags_None);
|
||||
IMGUI_API void ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup);
|
||||
IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup);
|
||||
IMGUI_API void ClosePopupsExceptModals();
|
||||
IMGUI_API bool IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags);
|
||||
IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags);
|
||||
IMGUI_API bool BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags);
|
||||
IMGUI_API bool BeginTooltipHidden();
|
||||
IMGUI_API ImRect GetPopupAllowedExtentRect(ImGuiWindow* window);
|
||||
IMGUI_API ImGuiWindow* GetTopMostPopupModal();
|
||||
IMGUI_API ImGuiWindow* GetTopMostAndVisiblePopupModal();
|
||||
|
@ -3156,6 +3259,10 @@ namespace ImGui
|
|||
IMGUI_API ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window);
|
||||
IMGUI_API ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy);
|
||||
|
||||
// Tooltips
|
||||
IMGUI_API bool BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags);
|
||||
IMGUI_API bool BeginTooltipHidden();
|
||||
|
||||
// Menus
|
||||
IMGUI_API bool BeginViewportSideBar(const char* name, ImGuiViewport* viewport, ImGuiDir dir, float size, ImGuiWindowFlags window_flags);
|
||||
IMGUI_API bool BeginMenuEx(const char* label, const char* icon, bool enabled = true);
|
||||
|
@ -3173,7 +3280,7 @@ namespace ImGui
|
|||
IMGUI_API void NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags);
|
||||
IMGUI_API void NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags);
|
||||
IMGUI_API void NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result);
|
||||
IMGUI_API void NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGuiNavTreeNodeData* tree_node_data);
|
||||
IMGUI_API void NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGuiTreeNodeStackData* tree_node_data);
|
||||
IMGUI_API void NavMoveRequestCancel();
|
||||
IMGUI_API void NavMoveRequestApplyResult();
|
||||
IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags);
|
||||
|
@ -3200,7 +3307,7 @@ namespace ImGui
|
|||
inline bool IsGamepadKey(ImGuiKey key) { return key >= ImGuiKey_Gamepad_BEGIN && key < ImGuiKey_Gamepad_END; }
|
||||
inline bool IsMouseKey(ImGuiKey key) { return key >= ImGuiKey_Mouse_BEGIN && key < ImGuiKey_Mouse_END; }
|
||||
inline bool IsAliasKey(ImGuiKey key) { return key >= ImGuiKey_Aliases_BEGIN && key < ImGuiKey_Aliases_END; }
|
||||
inline bool IsModKey(ImGuiKey key) { return key >= ImGuiKey_LeftCtrl && key <= ImGuiKey_RightSuper; }
|
||||
inline bool IsLRModKey(ImGuiKey key) { return key >= ImGuiKey_LeftCtrl && key <= ImGuiKey_RightSuper; }
|
||||
ImGuiKeyChord FixupKeyChord(ImGuiKeyChord key_chord);
|
||||
inline ImGuiKey ConvertSingleModFlagToKey(ImGuiKey key)
|
||||
{
|
||||
|
@ -3238,7 +3345,7 @@ namespace ImGui
|
|||
IMGUI_API ImGuiID GetKeyOwner(ImGuiKey key);
|
||||
IMGUI_API void SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags = 0);
|
||||
IMGUI_API void SetKeyOwnersForKeyChord(ImGuiKeyChord key, ImGuiID owner_id, ImGuiInputFlags flags = 0);
|
||||
IMGUI_API void SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags = 0); // Set key owner to last item if it is hovered or active. Equivalent to 'if (IsItemHovered() || IsItemActive()) { SetKeyOwner(key, GetItemID());'.
|
||||
IMGUI_API void SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags); // Set key owner to last item if it is hovered or active. Equivalent to 'if (IsItemHovered() || IsItemActive()) { SetKeyOwner(key, GetItemID());'.
|
||||
IMGUI_API bool TestKeyOwner(ImGuiKey key, ImGuiID owner_id); // Test that key is either not owned, either owned by 'owner_id'
|
||||
inline ImGuiKeyOwnerData* GetKeyOwnerData(ImGuiContext* ctx, ImGuiKey key) { if (key & ImGuiMod_Mask_) key = ConvertSingleModFlagToKey(key); IM_ASSERT(IsNamedKey(key)); return &ctx->KeysOwnerData[key - ImGuiKey_NamedKey_BEGIN]; }
|
||||
|
||||
|
@ -3301,6 +3408,18 @@ namespace ImGui
|
|||
IMGUI_API int TypingSelectFindNextSingleCharMatch(ImGuiTypingSelectRequest* req, int items_count, const char* (*get_item_name_func)(void*, int), void* user_data, int nav_item_idx);
|
||||
IMGUI_API int TypingSelectFindBestLeadingMatch(ImGuiTypingSelectRequest* req, int items_count, const char* (*get_item_name_func)(void*, int), void* user_data);
|
||||
|
||||
// Box-Select API
|
||||
IMGUI_API bool BeginBoxSelect(const ImRect& scope_rect, ImGuiWindow* window, ImGuiID box_select_id, ImGuiMultiSelectFlags ms_flags);
|
||||
IMGUI_API void EndBoxSelect(const ImRect& scope_rect, ImGuiMultiSelectFlags ms_flags);
|
||||
|
||||
// Multi-Select API
|
||||
IMGUI_API void MultiSelectItemHeader(ImGuiID id, bool* p_selected, ImGuiButtonFlags* p_button_flags);
|
||||
IMGUI_API void MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed);
|
||||
IMGUI_API void MultiSelectAddSetAll(ImGuiMultiSelectTempData* ms, bool selected);
|
||||
IMGUI_API void MultiSelectAddSetRange(ImGuiMultiSelectTempData* ms, bool selected, int range_dir, ImGuiSelectionUserData first_item, ImGuiSelectionUserData last_item);
|
||||
inline ImGuiBoxSelectState* GetBoxSelectState(ImGuiID id) { ImGuiContext& g = *GImGui; return (id != 0 && g.BoxSelectState.ID == id && g.BoxSelectState.IsActive) ? &g.BoxSelectState : NULL; }
|
||||
inline ImGuiMultiSelectState* GetMultiSelectState(ImGuiID id) { ImGuiContext& g = *GImGui; return g.MultiSelectStorage.GetByKey(id); }
|
||||
|
||||
// Internal Columns API (this is not exposed because we will encourage transitioning to the Tables API)
|
||||
IMGUI_API void SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect);
|
||||
IMGUI_API void BeginColumns(const char* str_id, int count, ImGuiOldColumnFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns().
|
||||
|
@ -3317,7 +3436,6 @@ namespace ImGui
|
|||
IMGUI_API void TableOpenContextMenu(int column_n = -1);
|
||||
IMGUI_API void TableSetColumnWidth(int column_n, float width);
|
||||
IMGUI_API void TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs);
|
||||
IMGUI_API int TableGetHoveredColumn(); // May use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) instead. Return hovered column. return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered.
|
||||
IMGUI_API int TableGetHoveredRow(); // Retrieve *PREVIOUS FRAME* hovered row. This difference with TableGetHoveredColumn() is the reason why this is not public yet.
|
||||
IMGUI_API float TableGetHeaderRowHeight();
|
||||
IMGUI_API float TableGetHeaderAngledMaxLabelWidth();
|
||||
|
@ -3353,7 +3471,7 @@ namespace ImGui
|
|||
IMGUI_API ImRect TableGetCellBgRect(const ImGuiTable* table, int column_n);
|
||||
IMGUI_API const char* TableGetColumnName(const ImGuiTable* table, int column_n);
|
||||
IMGUI_API ImGuiID TableGetColumnResizeID(ImGuiTable* table, int column_n, int instance_no = 0);
|
||||
IMGUI_API float TableGetMaxColumnWidth(const ImGuiTable* table, int column_n);
|
||||
IMGUI_API float TableCalcMaxColumnWidth(const ImGuiTable* table, int column_n);
|
||||
IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n);
|
||||
IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table);
|
||||
IMGUI_API void TableRemove(ImGuiTable* table);
|
||||
|
@ -3398,7 +3516,7 @@ namespace ImGui
|
|||
IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL);
|
||||
IMGUI_API void RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL);
|
||||
IMGUI_API void RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end, const ImVec2* text_size_if_known);
|
||||
IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f);
|
||||
IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool borders = true, float rounding = 0.0f);
|
||||
IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f);
|
||||
IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, ImDrawFlags flags = 0);
|
||||
IMGUI_API void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags = ImGuiNavHighlightFlags_None); // Navigation highlight
|
||||
|
@ -3438,11 +3556,13 @@ namespace ImGui
|
|||
IMGUI_API bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags);
|
||||
IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb);
|
||||
IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f, ImU32 bg_col = 0);
|
||||
|
||||
// Widgets: Tree Nodes
|
||||
IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL);
|
||||
IMGUI_API void TreePushOverrideID(ImGuiID id);
|
||||
IMGUI_API void TreeNodeSetOpen(ImGuiID id, bool open);
|
||||
IMGUI_API bool TreeNodeUpdateNextOpen(ImGuiID id, ImGuiTreeNodeFlags flags); // Return open state. Consume previous SetNextItemOpen() data, if any. May return true when logging.
|
||||
IMGUI_API void SetNextItemSelectionUserData(ImGuiSelectionUserData selection_user_data);
|
||||
IMGUI_API bool TreeNodeGetOpen(ImGuiID storage_id);
|
||||
IMGUI_API void TreeNodeSetOpen(ImGuiID storage_id, bool open);
|
||||
IMGUI_API bool TreeNodeUpdateNextOpen(ImGuiID storage_id, ImGuiTreeNodeFlags flags); // Return open state. Consume previous SetNextItemOpen() data, if any. May return true when logging.
|
||||
|
||||
// Template functions are instantiated in imgui_widgets.cpp for a finite number of types.
|
||||
// To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036).
|
||||
|
@ -3458,7 +3578,7 @@ namespace ImGui
|
|||
IMGUI_API const ImGuiDataTypeInfo* DataTypeGetInfo(ImGuiDataType data_type);
|
||||
IMGUI_API int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* p_data, const char* format);
|
||||
IMGUI_API void DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, const void* arg_1, const void* arg_2);
|
||||
IMGUI_API bool DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void* p_data, const char* format);
|
||||
IMGUI_API bool DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void* p_data, const char* format, void* p_data_when_empty = NULL);
|
||||
IMGUI_API int DataTypeCompare(ImGuiDataType data_type, const void* arg_1, const void* arg_2);
|
||||
IMGUI_API bool DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max);
|
||||
|
||||
|
@ -3469,6 +3589,7 @@ namespace ImGui
|
|||
IMGUI_API bool TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min = NULL, const void* p_clamp_max = NULL);
|
||||
inline bool TempInputIsActive(ImGuiID id) { ImGuiContext& g = *GImGui; return (g.ActiveId == id && g.TempInputId == id); }
|
||||
inline ImGuiInputTextState* GetInputTextState(ImGuiID id) { ImGuiContext& g = *GImGui; return (id != 0 && g.InputTextState.ID == id) ? &g.InputTextState : NULL; } // Get input text state if active
|
||||
IMGUI_API void SetNextItemRefVal(ImGuiDataType data_type, void* p_data);
|
||||
|
||||
// Color
|
||||
IMGUI_API void ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags);
|
||||
|
@ -3488,12 +3609,8 @@ namespace ImGui
|
|||
IMGUI_API void GcCompactTransientWindowBuffers(ImGuiWindow* window);
|
||||
IMGUI_API void GcAwakeTransientWindowBuffers(ImGuiWindow* window);
|
||||
|
||||
// Debug Log
|
||||
IMGUI_API void DebugLog(const char* fmt, ...) IM_FMTARGS(1);
|
||||
IMGUI_API void DebugLogV(const char* fmt, va_list args) IM_FMTLIST(1);
|
||||
IMGUI_API void DebugAllocHook(ImGuiDebugAllocInfo* info, int frame_count, void* ptr, size_t size); // size >= 0 : alloc, size = -1 : free
|
||||
|
||||
// Debug Tools
|
||||
IMGUI_API void DebugAllocHook(ImGuiDebugAllocInfo* info, int frame_count, void* ptr, size_t size); // size >= 0 : alloc, size = -1 : free
|
||||
IMGUI_API void ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL);
|
||||
IMGUI_API void ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL);
|
||||
IMGUI_API void ErrorCheckUsingSetCursorPosToExtendParentBoundaries();
|
||||
|
@ -3520,6 +3637,7 @@ namespace ImGui
|
|||
IMGUI_API void DebugNodeTableSettings(ImGuiTableSettings* settings);
|
||||
IMGUI_API void DebugNodeInputTextState(ImGuiInputTextState* state);
|
||||
IMGUI_API void DebugNodeTypingSelectState(ImGuiTypingSelectState* state);
|
||||
IMGUI_API void DebugNodeMultiSelectState(ImGuiMultiSelectState* state);
|
||||
IMGUI_API void DebugNodeWindow(ImGuiWindow* window, const char* label);
|
||||
IMGUI_API void DebugNodeWindowSettings(ImGuiWindowSettings* settings);
|
||||
IMGUI_API void DebugNodeWindowsList(ImVector<ImGuiWindow*>* windows, const char* label);
|
||||
|
|
167
source/engine/thirdparty/imgui/imgui_neo_internal.cpp
vendored
Normal file
167
source/engine/thirdparty/imgui/imgui_neo_internal.cpp
vendored
Normal file
|
@ -0,0 +1,167 @@
|
|||
//
|
||||
// Created by Matty on 2022-01-28.
|
||||
//
|
||||
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
|
||||
#include "imgui_neo_internal.h"
|
||||
#include "imgui_internal.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace ImGui {
|
||||
void RenderNeoSequencerBackground(const ImVec4 &color, const ImVec2 & cursor, const ImVec2 &size, ImDrawList * drawList, float sequencerRounding) {
|
||||
if(!drawList) drawList = ImGui::GetWindowDrawList();
|
||||
|
||||
const ImRect area = {cursor, cursor + size};
|
||||
|
||||
drawList->AddRectFilled(area.Min, area.Max, ColorConvertFloat4ToU32(color), sequencerRounding);
|
||||
}
|
||||
|
||||
void RenderNeoSequencerTopBarBackground(const ImVec4 &color, const ImVec2 &cursor, const ImVec2 &size,
|
||||
ImDrawList *drawList, float sequencerRounding) {
|
||||
if(!drawList) drawList = ImGui::GetWindowDrawList();
|
||||
|
||||
const ImRect barArea = {cursor, cursor + size};
|
||||
|
||||
drawList->AddRectFilled(barArea.Min, barArea.Max, ColorConvertFloat4ToU32(color), sequencerRounding);
|
||||
}
|
||||
|
||||
void
|
||||
RenderNeoSequencerTopBarOverlay(float zoom, float valuesWidth,uint32_t startFrame, uint32_t endFrame, uint32_t offsetFrame, const ImVec2 &cursor, const ImVec2 &size,
|
||||
ImDrawList *drawList, bool drawFrameLines,
|
||||
bool drawFrameText, float maxPixelsPerTick) {
|
||||
if(!drawList) drawList = ImGui::GetWindowDrawList();
|
||||
|
||||
const auto & style = GetStyle();
|
||||
|
||||
const ImRect barArea = {cursor + ImVec2{style.FramePadding.x + valuesWidth,style.FramePadding.y}, cursor + size };
|
||||
|
||||
const uint32_t viewEnd = endFrame + offsetFrame;
|
||||
const uint32_t viewStart = startFrame + offsetFrame;
|
||||
|
||||
if(drawFrameLines) {
|
||||
const auto count = (int32_t)((float)((viewEnd + 1) - viewStart) / zoom);
|
||||
|
||||
int32_t counter = 0;
|
||||
uint32_t primaryFrames = pow(10, counter++);
|
||||
uint32_t secondaryFrames = pow(10, counter);
|
||||
|
||||
float perFrameWidth = GetPerFrameWidth(size.x, valuesWidth, endFrame, startFrame, zoom);
|
||||
|
||||
if(perFrameWidth <= 0.0f) return;
|
||||
|
||||
while (perFrameWidth < maxPixelsPerTick)
|
||||
{
|
||||
primaryFrames = pow(10, counter++);
|
||||
secondaryFrames = pow(10, counter);
|
||||
|
||||
perFrameWidth *= (float)primaryFrames;
|
||||
}
|
||||
|
||||
if(primaryFrames == 0 || secondaryFrames == 0) {
|
||||
primaryFrames = 1;
|
||||
secondaryFrames = 10;
|
||||
}
|
||||
|
||||
for(int32_t i = 0; i < count; i++) {
|
||||
|
||||
const auto primaryFrame = ((viewStart + i) % primaryFrames == 0);
|
||||
const auto secondaryFrame = ((viewStart + i) % secondaryFrames == 0);
|
||||
|
||||
if(!primaryFrame && !secondaryFrame) continue;
|
||||
|
||||
const auto lineHeight = secondaryFrame ? barArea.GetSize().y : barArea.GetSize().y / 2.0f;
|
||||
|
||||
const ImVec2 p1 = {barArea.Min.x + (float)i * (perFrameWidth / (float)primaryFrames), barArea.Max.y};
|
||||
const ImVec2 p2 = {barArea.Min.x + (float)i * (perFrameWidth / (float)primaryFrames), barArea.Max.y - lineHeight};
|
||||
|
||||
drawList->AddLine(p1,p2, IM_COL32_WHITE, 1.0f);
|
||||
|
||||
if(drawFrameText && secondaryFrame) {
|
||||
char text[10];
|
||||
const auto printRes = snprintf(text, sizeof(text), "%i", viewStart + i);
|
||||
if(printRes > 0) {
|
||||
drawList->AddText(NULL, 0, {p1.x + 2.0f, barArea.Min.y }, IM_COL32_WHITE,text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderNeoTimelineLabel(const char * label,const ImVec2 & cursor,const ImVec2 & size, const ImVec4& color,bool isGroup, bool isOpen, ImDrawList *drawList)
|
||||
{
|
||||
const auto& imStyle = GetStyle();
|
||||
|
||||
if(!drawList) drawList = ImGui::GetWindowDrawList();
|
||||
|
||||
auto c = cursor;
|
||||
|
||||
if(isGroup) {
|
||||
RenderArrow(drawList,c,IM_COL32_WHITE,isOpen ? ImGuiDir_Down : ImGuiDir_Right);
|
||||
c.x += size.y + imStyle.ItemSpacing.x;
|
||||
}
|
||||
|
||||
drawList->AddText(c,ColorConvertFloat4ToU32(color),label, FindRenderedTextEnd(label));
|
||||
}
|
||||
|
||||
void RenderNeoTimelinesBorder(const ImVec4 &color, const ImVec2 &cursor, const ImVec2 &size, ImDrawList *drawList,
|
||||
float rounding, float borderSize)
|
||||
{
|
||||
if(!drawList) drawList = ImGui::GetWindowDrawList();
|
||||
|
||||
drawList->AddRect(cursor,cursor + size,ColorConvertFloat4ToU32(color),rounding, 0, borderSize);
|
||||
}
|
||||
|
||||
void RenderNeoTimelane(bool selected,const ImVec2 & cursor, const ImVec2& size, const ImVec4& highlightColor, ImDrawList *drawList) {
|
||||
if(!drawList) drawList = ImGui::GetWindowDrawList();
|
||||
|
||||
if(selected) {
|
||||
const ImRect area = {cursor, cursor + size};
|
||||
drawList->AddRectFilled(area.Min, area.Max, ColorConvertFloat4ToU32(highlightColor));
|
||||
}
|
||||
}
|
||||
|
||||
float GetPerFrameWidth(float totalSizeX, float valuesWidth, uint32_t endFrame, uint32_t startFrame, float zoom) {
|
||||
const auto& imStyle = GetStyle();
|
||||
|
||||
const auto size = totalSizeX - valuesWidth - imStyle.FramePadding.x;
|
||||
|
||||
auto count = (endFrame + 1) - startFrame;
|
||||
|
||||
return ((size / (float)count) * zoom);
|
||||
}
|
||||
|
||||
struct Vec2Pair {
|
||||
ImVec2 a;
|
||||
ImVec2 b;
|
||||
};
|
||||
|
||||
static Vec2Pair getCurrentFrameLine(const ImRect & pointerBB, float timelineHeight) {
|
||||
const auto center = ImVec2{pointerBB.Min.x, pointerBB.Max.y} + ImVec2{pointerBB.GetSize().x / 2.0f, 0};
|
||||
|
||||
return Vec2Pair{ center, center + ImVec2{0, timelineHeight} };
|
||||
}
|
||||
|
||||
void RenderNeoSequencerCurrentFrame(const ImVec4 &color, const ImVec4 &topColor, const ImRect &pointerBB,
|
||||
float timelineHeight, float lineWidth, ImDrawList *drawList) {
|
||||
if(!drawList) drawList = ImGui::GetWindowDrawList();
|
||||
|
||||
const auto pair = getCurrentFrameLine(pointerBB, timelineHeight);
|
||||
|
||||
drawList->AddLine(pair.a, pair.b, ColorConvertFloat4ToU32(color), lineWidth);
|
||||
|
||||
drawList->PopClipRect();
|
||||
|
||||
{ //Top pointer has custom shape, we have to create it
|
||||
const auto size = pointerBB.GetSize();
|
||||
ImVec2 pts[5];
|
||||
pts[0] = pointerBB.Min;
|
||||
pts[1] = pointerBB.Min + ImVec2{size.x, 0};
|
||||
pts[2] = pointerBB.Min + ImVec2{size.x, size.y * 0.85f};
|
||||
pts[3] = pointerBB.Min + ImVec2{size.x / 2, size.y};
|
||||
pts[4] = pointerBB.Min + ImVec2{0, size.y * 0.85f};
|
||||
|
||||
drawList->AddConvexPolyFilled(pts, sizeof(pts) / sizeof(*pts), ColorConvertFloat4ToU32(topColor));
|
||||
}
|
||||
}
|
||||
}
|
24
source/engine/thirdparty/imgui/imgui_neo_internal.h
vendored
Normal file
24
source/engine/thirdparty/imgui/imgui_neo_internal.h
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// Created by Matty on 2022-01-28.
|
||||
//
|
||||
|
||||
#ifndef IMGUI_NEO_INTERNAL_H
|
||||
#define IMGUI_NEO_INTERNAL_H
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace ImGui {
|
||||
IMGUI_API void RenderNeoSequencerBackground(const ImVec4& color, const ImVec2 & cursor, const ImVec2& size, ImDrawList * drawList = nullptr, float sequencerRounding = 0.0f);
|
||||
IMGUI_API void RenderNeoSequencerTopBarBackground(const ImVec4& color, const ImVec2 & cursor, const ImVec2& size, ImDrawList * drawList = nullptr, float sequencerRounding = 0.0f);
|
||||
IMGUI_API void RenderNeoSequencerTopBarOverlay(float zoom, float valuesWidth,uint32_t startFrame, uint32_t endFrame, uint32_t offsetFrame, const ImVec2 &cursor, const ImVec2& size, ImDrawList * drawList = nullptr, bool drawFrameLines = true, bool drawFrameText = true, float maxPixelsPerTick = -1.0f);
|
||||
IMGUI_API void RenderNeoTimelineLabel(const char * label,const ImVec2 & cursor,const ImVec2 & size, const ImVec4& color,bool isGroup = false, bool isOpen = false, ImDrawList *drawList = nullptr );
|
||||
IMGUI_API void RenderNeoTimelane(bool selected,const ImVec2 & cursor, const ImVec2& size, const ImVec4& highlightColor, ImDrawList *drawList = nullptr);
|
||||
IMGUI_API void RenderNeoTimelinesBorder(const ImVec4& color, const ImVec2 & cursor, const ImVec2& size, ImDrawList * drawList = nullptr, float rounding = 0.0f, float borderSize = 1.0f);
|
||||
IMGUI_API void RenderNeoSequencerCurrentFrame(const ImVec4& color,const ImVec4 & topColor,const ImRect & pointerBB ,float timelineHeight, float lineWidth = 1.0f, ImDrawList * drawList = nullptr);
|
||||
|
||||
IMGUI_API float GetPerFrameWidth(float totalSizeX, float valuesWidth, uint32_t endFrame, uint32_t startFrame, float zoom);
|
||||
}
|
||||
|
||||
#endif //IMGUI_NEO_INTERNAL_H
|
1376
source/engine/thirdparty/imgui/imgui_neo_sequencer.cpp
vendored
Normal file
1376
source/engine/thirdparty/imgui/imgui_neo_sequencer.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
155
source/engine/thirdparty/imgui/imgui_neo_sequencer.h
vendored
Normal file
155
source/engine/thirdparty/imgui/imgui_neo_sequencer.h
vendored
Normal file
|
@ -0,0 +1,155 @@
|
|||
//
|
||||
// Created by Matty on 2022-01-28.
|
||||
//
|
||||
|
||||
#ifndef IMGUI_NEO_SEQUENCER_H
|
||||
#define IMGUI_NEO_SEQUENCER_H
|
||||
|
||||
#include "imgui.h"
|
||||
#include <vector>
|
||||
|
||||
typedef int ImGuiNeoSequencerFlags;
|
||||
typedef int ImGuiNeoSequencerCol;
|
||||
typedef int ImGuiNeoTimelineFlags;
|
||||
typedef int ImGuiNeoTimelineIsSelectedFlags;
|
||||
|
||||
// Flags for ImGui::BeginNeoSequencer()
|
||||
enum ImGuiNeoSequencerFlags_
|
||||
{
|
||||
ImGuiNeoSequencerFlags_None = 0 ,
|
||||
ImGuiNeoSequencerFlags_AllowLengthChanging = 1 << 0, // Allows changing length of sequence
|
||||
ImGuiNeoSequencerFlags_EnableSelection = 1 << 1, // Enables selection of keyframes
|
||||
ImGuiNeoSequencerFlags_HideZoom = 1 << 2, // Disables zoom bar
|
||||
//ImGuiNeoSequencerFlags_PH = 1 << 3, // PLACEHOLDER
|
||||
ImGuiNeoSequencerFlags_AlwaysShowHeader = 1 << 4, // Enables overlay header, keeping it visible when scrolling
|
||||
|
||||
// Selection options, only work with enable selection flag
|
||||
ImGuiNeoSequencerFlags_Selection_EnableDragging = 1 << 5,
|
||||
ImGuiNeoSequencerFlags_Selection_EnableDeletion = 1 << 6,
|
||||
|
||||
};
|
||||
|
||||
// Flags for ImGui::BeginNeoTimeline()
|
||||
enum ImGuiNeoTimelineFlags_
|
||||
{
|
||||
ImGuiNeoTimelineFlags_None = 0 ,
|
||||
ImGuiNeoTimelineFlags_AllowFrameChanging = 1 << 0,
|
||||
ImGuiNeoTimelineFlags_Group = 1 << 1,
|
||||
};
|
||||
|
||||
// Flags for ImGui::IsNeoTimelineSelected()
|
||||
enum ImGuiNeoTimelineIsSelectedFlags_
|
||||
{
|
||||
ImGuiNeoTimelineIsSelectedFlags_None = 0 ,
|
||||
ImGuiNeoTimelineIsSelectedFlags_NewlySelected = 1 << 0,
|
||||
};
|
||||
|
||||
enum ImGuiNeoSequencerCol_
|
||||
{
|
||||
ImGuiNeoSequencerCol_Bg,
|
||||
ImGuiNeoSequencerCol_TopBarBg,
|
||||
ImGuiNeoSequencerCol_SelectedTimeline,
|
||||
ImGuiNeoSequencerCol_TimelineBorder,
|
||||
ImGuiNeoSequencerCol_TimelinesBg,
|
||||
ImGuiNeoSequencerCol_FramePointer,
|
||||
ImGuiNeoSequencerCol_FramePointerHovered,
|
||||
ImGuiNeoSequencerCol_FramePointerPressed,
|
||||
ImGuiNeoSequencerCol_Keyframe,
|
||||
ImGuiNeoSequencerCol_KeyframeHovered,
|
||||
ImGuiNeoSequencerCol_KeyframePressed,
|
||||
ImGuiNeoSequencerCol_KeyframeSelected,
|
||||
ImGuiNeoSequencerCol_FramePointerLine,
|
||||
|
||||
ImGuiNeoSequencerCol_ZoomBarBg,
|
||||
ImGuiNeoSequencerCol_ZoomBarSlider,
|
||||
ImGuiNeoSequencerCol_ZoomBarSliderHovered,
|
||||
ImGuiNeoSequencerCol_ZoomBarSliderEnds,
|
||||
ImGuiNeoSequencerCol_ZoomBarSliderEndsHovered,
|
||||
|
||||
ImGuiNeoSequencerCol_SelectionBorder,
|
||||
ImGuiNeoSequencerCol_Selection,
|
||||
|
||||
ImGuiNeoSequencerCol_COUNT
|
||||
};
|
||||
|
||||
struct ImGuiNeoSequencerStyle {
|
||||
float SequencerRounding = 2.5f; // Corner rounding around whole sequencer
|
||||
float TopBarHeight = 0.0f; // Value <= 0.0f = Height is calculated by FontSize + FramePadding.y * 2.0f
|
||||
bool TopBarShowFrameLines = true; // Show line for every frame in top bar
|
||||
bool TopBarShowFrameTexts = true; // Show frame number every 10th frame
|
||||
ImVec2 ItemSpacing = {4.0f,0.5f};
|
||||
float DepthItemSpacing = 10.0f; // Amount of text offset per depth level in timeline values
|
||||
float TopBarSpacing = 3.0f; // Space between top bar and timeline
|
||||
float TimelineBorderSize = 1.0f;
|
||||
float CurrentFramePointerSize = 7.0f; // Size of pointing arrow above current frame line
|
||||
float CurrentFrameLineWidth = 1.0f; // Width of line showing current frame over timeline
|
||||
float ZoomHeightScale = 1.0f; // Scale of Zoom bar, base height is font size
|
||||
float CollidedKeyframeOffset = 3.5f; // Offset on which colliding keyframes are rendered
|
||||
|
||||
float MaxSizePerTick = 4.0f; // Maximum amount of pixels per tick on timeline (if less pixels is present, ticks are not rendered)
|
||||
|
||||
ImVec4 Colors[ImGuiNeoSequencerCol_COUNT];
|
||||
|
||||
ImGuiKey ModRemoveKey = ImGuiMod_Ctrl; // Key mod which when held removes selected keyframes from present selection
|
||||
ImGuiKey ModAddKey = ImGuiMod_Shift; // Key mod which when held adds selected keyframes to present selection
|
||||
|
||||
ImGuiNeoSequencerStyle();
|
||||
};
|
||||
|
||||
namespace ImGui {
|
||||
typedef int32_t FrameIndexType;
|
||||
|
||||
IMGUI_API const ImVec4& GetStyleNeoSequencerColorVec4(ImGuiNeoSequencerCol idx);
|
||||
IMGUI_API ImGuiNeoSequencerStyle& GetNeoSequencerStyle();
|
||||
|
||||
IMGUI_API void PushNeoSequencerStyleColor(ImGuiNeoSequencerCol idx, ImU32 col);
|
||||
IMGUI_API void PushNeoSequencerStyleColor(ImGuiNeoSequencerCol idx, const ImVec4& col);
|
||||
IMGUI_API void PopNeoSequencerStyleColor(int count = 1);
|
||||
|
||||
IMGUI_API bool BeginNeoSequencer(const char* id, FrameIndexType * frame, FrameIndexType * startFrame, FrameIndexType * endFrame,const ImVec2& size = ImVec2(0, 0),ImGuiNeoSequencerFlags flags = ImGuiNeoSequencerFlags_None);
|
||||
IMGUI_API void EndNeoSequencer(); //Call only when BeginNeoSequencer() returns true!!
|
||||
|
||||
IMGUI_API bool BeginNeoGroup(const char* label, bool* open = nullptr);
|
||||
IMGUI_API void EndNeoGroup();
|
||||
|
||||
IMGUI_API bool BeginNeoTimeline(const char* label,FrameIndexType ** keyframes, uint32_t keyframeCount, bool * open = nullptr, ImGuiNeoTimelineFlags flags = ImGuiNeoTimelineFlags_None);
|
||||
IMGUI_API void EndNeoTimeLine(); //Call only when BeginNeoTimeline() returns true!!
|
||||
|
||||
// Fully customizable timeline with per key callback
|
||||
IMGUI_API bool BeginNeoTimelineEx(const char* label, bool * open = nullptr, ImGuiNeoTimelineFlags flags = ImGuiNeoTimelineFlags_None);
|
||||
IMGUI_API void NeoKeyframe(int32_t* value);
|
||||
|
||||
IMGUI_API bool IsNeoKeyframeHovered();
|
||||
IMGUI_API bool IsNeoKeyframeSelected();
|
||||
IMGUI_API bool IsNeoKeyframeRightClicked();
|
||||
|
||||
|
||||
// Selection API
|
||||
// DON'T delete keyframes while dragging, internal buffer will get corrupted
|
||||
// Order for deletion is generally:
|
||||
// CanDelete? -> DataSize? -> GetData() -> Delete your data -> ClearSelection()
|
||||
IMGUI_API void NeoClearSelection(); // Clears selection
|
||||
IMGUI_API bool NeoIsSelecting(); // Are we currently selecting?
|
||||
IMGUI_API bool NeoHasSelection(); // Is anything selected?
|
||||
IMGUI_API bool NeoIsDraggingSelection(); // Are we dragging selection?
|
||||
IMGUI_API bool NeoCanDeleteSelection(); // Can selection deletion be done?
|
||||
IMGUI_API bool IsNeoKeyframeSelectionRightClicked(); // Is selection rightclicked?
|
||||
|
||||
// Call only in BeginNeoTimeline / EndNeoTimeLine scope, returns selection per timeline and size per timeline
|
||||
IMGUI_API uint32_t GetNeoKeyframeSelectionSize();
|
||||
IMGUI_API void GetNeoKeyframeSelection(FrameIndexType * selection);
|
||||
|
||||
|
||||
// Sets currently selected timeline inside BeginNeoSequencer scope
|
||||
IMGUI_API void SetSelectedTimeline(const char* timelineLabel);
|
||||
|
||||
IMGUI_API bool IsNeoTimelineSelected(ImGuiNeoTimelineIsSelectedFlags flags = ImGuiNeoTimelineIsSelectedFlags_None);
|
||||
|
||||
#ifdef __cplusplus
|
||||
// C++ helper
|
||||
// IMGUI_API bool BeginNeoTimeline(const char* label,std::vector<int32_t> & keyframes ,bool * open = nullptr, ImGuiNeoTimelineFlags flags = ImGuiNeoTimelineFlags_None);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#endif //IMGUI_NEO_SEQUENCER_H
|
70
source/engine/thirdparty/imgui/imgui_tables.cpp
vendored
70
source/engine/thirdparty/imgui/imgui_tables.cpp
vendored
|
@ -1,4 +1,4 @@
|
|||
// dear imgui, v1.90.8 WIP
|
||||
// dear imgui, v1.91.1
|
||||
// (tables and columns code)
|
||||
|
||||
/*
|
||||
|
@ -412,8 +412,8 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
|||
SetNextWindowScroll(ImVec2(0.0f, 0.0f));
|
||||
|
||||
// Create scrolling region (without border and zero window padding)
|
||||
ImGuiWindowFlags child_flags = (flags & ImGuiTableFlags_ScrollX) ? ImGuiWindowFlags_HorizontalScrollbar : ImGuiWindowFlags_None;
|
||||
BeginChildEx(name, instance_id, outer_rect.GetSize(), false, child_flags);
|
||||
ImGuiWindowFlags child_window_flags = (flags & ImGuiTableFlags_ScrollX) ? ImGuiWindowFlags_HorizontalScrollbar : ImGuiWindowFlags_None;
|
||||
BeginChildEx(name, instance_id, outer_rect.GetSize(), ImGuiChildFlags_None, child_window_flags);
|
||||
table->InnerWindow = g.CurrentWindow;
|
||||
table->WorkRect = table->InnerWindow->WorkRect;
|
||||
table->OuterRect = table->InnerWindow->Rect();
|
||||
|
@ -460,16 +460,27 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
|||
temp_data->HostBackupItemWidthStackSize = outer_window->DC.ItemWidthStack.Size;
|
||||
inner_window->DC.PrevLineSize = inner_window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
|
||||
|
||||
// Make left and top borders not overlap our contents by offsetting HostClipRect (#6765)
|
||||
// Make borders not overlap our contents by offsetting HostClipRect (#6765, #7428, #3752)
|
||||
// (we normally shouldn't alter HostClipRect as we rely on TableMergeDrawChannels() expanding non-clipped column toward the
|
||||
// limits of that rectangle, in order for ImDrawListSplitter::Merge() to merge the draw commands. However since the overlap
|
||||
// problem only affect scrolling tables in this case we can get away with doing it without extra cost).
|
||||
if (inner_window != outer_window)
|
||||
{
|
||||
// FIXME: Because inner_window's Scrollbar doesn't know about border size, since it's not encoded in window->WindowBorderSize,
|
||||
// it already overlaps it and doesn't need an extra offset. Ideally we should be able to pass custom border size with
|
||||
// different x/y values to BeginChild().
|
||||
if (flags & ImGuiTableFlags_BordersOuterV)
|
||||
{
|
||||
table->HostClipRect.Min.x = ImMin(table->HostClipRect.Min.x + TABLE_BORDER_SIZE, table->HostClipRect.Max.x);
|
||||
if (inner_window->DecoOuterSizeX2 == 0.0f)
|
||||
table->HostClipRect.Max.x = ImMax(table->HostClipRect.Max.x - TABLE_BORDER_SIZE, table->HostClipRect.Min.x);
|
||||
}
|
||||
if (flags & ImGuiTableFlags_BordersOuterH)
|
||||
{
|
||||
table->HostClipRect.Min.y = ImMin(table->HostClipRect.Min.y + TABLE_BORDER_SIZE, table->HostClipRect.Max.y);
|
||||
if (inner_window->DecoOuterSizeY2 == 0.0f)
|
||||
table->HostClipRect.Max.y = ImMax(table->HostClipRect.Max.y - TABLE_BORDER_SIZE, table->HostClipRect.Min.y);
|
||||
}
|
||||
}
|
||||
|
||||
// Padding and Spacing
|
||||
|
@ -497,7 +508,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
|||
table->InnerClipRect = (inner_window == outer_window) ? table->WorkRect : inner_window->ClipRect;
|
||||
table->InnerClipRect.ClipWith(table->WorkRect); // We need this to honor inner_width
|
||||
table->InnerClipRect.ClipWithFull(table->HostClipRect);
|
||||
table->InnerClipRect.Max.y = (flags & ImGuiTableFlags_NoHostExtendY) ? ImMin(table->InnerClipRect.Max.y, inner_window->WorkRect.Max.y) : inner_window->ClipRect.Max.y;
|
||||
table->InnerClipRect.Max.y = (flags & ImGuiTableFlags_NoHostExtendY) ? ImMin(table->InnerClipRect.Max.y, inner_window->WorkRect.Max.y) : table->HostClipRect.Max.y;
|
||||
|
||||
table->RowPosY1 = table->RowPosY2 = table->WorkRect.Min.y; // This is needed somehow
|
||||
table->RowTextBaseline = 0.0f; // This will be cleared again by TableBeginRow()
|
||||
|
@ -1059,16 +1070,12 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
|||
continue;
|
||||
}
|
||||
|
||||
// Detect hovered column
|
||||
if (is_hovering_table && mouse_skewed_x >= column->ClipRect.Min.x && mouse_skewed_x < column->ClipRect.Max.x)
|
||||
table->HoveredColumnBody = (ImGuiTableColumnIdx)column_n;
|
||||
|
||||
// Lock start position
|
||||
column->MinX = offset_x;
|
||||
|
||||
// Lock width based on start position and minimum/maximum width for this position
|
||||
float max_width = TableGetMaxColumnWidth(table, column_n);
|
||||
column->WidthGiven = ImMin(column->WidthGiven, max_width);
|
||||
column->WidthMax = TableCalcMaxColumnWidth(table, column_n);
|
||||
column->WidthGiven = ImMin(column->WidthGiven, column->WidthMax);
|
||||
column->WidthGiven = ImMax(column->WidthGiven, ImMin(column->WidthRequest, table->MinColumnWidth));
|
||||
column->MaxX = offset_x + column->WidthGiven + table->CellSpacingX1 + table->CellSpacingX2 + table->CellPaddingX * 2.0f;
|
||||
|
||||
|
@ -1117,8 +1124,13 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
|||
column->Flags |= ImGuiTableColumnFlags_IsVisible;
|
||||
if (column->SortOrder != -1)
|
||||
column->Flags |= ImGuiTableColumnFlags_IsSorted;
|
||||
if (table->HoveredColumnBody == column_n)
|
||||
|
||||
// Detect hovered column
|
||||
if (is_hovering_table && mouse_skewed_x >= column->ClipRect.Min.x && mouse_skewed_x < column->ClipRect.Max.x)
|
||||
{
|
||||
column->Flags |= ImGuiTableColumnFlags_IsHovered;
|
||||
table->HoveredColumnBody = (ImGuiTableColumnIdx)column_n;
|
||||
}
|
||||
|
||||
// Alignment
|
||||
// FIXME-TABLE: This align based on the whole column width, not per-cell, and therefore isn't useful in
|
||||
|
@ -1249,7 +1261,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
|||
if (table->Flags & ImGuiTableFlags_NoClip)
|
||||
table->DrawSplitter->SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP);
|
||||
else
|
||||
inner_window->DrawList->PushClipRect(inner_window->ClipRect.Min, inner_window->ClipRect.Max, false);
|
||||
inner_window->DrawList->PushClipRect(inner_window->InnerClipRect.Min, inner_window->InnerClipRect.Max, false);
|
||||
}
|
||||
|
||||
// Process hit-testing on resizing borders. Actual size change will be applied in EndTable()
|
||||
|
@ -1996,14 +2008,16 @@ void ImGui::TableEndRow(ImGuiTable* table)
|
|||
// We need to do that in TableEndRow() instead of TableBeginRow() so the list clipper can mark end of row and
|
||||
// get the new cursor position.
|
||||
if (unfreeze_rows_request)
|
||||
{
|
||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||
table->Columns[column_n].NavLayerCurrent = ImGuiNavLayer_Main;
|
||||
const float y0 = ImMax(table->RowPosY2 + 1, window->InnerClipRect.Min.y);
|
||||
table_instance->LastFrozenHeight = y0 - table->OuterRect.Min.y;
|
||||
|
||||
if (unfreeze_rows_actual)
|
||||
{
|
||||
IM_ASSERT(table->IsUnfrozenRows == false);
|
||||
const float y0 = ImMax(table->RowPosY2 + 1, window->InnerClipRect.Min.y);
|
||||
table->IsUnfrozenRows = true;
|
||||
table_instance->LastFrozenHeight = y0 - table->OuterRect.Min.y;
|
||||
|
||||
// BgClipRect starts as table->InnerClipRect, reduce it now and make BgClipRectForDrawCmd == BgClipRect
|
||||
table->BgClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y = ImMin(y0, window->InnerClipRect.Max.y);
|
||||
|
@ -2025,6 +2039,7 @@ void ImGui::TableEndRow(ImGuiTable* table)
|
|||
SetWindowClipRectBeforeSetChannel(window, table->Columns[0].ClipRect);
|
||||
table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Columns[0].DrawChannelCurrent);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(table->RowFlags & ImGuiTableRowFlags_Headers))
|
||||
table->RowBgColorCounter++;
|
||||
|
@ -2192,8 +2207,8 @@ void ImGui::TableEndCell(ImGuiTable* table)
|
|||
// Note that actual columns widths are computed in TableUpdateLayout().
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// Maximum column content width given current layout. Use column->MinX so this value on a per-column basis.
|
||||
float ImGui::TableGetMaxColumnWidth(const ImGuiTable* table, int column_n)
|
||||
// Maximum column content width given current layout. Use column->MinX so this value differs on a per-column basis.
|
||||
float ImGui::TableCalcMaxColumnWidth(const ImGuiTable* table, int column_n)
|
||||
{
|
||||
const ImGuiTableColumn* column = &table->Columns[column_n];
|
||||
float max_width = FLT_MAX;
|
||||
|
@ -2255,7 +2270,7 @@ void ImGui::TableSetColumnWidth(int column_n, float width)
|
|||
// Compare both requested and actual given width to avoid overwriting requested width when column is stuck (minimum size, bounded)
|
||||
IM_ASSERT(table->MinColumnWidth > 0.0f);
|
||||
const float min_width = table->MinColumnWidth;
|
||||
const float max_width = ImMax(min_width, TableGetMaxColumnWidth(table, column_n));
|
||||
const float max_width = ImMax(min_width, column_0->WidthMax); // Don't use TableCalcMaxColumnWidth() here as it would rely on MinX from last instance (#7933)
|
||||
column_0_width = ImClamp(column_0_width, min_width, max_width);
|
||||
if (column_0->WidthGiven == column_0_width || column_0->WidthRequest == column_0_width)
|
||||
return;
|
||||
|
@ -2740,7 +2755,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
|
|||
const ImU32 outer_col = table->BorderColorStrong;
|
||||
if ((table->Flags & ImGuiTableFlags_BordersOuter) == ImGuiTableFlags_BordersOuter)
|
||||
{
|
||||
inner_drawlist->AddRect(outer_border.Min, outer_border.Max + ImVec2(1, 1), outer_col, 0.0f, 0, border_size);
|
||||
inner_drawlist->AddRect(outer_border.Min, outer_border.Max, outer_col, 0.0f, 0, border_size);
|
||||
}
|
||||
else if (table->Flags & ImGuiTableFlags_BordersOuterV)
|
||||
{
|
||||
|
@ -3004,7 +3019,8 @@ float ImGui::TableGetHeaderAngledMaxLabelWidth()
|
|||
// The intent is that advanced users willing to create customized headers would not need to use this helper
|
||||
// and can create their own! For example: TableHeader() may be preceded by Checkbox() or other custom widgets.
|
||||
// See 'Demo->Tables->Custom headers' for a demonstration of implementing a custom version of this.
|
||||
// This code is constructed to not make much use of internal functions, as it is intended to be a template to copy.
|
||||
// This code is intentionally written to not make much use of internal functions, to give you better direction
|
||||
// if you need to write your own.
|
||||
// FIXME-TABLE: TableOpenContextMenu() and TableGetHeaderRowHeight() are not public.
|
||||
void ImGui::TableHeadersRow()
|
||||
{
|
||||
|
@ -3012,7 +3028,8 @@ void ImGui::TableHeadersRow()
|
|||
ImGuiTable* table = g.CurrentTable;
|
||||
IM_ASSERT(table != NULL && "Need to call TableHeadersRow() after BeginTable()!");
|
||||
|
||||
// Layout if not already done (this is automatically done by TableNextRow, we do it here solely to facilitate stepping in debugger as it is frequent to step in TableUpdateLayout)
|
||||
// Call layout if not already done. This is automatically done by TableNextRow: we do it here _only_ to make
|
||||
// it easier to debug-step in TableUpdateLayout(). Your own version of this function doesn't need this.
|
||||
if (!table->IsLayoutLocked)
|
||||
TableUpdateLayout(table);
|
||||
|
||||
|
@ -3029,8 +3046,7 @@ void ImGui::TableHeadersRow()
|
|||
if (!TableSetColumnIndex(column_n))
|
||||
continue;
|
||||
|
||||
// Push an id to allow unnamed labels (generally accidental, but let's behave nicely with them)
|
||||
// In your own code you may omit the PushID/PopID all-together, provided you know they won't collide.
|
||||
// Push an id to allow empty/unnamed headers. This is also idiomatic as it ensure there is a consistent ID path to access columns (for e.g. automation)
|
||||
const char* name = (TableGetColumnFlags(column_n) & ImGuiTableColumnFlags_NoHeaderLabel) ? "" : TableGetColumnName(column_n);
|
||||
PushID(column_n);
|
||||
TableHeader(name);
|
||||
|
@ -3269,7 +3285,7 @@ void ImGui::TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label
|
|||
ButtonBehavior(row_r, row_id, NULL, NULL);
|
||||
KeepAliveID(row_id);
|
||||
|
||||
const float ascent_scaled = g.Font->Ascent * (g.FontSize / g.Font->FontSize); // FIXME: Standardize those scaling factors better
|
||||
const float ascent_scaled = g.Font->Ascent * g.FontScale; // FIXME: Standardize those scaling factors better
|
||||
const float line_off_for_ascent_x = (ImMax((g.FontSize - ascent_scaled) * 0.5f, 0.0f) / -sin_a) * (flip_label ? -1.0f : 1.0f);
|
||||
const ImVec2 padding = g.Style.CellPadding; // We will always use swapped component
|
||||
const ImVec2 align = g.Style.TableAngledHeadersTextAlign;
|
||||
|
@ -3471,7 +3487,7 @@ void ImGui::TableDrawDefaultContextMenu(ImGuiTable* table, ImGuiTableFlags flags
|
|||
Separator();
|
||||
want_separator = true;
|
||||
|
||||
PushItemFlag(ImGuiItemFlags_SelectableDontClosePopup, true);
|
||||
PushItemFlag(ImGuiItemFlags_AutoClosePopups, false);
|
||||
for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++)
|
||||
{
|
||||
ImGuiTableColumn* other_column = &table->Columns[other_column_n];
|
||||
|
@ -4425,12 +4441,12 @@ void ImGui::EndColumns()
|
|||
NavUpdateCurrentWindowIsScrollPushableX();
|
||||
}
|
||||
|
||||
void ImGui::Columns(int columns_count, const char* id, bool border)
|
||||
void ImGui::Columns(int columns_count, const char* id, bool borders)
|
||||
{
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
IM_ASSERT(columns_count >= 1);
|
||||
|
||||
ImGuiOldColumnFlags flags = (border ? 0 : ImGuiOldColumnFlags_NoBorder);
|
||||
ImGuiOldColumnFlags flags = (borders ? 0 : ImGuiOldColumnFlags_NoBorder);
|
||||
//flags |= ImGuiOldColumnFlags_NoPreserveWidths; // NB: Legacy behavior
|
||||
ImGuiOldColumns* columns = window->DC.CurrentColumns;
|
||||
if (columns != NULL && columns->Count == columns_count && columns->Flags == flags)
|
||||
|
|
1479
source/engine/thirdparty/imgui/imgui_widgets.cpp
vendored
1479
source/engine/thirdparty/imgui/imgui_widgets.cpp
vendored
File diff suppressed because it is too large
Load diff
3261
source/engine/thirdparty/imgui/imnodes.cpp
vendored
Normal file
3261
source/engine/thirdparty/imgui/imnodes.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
438
source/engine/thirdparty/imgui/imnodes.h
vendored
Normal file
438
source/engine/thirdparty/imgui/imnodes.h
vendored
Normal file
|
@ -0,0 +1,438 @@
|
|||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <imgui.h>
|
||||
|
||||
#ifdef IMNODES_USER_CONFIG
|
||||
#include IMNODES_USER_CONFIG
|
||||
#endif
|
||||
|
||||
#ifndef IMNODES_NAMESPACE
|
||||
#define IMNODES_NAMESPACE ImNodes
|
||||
#endif
|
||||
|
||||
typedef int ImNodesCol; // -> enum ImNodesCol_
|
||||
typedef int ImNodesStyleVar; // -> enum ImNodesStyleVar_
|
||||
typedef int ImNodesStyleFlags; // -> enum ImNodesStyleFlags_
|
||||
typedef int ImNodesPinShape; // -> enum ImNodesPinShape_
|
||||
typedef int ImNodesAttributeFlags; // -> enum ImNodesAttributeFlags_
|
||||
typedef int ImNodesMiniMapLocation; // -> enum ImNodesMiniMapLocation_
|
||||
|
||||
enum ImNodesCol_
|
||||
{
|
||||
ImNodesCol_NodeBackground = 0,
|
||||
ImNodesCol_NodeBackgroundHovered,
|
||||
ImNodesCol_NodeBackgroundSelected,
|
||||
ImNodesCol_NodeOutline,
|
||||
ImNodesCol_TitleBar,
|
||||
ImNodesCol_TitleBarHovered,
|
||||
ImNodesCol_TitleBarSelected,
|
||||
ImNodesCol_Link,
|
||||
ImNodesCol_LinkHovered,
|
||||
ImNodesCol_LinkSelected,
|
||||
ImNodesCol_Pin,
|
||||
ImNodesCol_PinHovered,
|
||||
ImNodesCol_BoxSelector,
|
||||
ImNodesCol_BoxSelectorOutline,
|
||||
ImNodesCol_GridBackground,
|
||||
ImNodesCol_GridLine,
|
||||
ImNodesCol_GridLinePrimary,
|
||||
ImNodesCol_MiniMapBackground,
|
||||
ImNodesCol_MiniMapBackgroundHovered,
|
||||
ImNodesCol_MiniMapOutline,
|
||||
ImNodesCol_MiniMapOutlineHovered,
|
||||
ImNodesCol_MiniMapNodeBackground,
|
||||
ImNodesCol_MiniMapNodeBackgroundHovered,
|
||||
ImNodesCol_MiniMapNodeBackgroundSelected,
|
||||
ImNodesCol_MiniMapNodeOutline,
|
||||
ImNodesCol_MiniMapLink,
|
||||
ImNodesCol_MiniMapLinkSelected,
|
||||
ImNodesCol_MiniMapCanvas,
|
||||
ImNodesCol_MiniMapCanvasOutline,
|
||||
ImNodesCol_COUNT
|
||||
};
|
||||
|
||||
enum ImNodesStyleVar_
|
||||
{
|
||||
ImNodesStyleVar_GridSpacing = 0,
|
||||
ImNodesStyleVar_NodeCornerRounding,
|
||||
ImNodesStyleVar_NodePadding,
|
||||
ImNodesStyleVar_NodeBorderThickness,
|
||||
ImNodesStyleVar_LinkThickness,
|
||||
ImNodesStyleVar_LinkLineSegmentsPerLength,
|
||||
ImNodesStyleVar_LinkHoverDistance,
|
||||
ImNodesStyleVar_PinCircleRadius,
|
||||
ImNodesStyleVar_PinQuadSideLength,
|
||||
ImNodesStyleVar_PinTriangleSideLength,
|
||||
ImNodesStyleVar_PinLineThickness,
|
||||
ImNodesStyleVar_PinHoverRadius,
|
||||
ImNodesStyleVar_PinOffset,
|
||||
ImNodesStyleVar_MiniMapPadding,
|
||||
ImNodesStyleVar_MiniMapOffset,
|
||||
ImNodesStyleVar_COUNT
|
||||
};
|
||||
|
||||
enum ImNodesStyleFlags_
|
||||
{
|
||||
ImNodesStyleFlags_None = 0,
|
||||
ImNodesStyleFlags_NodeOutline = 1 << 0,
|
||||
ImNodesStyleFlags_GridLines = 1 << 2,
|
||||
ImNodesStyleFlags_GridLinesPrimary = 1 << 3,
|
||||
ImNodesStyleFlags_GridSnapping = 1 << 4
|
||||
};
|
||||
|
||||
enum ImNodesPinShape_
|
||||
{
|
||||
ImNodesPinShape_Circle,
|
||||
ImNodesPinShape_CircleFilled,
|
||||
ImNodesPinShape_Triangle,
|
||||
ImNodesPinShape_TriangleFilled,
|
||||
ImNodesPinShape_Quad,
|
||||
ImNodesPinShape_QuadFilled
|
||||
};
|
||||
|
||||
// This enum controls the way the attribute pins behave.
|
||||
enum ImNodesAttributeFlags_
|
||||
{
|
||||
ImNodesAttributeFlags_None = 0,
|
||||
// Allow detaching a link by left-clicking and dragging the link at a pin it is connected to.
|
||||
// NOTE: the user has to actually delete the link for this to work. A deleted link can be
|
||||
// detected by calling IsLinkDestroyed() after EndNodeEditor().
|
||||
ImNodesAttributeFlags_EnableLinkDetachWithDragClick = 1 << 0,
|
||||
// Visual snapping of an in progress link will trigger IsLink Created/Destroyed events. Allows
|
||||
// for previewing the creation of a link while dragging it across attributes. See here for demo:
|
||||
// https://github.com/Nelarius/imnodes/issues/41#issuecomment-647132113 NOTE: the user has to
|
||||
// actually delete the link for this to work. A deleted link can be detected by calling
|
||||
// IsLinkDestroyed() after EndNodeEditor().
|
||||
ImNodesAttributeFlags_EnableLinkCreationOnSnap = 1 << 1
|
||||
};
|
||||
|
||||
struct ImNodesIO
|
||||
{
|
||||
struct EmulateThreeButtonMouse
|
||||
{
|
||||
EmulateThreeButtonMouse();
|
||||
|
||||
// The keyboard modifier to use in combination with mouse left click to pan the editor view.
|
||||
// Set to NULL by default. To enable this feature, set the modifier to point to a boolean
|
||||
// indicating the state of a modifier. For example,
|
||||
//
|
||||
// ImNodes::GetIO().EmulateThreeButtonMouse.Modifier = &ImGui::GetIO().KeyAlt;
|
||||
const bool* Modifier;
|
||||
} EmulateThreeButtonMouse;
|
||||
|
||||
struct LinkDetachWithModifierClick
|
||||
{
|
||||
LinkDetachWithModifierClick();
|
||||
|
||||
// Pointer to a boolean value indicating when the desired modifier is pressed. Set to NULL
|
||||
// by default. To enable the feature, set the modifier to point to a boolean indicating the
|
||||
// state of a modifier. For example,
|
||||
//
|
||||
// ImNodes::GetIO().LinkDetachWithModifierClick.Modifier = &ImGui::GetIO().KeyCtrl;
|
||||
//
|
||||
// Left-clicking a link with this modifier pressed will detach that link. NOTE: the user has
|
||||
// to actually delete the link for this to work. A deleted link can be detected by calling
|
||||
// IsLinkDestroyed() after EndNodeEditor().
|
||||
const bool* Modifier;
|
||||
} LinkDetachWithModifierClick;
|
||||
|
||||
struct MultipleSelectModifier
|
||||
{
|
||||
MultipleSelectModifier();
|
||||
|
||||
// Pointer to a boolean value indicating when the desired modifier is pressed. Set to NULL
|
||||
// by default. To enable the feature, set the modifier to point to a boolean indicating the
|
||||
// state of a modifier. For example,
|
||||
//
|
||||
// ImNodes::GetIO().MultipleSelectModifier.Modifier = &ImGui::GetIO().KeyCtrl;
|
||||
//
|
||||
// Left-clicking a node with this modifier pressed will add the node to the list of
|
||||
// currently selected nodes. If this value is NULL, the Ctrl key will be used.
|
||||
const bool* Modifier;
|
||||
} MultipleSelectModifier;
|
||||
|
||||
// Holding alt mouse button pans the node area, by default middle mouse button will be used
|
||||
// Set based on ImGuiMouseButton values
|
||||
int AltMouseButton;
|
||||
|
||||
// Panning speed when dragging an element and mouse is outside the main editor view.
|
||||
float AutoPanningSpeed;
|
||||
|
||||
ImNodesIO();
|
||||
};
|
||||
|
||||
struct ImNodesStyle
|
||||
{
|
||||
float GridSpacing;
|
||||
|
||||
float NodeCornerRounding;
|
||||
ImVec2 NodePadding;
|
||||
float NodeBorderThickness;
|
||||
|
||||
float LinkThickness;
|
||||
float LinkLineSegmentsPerLength;
|
||||
float LinkHoverDistance;
|
||||
|
||||
// The following variables control the look and behavior of the pins. The default size of each
|
||||
// pin shape is balanced to occupy approximately the same surface area on the screen.
|
||||
|
||||
// The circle radius used when the pin shape is either ImNodesPinShape_Circle or
|
||||
// ImNodesPinShape_CircleFilled.
|
||||
float PinCircleRadius;
|
||||
// The quad side length used when the shape is either ImNodesPinShape_Quad or
|
||||
// ImNodesPinShape_QuadFilled.
|
||||
float PinQuadSideLength;
|
||||
// The equilateral triangle side length used when the pin shape is either
|
||||
// ImNodesPinShape_Triangle or ImNodesPinShape_TriangleFilled.
|
||||
float PinTriangleSideLength;
|
||||
// The thickness of the line used when the pin shape is not filled.
|
||||
float PinLineThickness;
|
||||
// The radius from the pin's center position inside of which it is detected as being hovered
|
||||
// over.
|
||||
float PinHoverRadius;
|
||||
// Offsets the pins' positions from the edge of the node to the outside of the node.
|
||||
float PinOffset;
|
||||
|
||||
// Mini-map padding size between mini-map edge and mini-map content.
|
||||
ImVec2 MiniMapPadding;
|
||||
// Mini-map offset from the screen side.
|
||||
ImVec2 MiniMapOffset;
|
||||
|
||||
// By default, ImNodesStyleFlags_NodeOutline and ImNodesStyleFlags_Gridlines are enabled.
|
||||
ImNodesStyleFlags Flags;
|
||||
// Set these mid-frame using Push/PopColorStyle. You can index this color array with with a
|
||||
// ImNodesCol value.
|
||||
unsigned int Colors[ImNodesCol_COUNT];
|
||||
|
||||
ImNodesStyle();
|
||||
};
|
||||
|
||||
enum ImNodesMiniMapLocation_
|
||||
{
|
||||
ImNodesMiniMapLocation_BottomLeft,
|
||||
ImNodesMiniMapLocation_BottomRight,
|
||||
ImNodesMiniMapLocation_TopLeft,
|
||||
ImNodesMiniMapLocation_TopRight,
|
||||
};
|
||||
|
||||
struct ImGuiContext;
|
||||
struct ImVec2;
|
||||
|
||||
struct ImNodesContext;
|
||||
|
||||
// An editor context corresponds to a set of nodes in a single workspace (created with a single
|
||||
// Begin/EndNodeEditor pair)
|
||||
//
|
||||
// By default, the library creates an editor context behind the scenes, so using any of the imnodes
|
||||
// functions doesn't require you to explicitly create a context.
|
||||
struct ImNodesEditorContext;
|
||||
|
||||
// Callback type used to specify special behavior when hovering a node in the minimap
|
||||
#ifndef ImNodesMiniMapNodeHoveringCallback
|
||||
typedef void (*ImNodesMiniMapNodeHoveringCallback)(int, void*);
|
||||
#endif
|
||||
|
||||
#ifndef ImNodesMiniMapNodeHoveringCallbackUserData
|
||||
typedef void* ImNodesMiniMapNodeHoveringCallbackUserData;
|
||||
#endif
|
||||
|
||||
namespace IMNODES_NAMESPACE
|
||||
{
|
||||
// Call this function if you are compiling imnodes in to a dll, separate from ImGui. Calling this
|
||||
// function sets the GImGui global variable, which is not shared across dll boundaries.
|
||||
void SetImGuiContext(ImGuiContext* ctx);
|
||||
|
||||
ImNodesContext* CreateContext();
|
||||
void DestroyContext(ImNodesContext* ctx = NULL); // NULL = destroy current context
|
||||
ImNodesContext* GetCurrentContext();
|
||||
void SetCurrentContext(ImNodesContext* ctx);
|
||||
|
||||
ImNodesEditorContext* EditorContextCreate();
|
||||
void EditorContextFree(ImNodesEditorContext*);
|
||||
void EditorContextSet(ImNodesEditorContext*);
|
||||
ImVec2 EditorContextGetPanning();
|
||||
void EditorContextResetPanning(const ImVec2& pos);
|
||||
void EditorContextMoveToNode(const int node_id);
|
||||
|
||||
ImNodesIO& GetIO();
|
||||
|
||||
// Returns the global style struct. See the struct declaration for default values.
|
||||
ImNodesStyle& GetStyle();
|
||||
// Style presets matching the dear imgui styles of the same name. If dest is NULL, the active
|
||||
// context's ImNodesStyle instance will be used as the destination.
|
||||
void StyleColorsDark(ImNodesStyle* dest = NULL); // on by default
|
||||
void StyleColorsClassic(ImNodesStyle* dest = NULL);
|
||||
void StyleColorsLight(ImNodesStyle* dest = NULL);
|
||||
|
||||
// The top-level function call. Call this before calling BeginNode/EndNode. Calling this function
|
||||
// will result the node editor grid workspace being rendered.
|
||||
void BeginNodeEditor();
|
||||
void EndNodeEditor();
|
||||
|
||||
// Add a navigable minimap to the editor; call before EndNodeEditor after all
|
||||
// nodes and links have been specified
|
||||
void MiniMap(
|
||||
const float minimap_size_fraction = 0.2f,
|
||||
const ImNodesMiniMapLocation location = ImNodesMiniMapLocation_TopLeft,
|
||||
const ImNodesMiniMapNodeHoveringCallback node_hovering_callback = NULL,
|
||||
const ImNodesMiniMapNodeHoveringCallbackUserData node_hovering_callback_data = NULL);
|
||||
|
||||
// Use PushColorStyle and PopColorStyle to modify ImNodesStyle::Colors mid-frame.
|
||||
void PushColorStyle(ImNodesCol item, unsigned int color);
|
||||
void PopColorStyle();
|
||||
void PushStyleVar(ImNodesStyleVar style_item, float value);
|
||||
void PushStyleVar(ImNodesStyleVar style_item, const ImVec2& value);
|
||||
void PopStyleVar(int count = 1);
|
||||
|
||||
// id can be any positive or negative integer, but INT_MIN is currently reserved for internal use.
|
||||
void BeginNode(int id);
|
||||
void EndNode();
|
||||
|
||||
ImVec2 GetNodeDimensions(int id);
|
||||
|
||||
// Place your node title bar content (such as the node title, using ImGui::Text) between the
|
||||
// following function calls. These functions have to be called before adding any attributes, or the
|
||||
// layout of the node will be incorrect.
|
||||
void BeginNodeTitleBar();
|
||||
void EndNodeTitleBar();
|
||||
|
||||
// Attributes are ImGui UI elements embedded within the node. Attributes can have pin shapes
|
||||
// rendered next to them. Links are created between pins.
|
||||
//
|
||||
// The activity status of an attribute can be checked via the IsAttributeActive() and
|
||||
// IsAnyAttributeActive() function calls. This is one easy way of checking for any changes made to
|
||||
// an attribute's drag float UI, for instance.
|
||||
//
|
||||
// Each attribute id must be unique.
|
||||
|
||||
// Create an input attribute block. The pin is rendered on left side.
|
||||
void BeginInputAttribute(int id, ImNodesPinShape shape = ImNodesPinShape_CircleFilled);
|
||||
void EndInputAttribute();
|
||||
// Create an output attribute block. The pin is rendered on the right side.
|
||||
void BeginOutputAttribute(int id, ImNodesPinShape shape = ImNodesPinShape_CircleFilled);
|
||||
void EndOutputAttribute();
|
||||
// Create a static attribute block. A static attribute has no pin, and therefore can't be linked to
|
||||
// anything. However, you can still use IsAttributeActive() and IsAnyAttributeActive() to check for
|
||||
// attribute activity.
|
||||
void BeginStaticAttribute(int id);
|
||||
void EndStaticAttribute();
|
||||
|
||||
// Push a single AttributeFlags value. By default, only AttributeFlags_None is set.
|
||||
void PushAttributeFlag(ImNodesAttributeFlags flag);
|
||||
void PopAttributeFlag();
|
||||
|
||||
// Render a link between attributes.
|
||||
// The attributes ids used here must match the ids used in Begin(Input|Output)Attribute function
|
||||
// calls. The order of start_attr and end_attr doesn't make a difference for rendering the link.
|
||||
void Link(int id, int start_attribute_id, int end_attribute_id);
|
||||
|
||||
// Enable or disable the ability to click and drag a specific node.
|
||||
void SetNodeDraggable(int node_id, const bool draggable);
|
||||
|
||||
// The node's position can be expressed in three coordinate systems:
|
||||
// * screen space coordinates, -- the origin is the upper left corner of the window.
|
||||
// * editor space coordinates -- the origin is the upper left corner of the node editor window
|
||||
// * grid space coordinates, -- the origin is the upper left corner of the node editor window,
|
||||
// translated by the current editor panning vector (see EditorContextGetPanning() and
|
||||
// EditorContextResetPanning())
|
||||
|
||||
// Use the following functions to get and set the node's coordinates in these coordinate systems.
|
||||
|
||||
void SetNodeScreenSpacePos(int node_id, const ImVec2& screen_space_pos);
|
||||
void SetNodeEditorSpacePos(int node_id, const ImVec2& editor_space_pos);
|
||||
void SetNodeGridSpacePos(int node_id, const ImVec2& grid_pos);
|
||||
|
||||
ImVec2 GetNodeScreenSpacePos(const int node_id);
|
||||
ImVec2 GetNodeEditorSpacePos(const int node_id);
|
||||
ImVec2 GetNodeGridSpacePos(const int node_id);
|
||||
|
||||
// If ImNodesStyleFlags_GridSnapping is enabled, snap the specified node's origin to the grid.
|
||||
void SnapNodeToGrid(int node_id);
|
||||
|
||||
// Returns true if the current node editor canvas is being hovered over by the mouse, and is not
|
||||
// blocked by any other windows.
|
||||
bool IsEditorHovered();
|
||||
// The following functions return true if a UI element is being hovered over by the mouse cursor.
|
||||
// Assigns the id of the UI element being hovered over to the function argument. Use these functions
|
||||
// after EndNodeEditor() has been called.
|
||||
bool IsNodeHovered(int* node_id);
|
||||
bool IsLinkHovered(int* link_id);
|
||||
bool IsPinHovered(int* attribute_id);
|
||||
|
||||
// Use The following two functions to query the number of selected nodes or links in the current
|
||||
// editor. Use after calling EndNodeEditor().
|
||||
int NumSelectedNodes();
|
||||
int NumSelectedLinks();
|
||||
// Get the selected node/link ids. The pointer argument should point to an integer array with at
|
||||
// least as many elements as the respective NumSelectedNodes/NumSelectedLinks function call
|
||||
// returned.
|
||||
void GetSelectedNodes(int* node_ids);
|
||||
void GetSelectedLinks(int* link_ids);
|
||||
// Clears the list of selected nodes/links. Useful if you want to delete a selected node or link.
|
||||
void ClearNodeSelection();
|
||||
void ClearLinkSelection();
|
||||
// Use the following functions to add or remove individual nodes or links from the current editors
|
||||
// selection. Note that all functions require the id to be an existing valid id for this editor.
|
||||
// Select-functions has the precondition that the object is currently considered unselected.
|
||||
// Clear-functions has the precondition that the object is currently considered selected.
|
||||
// Preconditions listed above can be checked via IsNodeSelected/IsLinkSelected if not already
|
||||
// known.
|
||||
void SelectNode(int node_id);
|
||||
void ClearNodeSelection(int node_id);
|
||||
bool IsNodeSelected(int node_id);
|
||||
void SelectLink(int link_id);
|
||||
void ClearLinkSelection(int link_id);
|
||||
bool IsLinkSelected(int link_id);
|
||||
|
||||
// Was the previous attribute active? This will continuously return true while the left mouse button
|
||||
// is being pressed over the UI content of the attribute.
|
||||
bool IsAttributeActive();
|
||||
// Was any attribute active? If so, sets the active attribute id to the output function argument.
|
||||
bool IsAnyAttributeActive(int* attribute_id = NULL);
|
||||
|
||||
// Use the following functions to query a change of state for an existing link, or new link. Call
|
||||
// these after EndNodeEditor().
|
||||
|
||||
// Did the user start dragging a new link from a pin?
|
||||
bool IsLinkStarted(int* started_at_attribute_id);
|
||||
// Did the user drop the dragged link before attaching it to a pin?
|
||||
// There are two different kinds of situations to consider when handling this event:
|
||||
// 1) a link which is created at a pin and then dropped
|
||||
// 2) an existing link which is detached from a pin and then dropped
|
||||
// Use the including_detached_links flag to control whether this function triggers when the user
|
||||
// detaches a link and drops it.
|
||||
bool IsLinkDropped(int* started_at_attribute_id = NULL, bool including_detached_links = true);
|
||||
// Did the user finish creating a new link?
|
||||
bool IsLinkCreated(
|
||||
int* started_at_attribute_id,
|
||||
int* ended_at_attribute_id,
|
||||
bool* created_from_snap = NULL);
|
||||
bool IsLinkCreated(
|
||||
int* started_at_node_id,
|
||||
int* started_at_attribute_id,
|
||||
int* ended_at_node_id,
|
||||
int* ended_at_attribute_id,
|
||||
bool* created_from_snap = NULL);
|
||||
|
||||
// Was an existing link detached from a pin by the user? The detached link's id is assigned to the
|
||||
// output argument link_id.
|
||||
bool IsLinkDestroyed(int* link_id);
|
||||
|
||||
// Use the following functions to write the editor context's state to a string, or directly to a
|
||||
// file. The editor context is serialized in the INI file format.
|
||||
|
||||
const char* SaveCurrentEditorStateToIniString(size_t* data_size = NULL);
|
||||
const char* SaveEditorStateToIniString(
|
||||
const ImNodesEditorContext* editor,
|
||||
size_t* data_size = NULL);
|
||||
|
||||
void LoadCurrentEditorStateFromIniString(const char* data, size_t data_size);
|
||||
void LoadEditorStateFromIniString(ImNodesEditorContext* editor, const char* data, size_t data_size);
|
||||
|
||||
void SaveCurrentEditorStateToIniFile(const char* file_name);
|
||||
void SaveEditorStateToIniFile(const ImNodesEditorContext* editor, const char* file_name);
|
||||
|
||||
void LoadCurrentEditorStateFromIniFile(const char* file_name);
|
||||
void LoadEditorStateFromIniFile(ImNodesEditorContext* editor, const char* file_name);
|
||||
} // namespace IMNODES_NAMESPACE
|
500
source/engine/thirdparty/imgui/imnodes_internal.h
vendored
Normal file
500
source/engine/thirdparty/imgui/imnodes_internal.h
vendored
Normal file
|
@ -0,0 +1,500 @@
|
|||
#pragma once
|
||||
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
|
||||
#include "imnodes.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
// the structure of this file:
|
||||
//
|
||||
// [SECTION] internal enums
|
||||
// [SECTION] internal data structures
|
||||
// [SECTION] global and editor context structs
|
||||
// [SECTION] object pool implementation
|
||||
|
||||
struct ImNodesContext;
|
||||
|
||||
extern ImNodesContext* GImNodes;
|
||||
|
||||
// [SECTION] internal enums
|
||||
|
||||
typedef int ImNodesScope;
|
||||
typedef int ImNodesAttributeType;
|
||||
typedef int ImNodesUIState;
|
||||
typedef int ImNodesClickInteractionType;
|
||||
typedef int ImNodesLinkCreationType;
|
||||
|
||||
enum ImNodesScope_
|
||||
{
|
||||
ImNodesScope_None = 1,
|
||||
ImNodesScope_Editor = 1 << 1,
|
||||
ImNodesScope_Node = 1 << 2,
|
||||
ImNodesScope_Attribute = 1 << 3
|
||||
};
|
||||
|
||||
enum ImNodesAttributeType_
|
||||
{
|
||||
ImNodesAttributeType_None,
|
||||
ImNodesAttributeType_Input,
|
||||
ImNodesAttributeType_Output
|
||||
};
|
||||
|
||||
enum ImNodesUIState_
|
||||
{
|
||||
ImNodesUIState_None = 0,
|
||||
ImNodesUIState_LinkStarted = 1 << 0,
|
||||
ImNodesUIState_LinkDropped = 1 << 1,
|
||||
ImNodesUIState_LinkCreated = 1 << 2
|
||||
};
|
||||
|
||||
enum ImNodesClickInteractionType_
|
||||
{
|
||||
ImNodesClickInteractionType_Node,
|
||||
ImNodesClickInteractionType_Link,
|
||||
ImNodesClickInteractionType_LinkCreation,
|
||||
ImNodesClickInteractionType_Panning,
|
||||
ImNodesClickInteractionType_BoxSelection,
|
||||
ImNodesClickInteractionType_ImGuiItem,
|
||||
ImNodesClickInteractionType_None
|
||||
};
|
||||
|
||||
enum ImNodesLinkCreationType_
|
||||
{
|
||||
ImNodesLinkCreationType_Standard,
|
||||
ImNodesLinkCreationType_FromDetach
|
||||
};
|
||||
|
||||
// [SECTION] internal data structures
|
||||
|
||||
// The object T must have the following interface:
|
||||
//
|
||||
// struct T
|
||||
// {
|
||||
// T();
|
||||
//
|
||||
// int id;
|
||||
// };
|
||||
template<typename T>
|
||||
struct ImObjectPool
|
||||
{
|
||||
ImVector<T> Pool;
|
||||
ImVector<bool> InUse;
|
||||
ImVector<int> FreeList;
|
||||
ImGuiStorage IdMap;
|
||||
|
||||
ImObjectPool() : Pool(), InUse(), FreeList(), IdMap() {}
|
||||
};
|
||||
|
||||
// Emulates std::optional<int> using the sentinel value `INVALID_INDEX`.
|
||||
struct ImOptionalIndex
|
||||
{
|
||||
ImOptionalIndex() : _Index(INVALID_INDEX) {}
|
||||
ImOptionalIndex(const int value) : _Index(value) {}
|
||||
|
||||
// Observers
|
||||
|
||||
inline bool HasValue() const { return _Index != INVALID_INDEX; }
|
||||
|
||||
inline int Value() const
|
||||
{
|
||||
IM_ASSERT(HasValue());
|
||||
return _Index;
|
||||
}
|
||||
|
||||
// Modifiers
|
||||
|
||||
inline ImOptionalIndex& operator=(const int value)
|
||||
{
|
||||
_Index = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void Reset() { _Index = INVALID_INDEX; }
|
||||
|
||||
inline bool operator==(const ImOptionalIndex& rhs) const { return _Index == rhs._Index; }
|
||||
|
||||
inline bool operator==(const int rhs) const { return _Index == rhs; }
|
||||
|
||||
inline bool operator!=(const ImOptionalIndex& rhs) const { return _Index != rhs._Index; }
|
||||
|
||||
inline bool operator!=(const int rhs) const { return _Index != rhs; }
|
||||
|
||||
static const int INVALID_INDEX = -1;
|
||||
|
||||
private:
|
||||
int _Index;
|
||||
};
|
||||
|
||||
struct ImNodeData
|
||||
{
|
||||
int Id;
|
||||
ImVec2 Origin; // The node origin is in editor space
|
||||
ImRect TitleBarContentRect;
|
||||
ImRect Rect;
|
||||
|
||||
struct
|
||||
{
|
||||
ImU32 Background, BackgroundHovered, BackgroundSelected, Outline, Titlebar, TitlebarHovered,
|
||||
TitlebarSelected;
|
||||
} ColorStyle;
|
||||
|
||||
struct
|
||||
{
|
||||
float CornerRounding;
|
||||
ImVec2 Padding;
|
||||
float BorderThickness;
|
||||
} LayoutStyle;
|
||||
|
||||
ImVector<int> PinIndices;
|
||||
bool Draggable;
|
||||
|
||||
ImNodeData(const int node_id)
|
||||
: Id(node_id), Origin(0.0f, 0.0f), TitleBarContentRect(),
|
||||
Rect(ImVec2(0.0f, 0.0f), ImVec2(0.0f, 0.0f)), ColorStyle(), LayoutStyle(), PinIndices(),
|
||||
Draggable(true)
|
||||
{
|
||||
}
|
||||
|
||||
~ImNodeData() { Id = INT_MIN; }
|
||||
};
|
||||
|
||||
struct ImPinData
|
||||
{
|
||||
int Id;
|
||||
int ParentNodeIdx;
|
||||
ImRect AttributeRect;
|
||||
ImNodesAttributeType Type;
|
||||
ImNodesPinShape Shape;
|
||||
ImVec2 Pos; // screen-space coordinates
|
||||
int Flags;
|
||||
|
||||
struct
|
||||
{
|
||||
ImU32 Background, Hovered;
|
||||
} ColorStyle;
|
||||
|
||||
ImPinData(const int pin_id)
|
||||
: Id(pin_id), ParentNodeIdx(), AttributeRect(), Type(ImNodesAttributeType_None),
|
||||
Shape(ImNodesPinShape_CircleFilled), Pos(), Flags(ImNodesAttributeFlags_None),
|
||||
ColorStyle()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct ImLinkData
|
||||
{
|
||||
int Id;
|
||||
int StartPinIdx, EndPinIdx;
|
||||
|
||||
struct
|
||||
{
|
||||
ImU32 Base, Hovered, Selected;
|
||||
} ColorStyle;
|
||||
|
||||
ImLinkData(const int link_id) : Id(link_id), StartPinIdx(), EndPinIdx(), ColorStyle() {}
|
||||
};
|
||||
|
||||
struct ImClickInteractionState
|
||||
{
|
||||
ImNodesClickInteractionType Type;
|
||||
|
||||
struct
|
||||
{
|
||||
int StartPinIdx;
|
||||
ImOptionalIndex EndPinIdx;
|
||||
ImNodesLinkCreationType Type;
|
||||
} LinkCreation;
|
||||
|
||||
struct
|
||||
{
|
||||
ImRect Rect; // Coordinates in grid space
|
||||
} BoxSelector;
|
||||
|
||||
ImClickInteractionState() : Type(ImNodesClickInteractionType_None) {}
|
||||
};
|
||||
|
||||
struct ImNodesColElement
|
||||
{
|
||||
ImU32 Color;
|
||||
ImNodesCol Item;
|
||||
|
||||
ImNodesColElement(const ImU32 c, const ImNodesCol s) : Color(c), Item(s) {}
|
||||
};
|
||||
|
||||
struct ImNodesStyleVarElement
|
||||
{
|
||||
ImNodesStyleVar Item;
|
||||
float FloatValue[2];
|
||||
|
||||
ImNodesStyleVarElement(const ImNodesStyleVar variable, const float value) : Item(variable)
|
||||
{
|
||||
FloatValue[0] = value;
|
||||
}
|
||||
|
||||
ImNodesStyleVarElement(const ImNodesStyleVar variable, const ImVec2 value) : Item(variable)
|
||||
{
|
||||
FloatValue[0] = value.x;
|
||||
FloatValue[1] = value.y;
|
||||
}
|
||||
};
|
||||
|
||||
// [SECTION] global and editor context structs
|
||||
|
||||
struct ImNodesEditorContext
|
||||
{
|
||||
ImObjectPool<ImNodeData> Nodes;
|
||||
ImObjectPool<ImPinData> Pins;
|
||||
ImObjectPool<ImLinkData> Links;
|
||||
|
||||
ImVector<int> NodeDepthOrder;
|
||||
|
||||
// ui related fields
|
||||
ImVec2 Panning;
|
||||
ImVec2 AutoPanningDelta;
|
||||
// Minimum and maximum extents of all content in grid space. Valid after final
|
||||
// ImNodes::EndNode() call.
|
||||
ImRect GridContentBounds;
|
||||
|
||||
ImVector<int> SelectedNodeIndices;
|
||||
ImVector<int> SelectedLinkIndices;
|
||||
|
||||
// Relative origins of selected nodes for snapping of dragged nodes
|
||||
ImVector<ImVec2> SelectedNodeOffsets;
|
||||
// Offset of the primary node origin relative to the mouse cursor.
|
||||
ImVec2 PrimaryNodeOffset;
|
||||
|
||||
ImClickInteractionState ClickInteraction;
|
||||
|
||||
// Mini-map state set by MiniMap()
|
||||
|
||||
bool MiniMapEnabled;
|
||||
ImNodesMiniMapLocation MiniMapLocation;
|
||||
float MiniMapSizeFraction;
|
||||
ImNodesMiniMapNodeHoveringCallback MiniMapNodeHoveringCallback;
|
||||
ImNodesMiniMapNodeHoveringCallbackUserData MiniMapNodeHoveringCallbackUserData;
|
||||
|
||||
// Mini-map state set during EndNodeEditor() call
|
||||
|
||||
ImRect MiniMapRectScreenSpace;
|
||||
ImRect MiniMapContentScreenSpace;
|
||||
float MiniMapScaling;
|
||||
|
||||
ImNodesEditorContext()
|
||||
: Nodes(), Pins(), Links(), Panning(0.f, 0.f), SelectedNodeIndices(), SelectedLinkIndices(),
|
||||
SelectedNodeOffsets(), PrimaryNodeOffset(0.f, 0.f), ClickInteraction(),
|
||||
MiniMapEnabled(false), MiniMapSizeFraction(0.0f), MiniMapNodeHoveringCallback(NULL),
|
||||
MiniMapNodeHoveringCallbackUserData(NULL), MiniMapScaling(0.0f)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct ImNodesContext
|
||||
{
|
||||
ImNodesEditorContext* DefaultEditorCtx;
|
||||
ImNodesEditorContext* EditorCtx;
|
||||
|
||||
// Canvas draw list and helper state
|
||||
ImDrawList* CanvasDrawList;
|
||||
ImGuiStorage NodeIdxToSubmissionIdx;
|
||||
ImVector<int> NodeIdxSubmissionOrder;
|
||||
ImVector<int> NodeIndicesOverlappingWithMouse;
|
||||
ImVector<int> OccludedPinIndices;
|
||||
|
||||
// Canvas extents
|
||||
ImVec2 CanvasOriginScreenSpace;
|
||||
ImRect CanvasRectScreenSpace;
|
||||
|
||||
// Debug helpers
|
||||
ImNodesScope CurrentScope;
|
||||
|
||||
// Configuration state
|
||||
ImNodesIO Io;
|
||||
ImNodesStyle Style;
|
||||
ImVector<ImNodesColElement> ColorModifierStack;
|
||||
ImVector<ImNodesStyleVarElement> StyleModifierStack;
|
||||
ImGuiTextBuffer TextBuffer;
|
||||
|
||||
int CurrentAttributeFlags;
|
||||
ImVector<int> AttributeFlagStack;
|
||||
|
||||
// UI element state
|
||||
int CurrentNodeIdx;
|
||||
int CurrentPinIdx;
|
||||
int CurrentAttributeId;
|
||||
|
||||
ImOptionalIndex HoveredNodeIdx;
|
||||
ImOptionalIndex HoveredLinkIdx;
|
||||
ImOptionalIndex HoveredPinIdx;
|
||||
|
||||
ImOptionalIndex DeletedLinkIdx;
|
||||
ImOptionalIndex SnapLinkIdx;
|
||||
|
||||
// Event helper state
|
||||
// TODO: this should be a part of a state machine, and not a member of the global struct.
|
||||
// Unclear what parts of the code this relates to.
|
||||
int ImNodesUIState;
|
||||
|
||||
int ActiveAttributeId;
|
||||
bool ActiveAttribute;
|
||||
|
||||
// ImGui::IO cache
|
||||
|
||||
ImVec2 MousePos;
|
||||
|
||||
bool LeftMouseClicked;
|
||||
bool LeftMouseReleased;
|
||||
bool AltMouseClicked;
|
||||
bool LeftMouseDragging;
|
||||
bool AltMouseDragging;
|
||||
float AltMouseScrollDelta;
|
||||
bool MultipleSelectModifier;
|
||||
};
|
||||
|
||||
namespace IMNODES_NAMESPACE
|
||||
{
|
||||
static inline ImNodesEditorContext& EditorContextGet()
|
||||
{
|
||||
// No editor context was set! Did you forget to call ImNodes::CreateContext()?
|
||||
IM_ASSERT(GImNodes->EditorCtx != NULL);
|
||||
return *GImNodes->EditorCtx;
|
||||
}
|
||||
|
||||
// [SECTION] ObjectPool implementation
|
||||
|
||||
template<typename T>
|
||||
static inline int ObjectPoolFind(const ImObjectPool<T>& objects, const int id)
|
||||
{
|
||||
const int index = objects.IdMap.GetInt(static_cast<ImGuiID>(id), -1);
|
||||
return index;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void ObjectPoolUpdate(ImObjectPool<T>& objects)
|
||||
{
|
||||
for (int i = 0; i < objects.InUse.size(); ++i)
|
||||
{
|
||||
const int id = objects.Pool[i].Id;
|
||||
|
||||
if (!objects.InUse[i] && objects.IdMap.GetInt(id, -1) == i)
|
||||
{
|
||||
objects.IdMap.SetInt(id, -1);
|
||||
objects.FreeList.push_back(i);
|
||||
(objects.Pool.Data + i)->~T();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void ObjectPoolUpdate(ImObjectPool<ImNodeData>& nodes)
|
||||
{
|
||||
for (int i = 0; i < nodes.InUse.size(); ++i)
|
||||
{
|
||||
if (nodes.InUse[i])
|
||||
{
|
||||
nodes.Pool[i].PinIndices.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
const int id = nodes.Pool[i].Id;
|
||||
|
||||
if (nodes.IdMap.GetInt(id, -1) == i)
|
||||
{
|
||||
// Remove node idx form depth stack the first time we detect that this idx slot is
|
||||
// unused
|
||||
ImVector<int>& depth_stack = EditorContextGet().NodeDepthOrder;
|
||||
const int* const elem = depth_stack.find(i);
|
||||
IM_ASSERT(elem != depth_stack.end());
|
||||
depth_stack.erase(elem);
|
||||
|
||||
nodes.IdMap.SetInt(id, -1);
|
||||
nodes.FreeList.push_back(i);
|
||||
(nodes.Pool.Data + i)->~ImNodeData();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void ObjectPoolReset(ImObjectPool<T>& objects)
|
||||
{
|
||||
if (!objects.InUse.empty())
|
||||
{
|
||||
memset(objects.InUse.Data, 0, objects.InUse.size_in_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline int ObjectPoolFindOrCreateIndex(ImObjectPool<T>& objects, const int id)
|
||||
{
|
||||
int index = objects.IdMap.GetInt(static_cast<ImGuiID>(id), -1);
|
||||
|
||||
// Construct new object
|
||||
if (index == -1)
|
||||
{
|
||||
if (objects.FreeList.empty())
|
||||
{
|
||||
index = objects.Pool.size();
|
||||
IM_ASSERT(objects.Pool.size() == objects.InUse.size());
|
||||
const int new_size = objects.Pool.size() + 1;
|
||||
objects.Pool.resize(new_size);
|
||||
objects.InUse.resize(new_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
index = objects.FreeList.back();
|
||||
objects.FreeList.pop_back();
|
||||
}
|
||||
IM_PLACEMENT_NEW(objects.Pool.Data + index) T(id);
|
||||
objects.IdMap.SetInt(static_cast<ImGuiID>(id), index);
|
||||
}
|
||||
|
||||
// Flag it as used
|
||||
objects.InUse[index] = true;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline int ObjectPoolFindOrCreateIndex(ImObjectPool<ImNodeData>& nodes, const int node_id)
|
||||
{
|
||||
int node_idx = nodes.IdMap.GetInt(static_cast<ImGuiID>(node_id), -1);
|
||||
|
||||
// Construct new node
|
||||
if (node_idx == -1)
|
||||
{
|
||||
if (nodes.FreeList.empty())
|
||||
{
|
||||
node_idx = nodes.Pool.size();
|
||||
IM_ASSERT(nodes.Pool.size() == nodes.InUse.size());
|
||||
const int new_size = nodes.Pool.size() + 1;
|
||||
nodes.Pool.resize(new_size);
|
||||
nodes.InUse.resize(new_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
node_idx = nodes.FreeList.back();
|
||||
nodes.FreeList.pop_back();
|
||||
}
|
||||
IM_PLACEMENT_NEW(nodes.Pool.Data + node_idx) ImNodeData(node_id);
|
||||
nodes.IdMap.SetInt(static_cast<ImGuiID>(node_id), node_idx);
|
||||
|
||||
ImNodesEditorContext& editor = EditorContextGet();
|
||||
editor.NodeDepthOrder.push_back(node_idx);
|
||||
}
|
||||
|
||||
// Flag node as used
|
||||
nodes.InUse[node_idx] = true;
|
||||
|
||||
return node_idx;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline T& ObjectPoolFindOrCreateObject(ImObjectPool<T>& objects, const int id)
|
||||
{
|
||||
const int index = ObjectPoolFindOrCreateIndex(objects, id);
|
||||
return objects.Pool[index];
|
||||
}
|
||||
} // namespace IMNODES_NAMESPACE
|
281
source/engine/thirdparty/quickjs/quickjs.c
vendored
281
source/engine/thirdparty/quickjs/quickjs.c
vendored
|
@ -32,6 +32,10 @@
|
|||
#include <time.h>
|
||||
#include <fenv.h>
|
||||
#include <math.h>
|
||||
#include <script.h>
|
||||
#include <jsffi.h>
|
||||
#include <sokol/sokol_time.h>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <malloc/malloc.h>
|
||||
#elif defined(__linux__) || defined(__GLIBC__)
|
||||
|
@ -78,15 +82,13 @@
|
|||
#endif
|
||||
|
||||
static FILE *dumpout = NULL;
|
||||
static FILE *cycleout = NULL;
|
||||
|
||||
void quickjs_set_dumpout(FILE *f)
|
||||
{
|
||||
dumpout = f;
|
||||
}
|
||||
void quickjs_set_dumpout(FILE *f) { dumpout = f; }
|
||||
void quickjs_set_cycleout(FILE *f) { cycleout = f; }
|
||||
|
||||
/* dump object free */
|
||||
//#define DUMP_FREE
|
||||
//#define DUMP_CLOSURE
|
||||
/* dump the bytecode of the compiled functions: combination of bits
|
||||
1: dump pass 3 final byte code
|
||||
2: dump pass 2 code
|
||||
|
@ -112,6 +114,18 @@ void quickjs_set_dumpout(FILE *f)
|
|||
//#define DUMP_PROMISE
|
||||
//#define DUMP_READ_OBJECT
|
||||
|
||||
#ifdef DUMP
|
||||
//#define DUMP_FREE
|
||||
//#define DUMP_MEM
|
||||
#define DUMP_GC
|
||||
#define DUMP_LEAKS 1
|
||||
//#define DUMP_OBJECTS
|
||||
//#define DUMP_ATOMS
|
||||
//#define DUMP_SHAPES
|
||||
//#define DUMP_MODULE_RESOLVE
|
||||
//#define DUMP_PROMISE
|
||||
#endif
|
||||
|
||||
/* test the GC by forcing it before each object allocation */
|
||||
//#define FORCE_GC_AT_MALLOC
|
||||
|
||||
|
@ -312,6 +326,25 @@ struct JSRuntime {
|
|||
void *user_opaque;
|
||||
};
|
||||
|
||||
#define SETRT(FIELD) JS_SetPropertyStr(js, v, #FIELD, JS_NewFloat64(js, rt->FIELD));
|
||||
|
||||
JSValue JS_GetRTInfo(JSRuntime *rt, JSContext *js)
|
||||
{
|
||||
JSValue v = JS_NewObject(js);
|
||||
SETRT(atom_hash_size);
|
||||
SETRT(atom_count);
|
||||
SETRT(atom_size);
|
||||
SETRT(class_count);
|
||||
SETRT(stack_size);
|
||||
SETRT(stack_top);
|
||||
SETRT(stack_limit);
|
||||
SETRT(malloc_gc_threshold);
|
||||
SETRT(malloc_state.malloc_count);
|
||||
SETRT(malloc_state.malloc_size);
|
||||
SETRT(malloc_state.malloc_limit);
|
||||
return v;
|
||||
}
|
||||
|
||||
struct JSClass {
|
||||
uint32_t class_id; /* 0 means free entry */
|
||||
JSAtom class_name;
|
||||
|
@ -1051,12 +1084,12 @@ static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
|
|||
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...);
|
||||
static __maybe_unused void JS_DumpAtoms(JSRuntime *rt);
|
||||
static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p);
|
||||
static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt);
|
||||
static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p);
|
||||
static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p);
|
||||
static __maybe_unused void JS_DumpValueShort(JSRuntime *rt, JSValueConst val);
|
||||
static __maybe_unused void JS_DumpValue(JSContext *ctx, JSValueConst val);
|
||||
static __maybe_unused void JS_PrintValue(JSContext *ctx,
|
||||
static __maybe_unused void JS_DumpObjectHeader(FILE *fp, JSRuntime *rt);
|
||||
static __maybe_unused void JS_DumpObject(FILE *fp, JSRuntime *rt, JSObject *p);
|
||||
static __maybe_unused void JS_DumpGCObject(FILE *fp, JSRuntime *rt, JSGCObjectHeader *p);
|
||||
static __maybe_unused void JS_DumpValueShort(FILE *fp, JSRuntime *rt, JSValueConst val);
|
||||
static __maybe_unused void JS_DumpValue(FILE *fp, JSContext *ctx, JSValueConst val);
|
||||
static __maybe_unused void JS_PrintValue(FILE *fp,JSContext *ctx,
|
||||
const char *str,
|
||||
JSValueConst val);
|
||||
static __maybe_unused void JS_DumpShapes(JSRuntime *rt);
|
||||
|
@ -1292,6 +1325,27 @@ static const JSClassExoticMethods js_proxy_exotic_methods;
|
|||
static const JSClassExoticMethods js_module_ns_exotic_methods;
|
||||
static JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT;
|
||||
|
||||
|
||||
////// CUSTOM DUMP FUNCTIONS
|
||||
void JS_DumpMyValue(JSRuntime *rt, JSValue v)
|
||||
{
|
||||
uint32_t tag = JS_VALUE_GET_TAG(v);
|
||||
if (tag == JS_TAG_OBJECT)
|
||||
JS_DumpObject(dumpout, rt, JS_VALUE_GET_OBJ(v));
|
||||
else
|
||||
JS_DumpValueShort(dumpout, rt, v);
|
||||
}
|
||||
|
||||
void JS_PrintShapes(JSRuntime *rt)
|
||||
{
|
||||
JS_DumpShapes(rt);
|
||||
}
|
||||
|
||||
void JS_PrintAtoms(JSRuntime *rt)
|
||||
{
|
||||
JS_DumpAtoms(rt);
|
||||
}
|
||||
|
||||
static void js_trigger_gc(JSRuntime *rt, size_t size)
|
||||
{
|
||||
BOOL force_gc;
|
||||
|
@ -1303,7 +1357,7 @@ static void js_trigger_gc(JSRuntime *rt, size_t size)
|
|||
#endif
|
||||
if (force_gc) {
|
||||
#ifdef DUMP_GC
|
||||
fprintf(dumpout, dumpout, "GC: size=%" PRIu64 "\n",
|
||||
fprintf(dumpout, "GC: size=%" PRIu64 "\n",
|
||||
(uint64_t)rt->malloc_state.malloc_size);
|
||||
#endif
|
||||
JS_RunGC(rt);
|
||||
|
@ -1987,11 +2041,11 @@ void JS_FreeRuntime(JSRuntime *rt)
|
|||
p = list_entry(el, JSGCObjectHeader, link);
|
||||
if (p->ref_count != 0) {
|
||||
if (!header_done) {
|
||||
fprintf(dumpout, dumpout, "Object leaks:\n");
|
||||
JS_DumpObjectHeader(rt);
|
||||
fprintf(cycleout, "Object leaks:\n");
|
||||
JS_DumpObjectHeader(cycleout, rt);
|
||||
header_done = TRUE;
|
||||
}
|
||||
JS_DumpGCObject(rt, p);
|
||||
JS_DumpGCObject(cycleout, rt, p);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2003,7 +2057,7 @@ void JS_FreeRuntime(JSRuntime *rt)
|
|||
}
|
||||
}
|
||||
if (count != 0)
|
||||
fprintf(dumpout, "Secondary object leaks: %d\n", count);
|
||||
fprintf(cycleout, "Secondary object leaks: %d\n", count);
|
||||
}
|
||||
#endif
|
||||
assert(list_empty(&rt->gc_obj_list));
|
||||
|
@ -2322,7 +2376,7 @@ void JS_FreeContext(JSContext *ctx)
|
|||
{
|
||||
JSMemoryUsage stats;
|
||||
JS_ComputeMemoryUsage(rt, &stats);
|
||||
JS_DumpMemoryUsage(stdout, &stats, rt);
|
||||
// JS_DumpMemoryUsage(stdout, &stats, rt);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2521,6 +2575,7 @@ static __maybe_unused void JS_DumpChar(JSRuntime *rt, int c, int sep)
|
|||
|
||||
static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p)
|
||||
{
|
||||
return; // TODO: Reimplment this
|
||||
int i, sep;
|
||||
|
||||
if (p == NULL) {
|
||||
|
@ -5820,7 +5875,7 @@ static void gc_free_cycles(JSRuntime *rt)
|
|||
{
|
||||
struct list_head *el, *el1;
|
||||
JSGCObjectHeader *p;
|
||||
#ifdef DUMP_GC_FREE
|
||||
#ifdef DUMP
|
||||
BOOL header_done = FALSE;
|
||||
#endif
|
||||
|
||||
|
@ -5838,13 +5893,13 @@ static void gc_free_cycles(JSRuntime *rt)
|
|||
case JS_GC_OBJ_TYPE_JS_OBJECT:
|
||||
case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
|
||||
case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
|
||||
#ifdef DUMP_GC_FREE
|
||||
#ifdef DUMP
|
||||
if (!header_done) {
|
||||
fprintf(dumpout, "Freeing cycles:\n");
|
||||
JS_DumpObjectHeader(rt);
|
||||
fprintf(cycleout, "Freeing cycles:\n");
|
||||
JS_DumpObjectHeader(cycleout, rt);
|
||||
header_done = TRUE;
|
||||
}
|
||||
JS_DumpGCObject(rt, p);
|
||||
JS_DumpGCObject(cycleout, rt, p);
|
||||
#endif
|
||||
free_gc_object(rt, p);
|
||||
break;
|
||||
|
@ -5869,6 +5924,9 @@ static void gc_free_cycles(JSRuntime *rt)
|
|||
|
||||
void JS_RunGC(JSRuntime *rt)
|
||||
{
|
||||
double n = stm_now();
|
||||
double size = rt->malloc_state.malloc_size;
|
||||
|
||||
/* decrement the reference of the children of each object. mark =
|
||||
1 after this pass. */
|
||||
gc_decref(rt);
|
||||
|
@ -5878,6 +5936,8 @@ void JS_RunGC(JSRuntime *rt)
|
|||
|
||||
/* free the GC objects in a cycle */
|
||||
gc_free_cycles(rt);
|
||||
|
||||
script_report_gc_time(stm_now()-n, size, rt->malloc_state.malloc_size);
|
||||
}
|
||||
|
||||
/* Return false if not an object or if the object has already been
|
||||
|
@ -5972,6 +6032,25 @@ static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp)
|
|||
}
|
||||
}
|
||||
|
||||
double JS_MyValueSize(JSRuntime *rt, JSValue v)
|
||||
{
|
||||
JSMemoryUsage_helper mem = {0};
|
||||
compute_value_size(v, &mem);
|
||||
return mem.memory_used_count;
|
||||
}
|
||||
|
||||
void JS_FillMemoryState(JSRuntime *rt, JSMemoryUsage *s)
|
||||
{
|
||||
s->malloc_count = rt->malloc_state.malloc_count;
|
||||
s->malloc_size = rt->malloc_state.malloc_size;
|
||||
s->malloc_limit = rt->malloc_state.malloc_limit;
|
||||
|
||||
s->gc_threshold = rt->malloc_gc_threshold;
|
||||
|
||||
s->memory_used_count = 2; /* rt + rt->class_array */
|
||||
s->memory_used_size = sizeof(JSRuntime) + sizeof(JSValue) * rt->class_count;
|
||||
}
|
||||
|
||||
void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
|
||||
{
|
||||
struct list_head *el, *el1;
|
||||
|
@ -5983,6 +6062,8 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
|
|||
s->malloc_size = rt->malloc_state.malloc_size;
|
||||
s->malloc_limit = rt->malloc_state.malloc_limit;
|
||||
|
||||
s->gc_threshold = rt->malloc_gc_threshold;
|
||||
|
||||
s->memory_used_count = 2; /* rt + rt->class_array */
|
||||
s->memory_used_size = sizeof(JSRuntime) + sizeof(JSValue) * rt->class_count;
|
||||
|
||||
|
@ -6262,7 +6343,7 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
|
|||
|
||||
void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt)
|
||||
{
|
||||
fprintf(dumpout, fp, "QuickJS memory usage -- "
|
||||
fprintf(fp, "QuickJS memory usage -- "
|
||||
#ifdef CONFIG_BIGNUM
|
||||
"BigNum "
|
||||
#endif
|
||||
|
@ -6288,14 +6369,14 @@ void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt)
|
|||
unsigned int size1 = js_malloc_usable_size_rt(rt, p);
|
||||
if (size1 >= size) {
|
||||
usage_size_ok = 1;
|
||||
fprintf(dumpout, fp, " %3u + %-2u %s\n",
|
||||
fprintf(fp, " %3u + %-2u %s\n",
|
||||
size, size1 - size, object_types[i].name);
|
||||
}
|
||||
js_free_rt(rt, p);
|
||||
}
|
||||
}
|
||||
if (!usage_size_ok) {
|
||||
fprintf(dumpout, fp, " malloc_usable_size unavailable\n");
|
||||
fprintf(fp, " malloc_usable_size unavailable\n");
|
||||
}
|
||||
{
|
||||
int obj_classes[JS_CLASS_INIT_COUNT + 1] = { 0 };
|
||||
|
@ -6309,82 +6390,82 @@ void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt)
|
|||
obj_classes[min_uint32(p->class_id, JS_CLASS_INIT_COUNT)]++;
|
||||
}
|
||||
}
|
||||
fprintf(dumpout, fp, "\n" "JSObject classes\n");
|
||||
fprintf(fp, "\n" "JSObject classes\n");
|
||||
if (obj_classes[0])
|
||||
fprintf(dumpout, fp, " %5d %2.0d %s\n", obj_classes[0], 0, "none");
|
||||
fprintf(fp, " %5d %2.0d %s\n", obj_classes[0], 0, "none");
|
||||
for (class_id = 1; class_id < JS_CLASS_INIT_COUNT; class_id++) {
|
||||
if (obj_classes[class_id] && class_id < rt->class_count) {
|
||||
char buf[ATOM_GET_STR_BUF_SIZE];
|
||||
fprintf(dumpout, fp, " %5d %2.0d %s\n", obj_classes[class_id], class_id,
|
||||
fprintf(fp, " %5d %2.0d %s\n", obj_classes[class_id], class_id,
|
||||
JS_AtomGetStrRT(rt, buf, sizeof(buf), rt->class_array[class_id].class_name));
|
||||
}
|
||||
}
|
||||
if (obj_classes[JS_CLASS_INIT_COUNT])
|
||||
fprintf(dumpout, fp, " %5d %2.0d %s\n", obj_classes[JS_CLASS_INIT_COUNT], 0, "other");
|
||||
fprintf(fp, " %5d %2.0d %s\n", obj_classes[JS_CLASS_INIT_COUNT], 0, "other");
|
||||
}
|
||||
fprintf(dumpout, fp, "\n");
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
#endif
|
||||
fprintf(dumpout, fp, "%-20s %8s %8s\n", "NAME", "COUNT", "SIZE");
|
||||
fprintf(fp, "%-20s %8s %8s\n", "NAME", "COUNT", "SIZE");
|
||||
|
||||
if (s->malloc_count) {
|
||||
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per block)\n",
|
||||
fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per block)\n",
|
||||
"memory allocated", s->malloc_count, s->malloc_size,
|
||||
(double)s->malloc_size / s->malloc_count);
|
||||
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%d overhead, %0.1f average slack)\n",
|
||||
fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%d overhead, %0.1f average slack)\n",
|
||||
"memory used", s->memory_used_count, s->memory_used_size,
|
||||
MALLOC_OVERHEAD, ((double)(s->malloc_size - s->memory_used_size) /
|
||||
s->memory_used_count));
|
||||
}
|
||||
if (s->atom_count) {
|
||||
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per atom)\n",
|
||||
fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per atom)\n",
|
||||
"atoms", s->atom_count, s->atom_size,
|
||||
(double)s->atom_size / s->atom_count);
|
||||
}
|
||||
if (s->str_count) {
|
||||
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per string)\n",
|
||||
fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per string)\n",
|
||||
"strings", s->str_count, s->str_size,
|
||||
(double)s->str_size / s->str_count);
|
||||
}
|
||||
if (s->obj_count) {
|
||||
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per object)\n",
|
||||
fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per object)\n",
|
||||
"objects", s->obj_count, s->obj_size,
|
||||
(double)s->obj_size / s->obj_count);
|
||||
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per object)\n",
|
||||
fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per object)\n",
|
||||
" properties", s->prop_count, s->prop_size,
|
||||
(double)s->prop_count / s->obj_count);
|
||||
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per shape)\n",
|
||||
fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per shape)\n",
|
||||
" shapes", s->shape_count, s->shape_size,
|
||||
(double)s->shape_size / s->shape_count);
|
||||
}
|
||||
if (s->js_func_count) {
|
||||
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64"\n",
|
||||
fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n",
|
||||
"bytecode functions", s->js_func_count, s->js_func_size);
|
||||
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per function)\n",
|
||||
fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per function)\n",
|
||||
" bytecode", s->js_func_count, s->js_func_code_size,
|
||||
(double)s->js_func_code_size / s->js_func_count);
|
||||
if (s->js_func_pc2line_count) {
|
||||
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per function)\n",
|
||||
fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per function)\n",
|
||||
" pc2line", s->js_func_pc2line_count,
|
||||
s->js_func_pc2line_size,
|
||||
(double)s->js_func_pc2line_size / s->js_func_pc2line_count);
|
||||
}
|
||||
}
|
||||
if (s->c_func_count) {
|
||||
fprintf(dumpout, fp, "%-20s %8"PRId64"\n", "C functions", s->c_func_count);
|
||||
fprintf(fp, "%-20s %8"PRId64"\n", "C functions", s->c_func_count);
|
||||
}
|
||||
if (s->array_count) {
|
||||
fprintf(dumpout, fp, "%-20s %8"PRId64"\n", "arrays", s->array_count);
|
||||
fprintf(fp, "%-20s %8"PRId64"\n", "arrays", s->array_count);
|
||||
if (s->fast_array_count) {
|
||||
fprintf(dumpout, fp, "%-20s %8"PRId64"\n", " fast arrays", s->fast_array_count);
|
||||
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per fast array)\n",
|
||||
fprintf(fp, "%-20s %8"PRId64"\n", " fast arrays", s->fast_array_count);
|
||||
fprintf(fp, "%-20s %8"PRId64" %8"PRId64" (%0.1f per fast array)\n",
|
||||
" elements", s->fast_array_elements,
|
||||
s->fast_array_elements * (int)sizeof(JSValue),
|
||||
(double)s->fast_array_elements / s->fast_array_count);
|
||||
}
|
||||
}
|
||||
if (s->binary_object_count) {
|
||||
fprintf(dumpout, fp, "%-20s %8"PRId64" %8"PRId64"\n",
|
||||
fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n",
|
||||
"binary objects", s->binary_object_count, s->binary_object_size);
|
||||
}
|
||||
}
|
||||
|
@ -11857,14 +11938,14 @@ static JSValue JS_ToQuotedString(JSContext *ctx, JSValueConst val1)
|
|||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt)
|
||||
static __maybe_unused void JS_DumpObjectHeader(FILE *fp, JSRuntime *rt)
|
||||
{
|
||||
fprintf(dumpout, "%14s %4s %4s %14s %10s %s\n",
|
||||
fprintf(fp, "%14s %4s %4s %14s %10s %s\n",
|
||||
"ADDRESS", "REFS", "SHRF", "PROTO", "CLASS", "PROPS");
|
||||
}
|
||||
|
||||
/* for debug only: dump an object without side effect */
|
||||
static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
|
||||
static __maybe_unused void JS_DumpObject(FILE *fp, JSRuntime *rt, JSObject *p)
|
||||
{
|
||||
uint32_t i;
|
||||
char atom_buf[ATOM_GET_STR_BUF_SIZE];
|
||||
|
@ -11875,28 +11956,28 @@ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
|
|||
|
||||
/* XXX: should encode atoms with special characters */
|
||||
sh = p->shape; /* the shape can be NULL while freeing an object */
|
||||
fprintf(dumpout, "%14p %4d ",
|
||||
fprintf(fp, "%14p %4d ",
|
||||
(void *)p,
|
||||
p->header.ref_count);
|
||||
if (sh) {
|
||||
fprintf(dumpout, "%3d%c %14p ",
|
||||
fprintf(fp, "%3d%c %14p ",
|
||||
sh->header.ref_count,
|
||||
" *"[sh->is_hashed],
|
||||
(void *)sh->proto);
|
||||
} else {
|
||||
fprintf(dumpout, "%3s %14s ", "-", "-");
|
||||
fprintf(fp, "%3s %14s ", "-", "-");
|
||||
}
|
||||
fprintf(dumpout, "%10s ",
|
||||
fprintf(fp, "%10s ",
|
||||
JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), rt->class_array[p->class_id].class_name));
|
||||
if (p->is_exotic && p->fast_array) {
|
||||
fprintf(dumpout, "[ ");
|
||||
fprintf(fp, "[ ");
|
||||
for(i = 0; i < p->u.array.count; i++) {
|
||||
if (i != 0)
|
||||
fprintf(dumpout, ", ");
|
||||
fprintf(fp, ", ");
|
||||
switch (p->class_id) {
|
||||
case JS_CLASS_ARRAY:
|
||||
case JS_CLASS_ARGUMENTS:
|
||||
JS_DumpValueShort(rt, p->u.array.u.values[i]);
|
||||
JS_DumpValueShort(fp, rt, p->u.array.u.values[i]);
|
||||
break;
|
||||
case JS_CLASS_UINT8C_ARRAY:
|
||||
case JS_CLASS_INT8_ARRAY:
|
||||
|
@ -11913,40 +11994,40 @@ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
|
|||
int size = 1 << typed_array_size_log2(p->class_id);
|
||||
const uint8_t *b = p->u.array.u.uint8_ptr + i * size;
|
||||
while (size-- > 0)
|
||||
fprintf(dumpout, "%02X", *b++);
|
||||
fprintf(fp, "%02X", *b++);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(dumpout, " ] ");
|
||||
fprintf(fp, " ] ");
|
||||
}
|
||||
|
||||
if (sh) {
|
||||
fprintf(dumpout, "{ ");
|
||||
fprintf(fp, "{ ");
|
||||
for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
|
||||
if (prs->atom != JS_ATOM_NULL) {
|
||||
pr = &p->prop[i];
|
||||
if (!is_first)
|
||||
fprintf(dumpout, ", ");
|
||||
fprintf(dumpout, "%s: ",
|
||||
fprintf(fp, ", ");
|
||||
fprintf(fp, "%s: ",
|
||||
JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), prs->atom));
|
||||
if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
|
||||
fprintf(dumpout, "[getset %p %p]", (void *)pr->u.getset.getter,
|
||||
fprintf(fp, "[getset %p %p]", (void *)pr->u.getset.getter,
|
||||
(void *)pr->u.getset.setter);
|
||||
} else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
|
||||
fprintf(dumpout, "[varref %p]", (void *)pr->u.var_ref);
|
||||
fprintf(fp, "[varref %p]", (void *)pr->u.var_ref);
|
||||
} else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
|
||||
fprintf(dumpout, "[autoinit %p %d %p]",
|
||||
fprintf(fp, "[autoinit %p %d %p]",
|
||||
(void *)js_autoinit_get_realm(pr),
|
||||
js_autoinit_get_id(pr),
|
||||
(void *)pr->u.init.opaque);
|
||||
} else {
|
||||
JS_DumpValueShort(rt, pr->u.value);
|
||||
JS_DumpValueShort(fp, rt, pr->u.value);
|
||||
}
|
||||
is_first = FALSE;
|
||||
}
|
||||
}
|
||||
fprintf(dumpout, " }");
|
||||
fprintf(fp, " }");
|
||||
}
|
||||
|
||||
if (js_class_has_bytecode(p->class_id)) {
|
||||
|
@ -11954,53 +12035,53 @@ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
|
|||
JSVarRef **var_refs;
|
||||
if (b->closure_var_count) {
|
||||
var_refs = p->u.func.var_refs;
|
||||
fprintf(dumpout, " Closure:");
|
||||
fprintf(fp, " Closure:");
|
||||
for(i = 0; i < b->closure_var_count; i++) {
|
||||
fprintf(dumpout, " ");
|
||||
JS_DumpValueShort(rt, var_refs[i]->value);
|
||||
fprintf(fp, " ");
|
||||
JS_DumpValueShort(fp, rt, var_refs[i]->value);
|
||||
}
|
||||
if (p->u.func.home_object) {
|
||||
fprintf(dumpout, " HomeObject: ");
|
||||
JS_DumpValueShort(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object));
|
||||
fprintf(fp, " HomeObject: ");
|
||||
JS_DumpValueShort(fp, rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object));
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(dumpout, "\n");
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p)
|
||||
static __maybe_unused void JS_DumpGCObject(FILE *fp, JSRuntime *rt, JSGCObjectHeader *p)
|
||||
{
|
||||
if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
|
||||
JS_DumpObject(rt, (JSObject *)p);
|
||||
JS_DumpObject(fp, rt, (JSObject *)p);
|
||||
} else {
|
||||
fprintf(dumpout, "%14p %4d ",
|
||||
fprintf(fp, "%14p %4d ",
|
||||
(void *)p,
|
||||
p->ref_count);
|
||||
switch(p->gc_obj_type) {
|
||||
case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
|
||||
fprintf(dumpout, "[function bytecode]");
|
||||
fprintf(fp, "[function bytecode]");
|
||||
break;
|
||||
case JS_GC_OBJ_TYPE_SHAPE:
|
||||
fprintf(dumpout, "[shape]");
|
||||
fprintf(fp, "[shape]");
|
||||
break;
|
||||
case JS_GC_OBJ_TYPE_VAR_REF:
|
||||
fprintf(dumpout, "[var_ref]");
|
||||
fprintf(fp, "[var_ref]");
|
||||
break;
|
||||
case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
|
||||
fprintf(dumpout, "[async_function]");
|
||||
fprintf(fp, "[async_function]");
|
||||
break;
|
||||
case JS_GC_OBJ_TYPE_JS_CONTEXT:
|
||||
fprintf(dumpout, "[js_context]");
|
||||
fprintf(fp, "[js_context]");
|
||||
break;
|
||||
default:
|
||||
fprintf(dumpout, "[unknown %d]", p->gc_obj_type);
|
||||
fprintf(fp, "[unknown %d]", p->gc_obj_type);
|
||||
break;
|
||||
}
|
||||
fprintf(dumpout, "\n");
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
|
||||
static __maybe_unused void JS_DumpValueShort(FILE *fp, JSRuntime *rt,
|
||||
JSValueConst val)
|
||||
{
|
||||
uint32_t tag = JS_VALUE_GET_NORM_TAG(val);
|
||||
|
@ -12008,7 +12089,7 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
|
|||
|
||||
switch(tag) {
|
||||
case JS_TAG_INT:
|
||||
fprintf(dumpout, "%d", JS_VALUE_GET_INT(val));
|
||||
fprintf(fp, "%d", JS_VALUE_GET_INT(val));
|
||||
break;
|
||||
case JS_TAG_BOOL:
|
||||
if (JS_VALUE_GET_BOOL(val))
|
||||
|
@ -12028,10 +12109,10 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
|
|||
case JS_TAG_UNDEFINED:
|
||||
str = "undefined";
|
||||
print_str:
|
||||
fprintf(dumpout, "%s", str);
|
||||
fprintf(fp, "%s", str);
|
||||
break;
|
||||
case JS_TAG_FLOAT64:
|
||||
fprintf(dumpout, "%.14g", JS_VALUE_GET_FLOAT64(val));
|
||||
fprintf(fp, "%.14g", JS_VALUE_GET_FLOAT64(val));
|
||||
break;
|
||||
case JS_TAG_BIG_INT:
|
||||
{
|
||||
|
@ -12039,7 +12120,7 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
|
|||
char *str;
|
||||
str = bf_ftoa(NULL, &p->num, 10, 0,
|
||||
BF_RNDZ | BF_FTOA_FORMAT_FRAC);
|
||||
fprintf(dumpout, "%sn", str);
|
||||
fprintf(fp, "%sn", str);
|
||||
bf_realloc(&rt->bf_ctx, str, 0);
|
||||
}
|
||||
break;
|
||||
|
@ -12050,7 +12131,7 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
|
|||
char *str;
|
||||
str = bf_ftoa(NULL, &p->num, 16, BF_PREC_INF,
|
||||
BF_RNDZ | BF_FTOA_FORMAT_FREE | BF_FTOA_ADD_PREFIX);
|
||||
fprintf(dumpout, "%sl", str);
|
||||
fprintf(fp, "%sl", str);
|
||||
bf_free(&rt->bf_ctx, str);
|
||||
}
|
||||
break;
|
||||
|
@ -12060,7 +12141,7 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
|
|||
char *str;
|
||||
str = bfdec_ftoa(NULL, &p->num, BF_PREC_INF,
|
||||
BF_RNDZ | BF_FTOA_FORMAT_FREE);
|
||||
fprintf(dumpout, "%sm", str);
|
||||
fprintf(fp, "%sm", str);
|
||||
bf_free(&rt->bf_ctx, str);
|
||||
}
|
||||
break;
|
||||
|
@ -12076,7 +12157,7 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
|
|||
{
|
||||
JSFunctionBytecode *b = JS_VALUE_GET_PTR(val);
|
||||
char buf[ATOM_GET_STR_BUF_SIZE];
|
||||
fprintf(dumpout, "[bytecode %s]", JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));
|
||||
fprintf(fp, "[bytecode %s]", JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));
|
||||
}
|
||||
break;
|
||||
case JS_TAG_OBJECT:
|
||||
|
@ -12084,7 +12165,7 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
|
|||
JSObject *p = JS_VALUE_GET_OBJ(val);
|
||||
JSAtom atom = rt->class_array[p->class_id].class_name;
|
||||
char atom_buf[ATOM_GET_STR_BUF_SIZE];
|
||||
fprintf(dumpout, "[%s %p]",
|
||||
fprintf(fp, "[%s %p]",
|
||||
JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), atom), (void *)p);
|
||||
}
|
||||
break;
|
||||
|
@ -12092,32 +12173,32 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
|
|||
{
|
||||
JSAtomStruct *p = JS_VALUE_GET_PTR(val);
|
||||
char atom_buf[ATOM_GET_STR_BUF_SIZE];
|
||||
fprintf(dumpout, "Symbol(%s)",
|
||||
fprintf(fp, "Symbol(%s)",
|
||||
JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), js_get_atom_index(rt, p)));
|
||||
}
|
||||
break;
|
||||
case JS_TAG_MODULE:
|
||||
fprintf(dumpout, "[module]");
|
||||
fprintf(fp, "[module]");
|
||||
break;
|
||||
default:
|
||||
fprintf(dumpout, "[unknown tag %d]", tag);
|
||||
fprintf(fp, "[unknown tag %d]", tag);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static __maybe_unused void JS_DumpValue(JSContext *ctx,
|
||||
static __maybe_unused void JS_DumpValue(FILE *fp, JSContext *ctx,
|
||||
JSValueConst val)
|
||||
{
|
||||
JS_DumpValueShort(ctx->rt, val);
|
||||
JS_DumpValueShort(fp, ctx->rt, val);
|
||||
}
|
||||
|
||||
static __maybe_unused void JS_PrintValue(JSContext *ctx,
|
||||
static __maybe_unused void JS_PrintValue(FILE *fp, JSContext *ctx,
|
||||
const char *str,
|
||||
JSValueConst val)
|
||||
{
|
||||
fprintf(dumpout, "%s=", str);
|
||||
JS_DumpValueShort(ctx->rt, val);
|
||||
fprintf(dumpout, "\n");
|
||||
fprintf(fp, "%s=", str);
|
||||
JS_DumpValueShort(fp, ctx->rt, val);
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
/* return -1 if exception (proxy case) or TRUE/FALSE */
|
||||
|
|
9
source/engine/thirdparty/quickjs/quickjs.h
vendored
9
source/engine/thirdparty/quickjs/quickjs.h
vendored
|
@ -92,7 +92,11 @@ typedef struct JSRefCountHeader {
|
|||
} JSRefCountHeader;
|
||||
|
||||
void quickjs_set_dumpout(FILE *f);
|
||||
void quickjs_set_cycleout(FILE *f);
|
||||
void JS_SetInterruptRate(int count);
|
||||
void JS_PrintShapes(JSRuntime *rt);
|
||||
void JS_PrintAtoms(JSRuntime *rt);
|
||||
|
||||
|
||||
#define JS_FLOAT64_NAN NAN
|
||||
|
||||
|
@ -339,6 +343,7 @@ JSRuntime *JS_NewRuntime(void);
|
|||
void JS_SetRuntimeInfo(JSRuntime *rt, const char *info);
|
||||
void JS_SetMemoryLimit(JSRuntime *rt, size_t limit);
|
||||
void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold);
|
||||
JSValue JS_GetRTInfo(JSRuntime *rt, JSContext *js);
|
||||
/* use 0 to disable maximum stack size check */
|
||||
void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size);
|
||||
/* should be called when changing thread to update the stack top value
|
||||
|
@ -404,6 +409,7 @@ char *js_strndup(JSContext *ctx, const char *s, size_t n);
|
|||
|
||||
typedef struct JSMemoryUsage {
|
||||
int64_t malloc_size, malloc_limit, memory_used_size;
|
||||
int64_t gc_threshold;
|
||||
int64_t malloc_count;
|
||||
int64_t memory_used_count;
|
||||
int64_t atom_count, atom_size;
|
||||
|
@ -419,7 +425,10 @@ typedef struct JSMemoryUsage {
|
|||
} JSMemoryUsage;
|
||||
|
||||
void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s);
|
||||
void JS_FillMemoryState(JSRuntime *rt, JSMemoryUsage *s);
|
||||
void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt);
|
||||
void JS_DumpMyValue(JSRuntime *rt, JSValue v);
|
||||
double JS_MyValueSize(JSRuntime *rt, JSValue v);
|
||||
|
||||
/* atom support */
|
||||
#define JS_ATOM_NULL 0
|
||||
|
|
830
source/engine/thirdparty/sokol/sokol_app.h
vendored
830
source/engine/thirdparty/sokol/sokol_app.h
vendored
File diff suppressed because it is too large
Load diff
14
source/engine/thirdparty/sokol/sokol_audio.h
vendored
14
source/engine/thirdparty/sokol/sokol_audio.h
vendored
|
@ -453,6 +453,7 @@
|
|||
the standard logger in sokol_log.h instead, otherwise you won't see any warnings or
|
||||
errors.
|
||||
|
||||
|
||||
LICENSE
|
||||
=======
|
||||
|
||||
|
@ -1067,6 +1068,7 @@ typedef struct {
|
|||
/* sokol-audio state */
|
||||
typedef struct {
|
||||
bool valid;
|
||||
bool setup_called;
|
||||
void (*stream_cb)(float* buffer, int num_frames, int num_channels);
|
||||
void (*stream_userdata_cb)(float* buffer, int num_frames, int num_channels, void* user_data);
|
||||
void* user_data;
|
||||
|
@ -2486,9 +2488,11 @@ void _saudio_backend_shutdown(void) {
|
|||
// >>public
|
||||
SOKOL_API_IMPL void saudio_setup(const saudio_desc* desc) {
|
||||
SOKOL_ASSERT(!_saudio.valid);
|
||||
SOKOL_ASSERT(!_saudio.setup_called);
|
||||
SOKOL_ASSERT(desc);
|
||||
SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn));
|
||||
_saudio_clear(&_saudio, sizeof(_saudio));
|
||||
_saudio.setup_called = true;
|
||||
_saudio.desc = *desc;
|
||||
_saudio.stream_cb = desc->stream_cb;
|
||||
_saudio.stream_userdata_cb = desc->stream_userdata_cb;
|
||||
|
@ -2519,6 +2523,8 @@ SOKOL_API_IMPL void saudio_setup(const saudio_desc* desc) {
|
|||
}
|
||||
|
||||
SOKOL_API_IMPL void saudio_shutdown(void) {
|
||||
SOKOL_ASSERT(_saudio.setup_called);
|
||||
_saudio.setup_called = false;
|
||||
if (_saudio.valid) {
|
||||
_saudio_backend_shutdown();
|
||||
_saudio_fifo_shutdown(&_saudio.fifo);
|
||||
|
@ -2532,26 +2538,32 @@ SOKOL_API_IMPL bool saudio_isvalid(void) {
|
|||
}
|
||||
|
||||
SOKOL_API_IMPL void* saudio_userdata(void) {
|
||||
SOKOL_ASSERT(_saudio.setup_called);
|
||||
return _saudio.desc.user_data;
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL saudio_desc saudio_query_desc(void) {
|
||||
SOKOL_ASSERT(_saudio.setup_called);
|
||||
return _saudio.desc;
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL int saudio_sample_rate(void) {
|
||||
SOKOL_ASSERT(_saudio.setup_called);
|
||||
return _saudio.sample_rate;
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL int saudio_buffer_frames(void) {
|
||||
SOKOL_ASSERT(_saudio.setup_called);
|
||||
return _saudio.buffer_frames;
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL int saudio_channels(void) {
|
||||
SOKOL_ASSERT(_saudio.setup_called);
|
||||
return _saudio.num_channels;
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL bool saudio_suspended(void) {
|
||||
SOKOL_ASSERT(_saudio.setup_called);
|
||||
#if defined(_SAUDIO_EMSCRIPTEN)
|
||||
if (_saudio.valid) {
|
||||
return 1 == saudio_js_suspended();
|
||||
|
@ -2565,6 +2577,7 @@ SOKOL_API_IMPL bool saudio_suspended(void) {
|
|||
}
|
||||
|
||||
SOKOL_API_IMPL int saudio_expect(void) {
|
||||
SOKOL_ASSERT(_saudio.setup_called);
|
||||
if (_saudio.valid) {
|
||||
const int num_frames = _saudio_fifo_writable_bytes(&_saudio.fifo) / _saudio.bytes_per_frame;
|
||||
return num_frames;
|
||||
|
@ -2575,6 +2588,7 @@ SOKOL_API_IMPL int saudio_expect(void) {
|
|||
}
|
||||
|
||||
SOKOL_API_IMPL int saudio_push(const float* frames, int num_frames) {
|
||||
SOKOL_ASSERT(_saudio.setup_called);
|
||||
SOKOL_ASSERT(frames && (num_frames > 0));
|
||||
if (_saudio.valid) {
|
||||
const int num_bytes = num_frames * _saudio.bytes_per_frame;
|
||||
|
|
10
source/engine/thirdparty/sokol/sokol_fetch.h
vendored
10
source/engine/thirdparty/sokol/sokol_fetch.h
vendored
|
@ -1201,6 +1201,11 @@ inline sfetch_handle_t sfetch_send(const sfetch_request_t& request) { return sfe
|
|||
#define _SFETCH_HAS_THREADS (1)
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4724) // potential mod by 0
|
||||
#endif
|
||||
|
||||
// ███████ ████████ ██████ ██ ██ ██████ ████████ ███████
|
||||
// ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
// ███████ ██ ██████ ██ ██ ██ ██ ███████
|
||||
|
@ -2806,4 +2811,9 @@ SOKOL_API_IMPL void sfetch_cancel(sfetch_handle_t h) {
|
|||
item->user.cancel = true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif /* SOKOL_FETCH_IMPL */
|
||||
|
|
192
source/engine/thirdparty/sokol/sokol_gfx.h
vendored
192
source/engine/thirdparty/sokol/sokol_gfx.h
vendored
|
@ -963,7 +963,7 @@
|
|||
ON STORAGE BUFFERS
|
||||
==================
|
||||
Storage buffers can be used to pass large amounts of random access structured
|
||||
data fromt the CPU side to the shaders. They are similar to data textures, but are
|
||||
data from the CPU side to the shaders. They are similar to data textures, but are
|
||||
more convenient to use both on the CPU and shader side since they can be accessed
|
||||
in shaders as as a 1-dimensional array of struct items.
|
||||
|
||||
|
@ -1496,6 +1496,7 @@
|
|||
.wgpu.num_bindgroup_cache_hits
|
||||
.wgpu.num_bindgroup_cache_misses
|
||||
.wgpu.num_bindgroup_cache_collisions
|
||||
.wgpu_num_bindgroup_cache_invalidates
|
||||
.wgpu.num_bindgroup_cache_vs_hash_key_mismatch
|
||||
|
||||
The value to pay attention to is `.wgpu.num_bindgroup_cache_collisions`,
|
||||
|
@ -2097,13 +2098,10 @@ typedef enum sg_primitive_type {
|
|||
used in the sg_sampler_desc.min_filter, sg_sampler_desc.mag_filter
|
||||
and sg_sampler_desc.mipmap_filter members when creating a sampler object.
|
||||
|
||||
For min_filter and mag_filter the default is SG_FILTER_NEAREST.
|
||||
|
||||
For mipmap_filter the default is SG_FILTER_NONE.
|
||||
For the default is SG_FILTER_NEAREST.
|
||||
*/
|
||||
typedef enum sg_filter {
|
||||
_SG_FILTER_DEFAULT, // value 0 reserved for default-init
|
||||
SG_FILTER_NONE, // FIXME: deprecated
|
||||
SG_FILTER_NEAREST,
|
||||
SG_FILTER_LINEAR,
|
||||
_SG_FILTER_NUM,
|
||||
|
@ -2892,7 +2890,7 @@ typedef struct sg_image_desc {
|
|||
|
||||
.min_filter: SG_FILTER_NEAREST
|
||||
.mag_filter: SG_FILTER_NEAREST
|
||||
.mipmap_filter SG_FILTER_NONE
|
||||
.mipmap_filter SG_FILTER_NEAREST
|
||||
.wrap_u: SG_WRAP_REPEAT
|
||||
.wrap_v: SG_WRAP_REPEAT
|
||||
.wrap_w: SG_WRAP_REPEAT (only SG_IMAGETYPE_3D)
|
||||
|
@ -3482,6 +3480,7 @@ typedef struct sg_frame_stats_wgpu_bindings {
|
|||
uint32_t num_bindgroup_cache_hits;
|
||||
uint32_t num_bindgroup_cache_misses;
|
||||
uint32_t num_bindgroup_cache_collisions;
|
||||
uint32_t num_bindgroup_cache_invalidates;
|
||||
uint32_t num_bindgroup_cache_hash_vs_key_mismatch;
|
||||
} sg_frame_stats_wgpu_bindings;
|
||||
|
||||
|
@ -3592,7 +3591,7 @@ typedef struct sg_frame_stats {
|
|||
_SG_LOGITEM_XMACRO(WGPU_ATTACHMENTS_CREATE_TEXTURE_VIEW_FAILED, "wgpuTextureCreateView() failed in create attachments") \
|
||||
_SG_LOGITEM_XMACRO(IDENTICAL_COMMIT_LISTENER, "attempting to add identical commit listener") \
|
||||
_SG_LOGITEM_XMACRO(COMMIT_LISTENER_ARRAY_FULL, "commit listener array full") \
|
||||
_SG_LOGITEM_XMACRO(TRACE_HOOKS_NOT_ENABLED, "sg_install_trace_hooks() called, but SG_TRACE_HOOKS is not defined") \
|
||||
_SG_LOGITEM_XMACRO(TRACE_HOOKS_NOT_ENABLED, "sg_install_trace_hooks() called, but SOKOL_TRACE_HOOKS is not defined") \
|
||||
_SG_LOGITEM_XMACRO(DEALLOC_BUFFER_INVALID_STATE, "sg_dealloc_buffer(): buffer must be in ALLOC state") \
|
||||
_SG_LOGITEM_XMACRO(DEALLOC_IMAGE_INVALID_STATE, "sg_dealloc_image(): image must be in alloc state") \
|
||||
_SG_LOGITEM_XMACRO(DEALLOC_SAMPLER_INVALID_STATE, "sg_dealloc_sampler(): sampler must be in alloc state") \
|
||||
|
@ -3650,8 +3649,6 @@ typedef struct sg_frame_stats {
|
|||
_SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_DYNAMIC_NO_DATA, "dynamic/stream images cannot be initialized with data") \
|
||||
_SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_COMPRESSED_IMMUTABLE, "compressed images must be immutable") \
|
||||
_SG_LOGITEM_XMACRO(VALIDATE_SAMPLERDESC_CANARY, "sg_sampler_desc not initialized") \
|
||||
_SG_LOGITEM_XMACRO(VALIDATE_SAMPLERDESC_MINFILTER_NONE, "sg_sampler_desc.min_filter cannot be SG_FILTER_NONE") \
|
||||
_SG_LOGITEM_XMACRO(VALIDATE_SAMPLERDESC_MAGFILTER_NONE, "sg_sampler_desc.mag_filter cannot be SG_FILTER_NONE") \
|
||||
_SG_LOGITEM_XMACRO(VALIDATE_SAMPLERDESC_ANISTROPIC_REQUIRES_LINEAR_FILTERING, "sg_sampler_desc.max_anisotropy > 1 requires min/mag/mipmap_filter to be SG_FILTER_LINEAR") \
|
||||
_SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_CANARY, "sg_shader_desc not initialized") \
|
||||
_SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_SOURCE, "shader source code required") \
|
||||
|
@ -3887,6 +3884,12 @@ typedef enum sg_log_item {
|
|||
before sg_setup() is called
|
||||
.environment.d3d11.device_context
|
||||
a pointer to the ID3D11DeviceContext object
|
||||
.d3d11_shader_debugging
|
||||
set this to true to compile shaders which are provided as HLSL source
|
||||
code with debug information and without optimization, this allows
|
||||
shader debugging in tools like RenderDoc, to output source code
|
||||
instead of byte code from sokol-shdc, omit the `--binary` cmdline
|
||||
option
|
||||
|
||||
WebGPU specific:
|
||||
.wgpu_disable_bindgroups_cache
|
||||
|
@ -3999,6 +4002,7 @@ typedef struct sg_desc {
|
|||
int uniform_buffer_size;
|
||||
int max_commit_listeners;
|
||||
bool disable_validation; // disable validation layer even in debug mode, useful for tests
|
||||
bool d3d11_shader_debugging; // if true, HLSL shaders are compiled with D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION
|
||||
bool mtl_force_managed_storage_mode; // for debugging: use Metal managed storage mode for resources even with UMA
|
||||
bool mtl_use_command_buffer_with_retained_references; // Metal: use a managed MTLCommandBuffer which ref-counts used resources
|
||||
bool wgpu_disable_bindgroups_cache; // set to true to disable the WebGPU backend BindGroup cache
|
||||
|
@ -5783,10 +5787,20 @@ typedef struct {
|
|||
uint32_t id;
|
||||
} _sg_wgpu_bindgroup_handle_t;
|
||||
|
||||
#define _SG_WGPU_BINDGROUPSCACHE_NUM_ITEMS (1 + _SG_WGPU_MAX_BINDGROUP_ENTRIES)
|
||||
typedef enum {
|
||||
_SG_WGPU_BINDGROUPSCACHEITEMTYPE_NONE = 0,
|
||||
_SG_WGPU_BINDGROUPSCACHEITEMTYPE_IMAGE = 0x1111111111111111,
|
||||
_SG_WGPU_BINDGROUPSCACHEITEMTYPE_SAMPLER = 0x2222222222222222,
|
||||
_SG_WGPU_BINDGROUPSCACHEITEMTYPE_STORAGEBUFFER = 0x3333333333333333,
|
||||
_SG_WGPU_BINDGROUPSCACHEITEMTYPE_PIPELINE = 0x4444444444444444,
|
||||
} _sg_wgpu_bindgroups_cache_item_type_t;
|
||||
|
||||
#define _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS (1 + _SG_WGPU_MAX_BINDGROUP_ENTRIES)
|
||||
typedef struct {
|
||||
uint64_t hash;
|
||||
uint32_t items[_SG_WGPU_BINDGROUPSCACHE_NUM_ITEMS];
|
||||
// the format of cache key items is (_sg_wgpu_bindgroups_cache_item_type_t << 32) | handle.id,
|
||||
// where the item type is a per-resource-type bit pattern
|
||||
uint64_t items[_SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS];
|
||||
} _sg_wgpu_bindgroups_cache_key_t;
|
||||
|
||||
typedef struct {
|
||||
|
@ -7142,14 +7156,12 @@ _SOKOL_PRIVATE GLenum _sg_gl_blend_op(sg_blend_op op) {
|
|||
_SOKOL_PRIVATE GLenum _sg_gl_min_filter(sg_filter min_f, sg_filter mipmap_f) {
|
||||
if (min_f == SG_FILTER_NEAREST) {
|
||||
switch (mipmap_f) {
|
||||
case SG_FILTER_NONE: return GL_NEAREST;
|
||||
case SG_FILTER_NEAREST: return GL_NEAREST_MIPMAP_NEAREST;
|
||||
case SG_FILTER_LINEAR: return GL_NEAREST_MIPMAP_LINEAR;
|
||||
default: SOKOL_UNREACHABLE; return (GLenum)0;
|
||||
}
|
||||
} else if (min_f == SG_FILTER_LINEAR) {
|
||||
switch (mipmap_f) {
|
||||
case SG_FILTER_NONE: return GL_LINEAR;
|
||||
case SG_FILTER_NEAREST: return GL_LINEAR_MIPMAP_NEAREST;
|
||||
case SG_FILTER_LINEAR: return GL_LINEAR_MIPMAP_LINEAR;
|
||||
default: SOKOL_UNREACHABLE; return (GLenum)0;
|
||||
|
@ -8299,6 +8311,22 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_image(_sg_image_t* img, const sg_
|
|||
_sg_gl_cache_store_texture_sampler_binding(0);
|
||||
_sg_gl_cache_bind_texture_sampler(0, img->gl.target, img->gl.tex[slot], 0);
|
||||
glTexParameteri(img->gl.target, GL_TEXTURE_MAX_LEVEL, img->cmn.num_mipmaps - 1);
|
||||
|
||||
// NOTE: workaround for https://issues.chromium.org/issues/355605685
|
||||
// FIXME: on GLES3 and GL 4.3 (e.g. not macOS) the texture initialization
|
||||
// should be rewritten to use glTexStorage + glTexSubImage
|
||||
bool tex_storage_allocated = false;
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
if (desc->data.subimage[0][0].ptr == 0) {
|
||||
tex_storage_allocated = true;
|
||||
if ((SG_IMAGETYPE_2D == img->cmn.type) || (SG_IMAGETYPE_CUBE == img->cmn.type)) {
|
||||
glTexStorage2D(img->gl.target, img->cmn.num_mipmaps, gl_internal_format, img->cmn.width, img->cmn.height);
|
||||
} else if ((SG_IMAGETYPE_3D == img->cmn.type) || (SG_IMAGETYPE_ARRAY == img->cmn.type)) {
|
||||
glTexStorage3D(img->gl.target, img->cmn.num_mipmaps, gl_internal_format, img->cmn.width, img->cmn.height, img->cmn.num_slices);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!tex_storage_allocated) {
|
||||
const int num_faces = img->cmn.type == SG_IMAGETYPE_CUBE ? 6 : 1;
|
||||
int data_index = 0;
|
||||
for (int face_index = 0; face_index < num_faces; face_index++) {
|
||||
|
@ -8337,6 +8365,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_image(_sg_image_t* img, const sg_
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_sg_gl_cache_restore_texture_sampler_binding(0);
|
||||
}
|
||||
}
|
||||
|
@ -10683,6 +10712,12 @@ _SOKOL_PRIVATE ID3DBlob* _sg_d3d11_compile_shader(const sg_shader_stage_desc* st
|
|||
return NULL;
|
||||
}
|
||||
SOKOL_ASSERT(stage_desc->d3d11_target);
|
||||
UINT flags1 = D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR;
|
||||
if (_sg.desc.d3d11_shader_debugging) {
|
||||
flags1 |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
|
||||
} else {
|
||||
flags1 |= D3DCOMPILE_OPTIMIZATION_LEVEL3;
|
||||
}
|
||||
ID3DBlob* output = NULL;
|
||||
ID3DBlob* errors_or_warnings = NULL;
|
||||
HRESULT hr = _sg.d3d11.D3DCompile_func(
|
||||
|
@ -10693,7 +10728,7 @@ _SOKOL_PRIVATE ID3DBlob* _sg_d3d11_compile_shader(const sg_shader_stage_desc* st
|
|||
NULL, // pInclude
|
||||
stage_desc->entry ? stage_desc->entry : "main", // pEntryPoint
|
||||
stage_desc->d3d11_target, // pTarget
|
||||
D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR | D3DCOMPILE_OPTIMIZATION_LEVEL3, // Flags1
|
||||
flags1, // Flags1
|
||||
0, // Flags2
|
||||
&output, // ppCode
|
||||
&errors_or_warnings); // ppErrorMsgs
|
||||
|
@ -11437,12 +11472,15 @@ _SOKOL_PRIVATE void _sg_d3d11_append_buffer(_sg_buffer_t* buf, const sg_range* d
|
|||
}
|
||||
}
|
||||
|
||||
// see: https://learn.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-resources-subresources
|
||||
// also see: https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-d3d11calcsubresource
|
||||
_SOKOL_PRIVATE void _sg_d3d11_update_image(_sg_image_t* img, const sg_image_data* data) {
|
||||
SOKOL_ASSERT(img && data);
|
||||
SOKOL_ASSERT(_sg.d3d11.ctx);
|
||||
SOKOL_ASSERT(img->d3d11.res);
|
||||
const int num_faces = (img->cmn.type == SG_IMAGETYPE_CUBE) ? 6:1;
|
||||
const int num_slices = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? img->cmn.num_slices:1;
|
||||
const int num_depth_slices = (img->cmn.type == SG_IMAGETYPE_3D) ? img->cmn.num_slices:1;
|
||||
UINT subres_index = 0;
|
||||
HRESULT hr;
|
||||
D3D11_MAPPED_SUBRESOURCE d3d11_msr;
|
||||
|
@ -11452,27 +11490,36 @@ _SOKOL_PRIVATE void _sg_d3d11_update_image(_sg_image_t* img, const sg_image_data
|
|||
SOKOL_ASSERT(subres_index < (SG_MAX_MIPMAPS * SG_MAX_TEXTUREARRAY_LAYERS));
|
||||
const int mip_width = _sg_miplevel_dim(img->cmn.width, mip_index);
|
||||
const int mip_height = _sg_miplevel_dim(img->cmn.height, mip_index);
|
||||
const int src_pitch = _sg_row_pitch(img->cmn.pixel_format, mip_width, 1);
|
||||
const int src_row_pitch = _sg_row_pitch(img->cmn.pixel_format, mip_width, 1);
|
||||
const int src_depth_pitch = _sg_surface_pitch(img->cmn.pixel_format, mip_width, mip_height, 1);
|
||||
const sg_range* subimg_data = &(data->subimage[face_index][mip_index]);
|
||||
const size_t slice_size = subimg_data->size / (size_t)num_slices;
|
||||
SOKOL_ASSERT(slice_size == (size_t)(src_depth_pitch * num_depth_slices));
|
||||
const size_t slice_offset = slice_size * (size_t)slice_index;
|
||||
const uint8_t* slice_ptr = ((const uint8_t*)subimg_data->ptr) + slice_offset;
|
||||
hr = _sg_d3d11_Map(_sg.d3d11.ctx, img->d3d11.res, subres_index, D3D11_MAP_WRITE_DISCARD, 0, &d3d11_msr);
|
||||
_sg_stats_add(d3d11.num_map, 1);
|
||||
if (SUCCEEDED(hr)) {
|
||||
// FIXME: need to handle difference in depth-pitch for 3D textures as well!
|
||||
if (src_pitch == (int)d3d11_msr.RowPitch) {
|
||||
memcpy(d3d11_msr.pData, slice_ptr, slice_size);
|
||||
} else {
|
||||
SOKOL_ASSERT(src_pitch < (int)d3d11_msr.RowPitch);
|
||||
const uint8_t* src_ptr = slice_ptr;
|
||||
uint8_t* dst_ptr = (uint8_t*)d3d11_msr.pData;
|
||||
for (int depth_index = 0; depth_index < num_depth_slices; depth_index++) {
|
||||
if (src_row_pitch == (int)d3d11_msr.RowPitch) {
|
||||
const size_t copy_size = slice_size / (size_t)num_depth_slices;
|
||||
SOKOL_ASSERT((copy_size * (size_t)num_depth_slices) == slice_size);
|
||||
memcpy(dst_ptr, src_ptr, copy_size);
|
||||
} else {
|
||||
SOKOL_ASSERT(src_row_pitch < (int)d3d11_msr.RowPitch);
|
||||
const uint8_t* src_row_ptr = src_ptr;
|
||||
uint8_t* dst_row_ptr = dst_ptr;
|
||||
for (int row_index = 0; row_index < mip_height; row_index++) {
|
||||
memcpy(dst_ptr, src_ptr, (size_t)src_pitch);
|
||||
src_ptr += src_pitch;
|
||||
dst_ptr += d3d11_msr.RowPitch;
|
||||
memcpy(dst_row_ptr, src_row_ptr, (size_t)src_row_pitch);
|
||||
src_row_ptr += src_row_pitch;
|
||||
dst_row_ptr += d3d11_msr.RowPitch;
|
||||
}
|
||||
}
|
||||
src_ptr += src_depth_pitch;
|
||||
dst_ptr += d3d11_msr.DepthPitch;
|
||||
}
|
||||
_sg_d3d11_Unmap(_sg.d3d11.ctx, img->d3d11.res, subres_index);
|
||||
_sg_stats_add(d3d11.num_unmap, 1);
|
||||
} else {
|
||||
|
@ -11853,8 +11900,6 @@ _SOKOL_PRIVATE MTLSamplerMinMagFilter _sg_mtl_minmag_filter(sg_filter f) {
|
|||
|
||||
_SOKOL_PRIVATE MTLSamplerMipFilter _sg_mtl_mipmap_filter(sg_filter f) {
|
||||
switch (f) {
|
||||
case SG_FILTER_NONE:
|
||||
return MTLSamplerMipFilterNotMipmapped;
|
||||
case SG_FILTER_NEAREST:
|
||||
return MTLSamplerMipFilterNearest;
|
||||
case SG_FILTER_LINEAR:
|
||||
|
@ -13410,7 +13455,6 @@ _SOKOL_PRIVATE WGPUFilterMode _sg_wgpu_sampler_minmag_filter(sg_filter f) {
|
|||
|
||||
_SOKOL_PRIVATE WGPUMipmapFilterMode _sg_wgpu_sampler_mipmap_filter(sg_filter f) {
|
||||
switch (f) {
|
||||
case SG_FILTER_NONE:
|
||||
case SG_FILTER_NEAREST:
|
||||
return WGPUMipmapFilterMode_Nearest;
|
||||
case SG_FILTER_LINEAR:
|
||||
|
@ -14005,6 +14049,26 @@ _SOKOL_PRIVATE uint64_t _sg_wgpu_hash(const void* key, int len, uint64_t seed) {
|
|||
return h;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE uint64_t _sg_wgpu_bindgroups_cache_item(_sg_wgpu_bindgroups_cache_item_type_t type, uint32_t id) {
|
||||
return (((uint64_t)type) << 32) | id;
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE uint64_t _sg_wgpu_bindgroups_cache_pip_item(uint32_t id) {
|
||||
return _sg_wgpu_bindgroups_cache_item(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_PIPELINE, id);
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE uint64_t _sg_wgpu_bindgroups_cache_image_item(uint32_t id) {
|
||||
return _sg_wgpu_bindgroups_cache_item(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_IMAGE, id);
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE uint64_t _sg_wgpu_bindgroups_cache_sampler_item(uint32_t id) {
|
||||
return _sg_wgpu_bindgroups_cache_item(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_SAMPLER, id);
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE uint64_t _sg_wgpu_bindgroups_cache_sbuf_item(uint32_t id) {
|
||||
return _sg_wgpu_bindgroups_cache_item(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_STORAGEBUFFER, id);
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sg_wgpu_init_bindgroups_cache_key(_sg_wgpu_bindgroups_cache_key_t* key, const _sg_bindings_t* bnd) {
|
||||
SOKOL_ASSERT(bnd);
|
||||
SOKOL_ASSERT(bnd->pip);
|
||||
|
@ -14016,38 +14080,39 @@ _SOKOL_PRIVATE void _sg_wgpu_init_bindgroups_cache_key(_sg_wgpu_bindgroups_cache
|
|||
SOKOL_ASSERT(bnd->num_fs_sbufs <= SG_MAX_SHADERSTAGE_STORAGEBUFFERS);
|
||||
|
||||
_sg_clear(key->items, sizeof(key->items));
|
||||
key->items[0] = bnd->pip->slot.id;
|
||||
const int vs_imgs_offset = 1;
|
||||
const int vs_smps_offset = vs_imgs_offset + SG_MAX_SHADERSTAGE_IMAGES;
|
||||
const int vs_sbufs_offset = vs_smps_offset + SG_MAX_SHADERSTAGE_SAMPLERS;
|
||||
const int fs_imgs_offset = vs_sbufs_offset + SG_MAX_SHADERSTAGE_STORAGEBUFFERS;
|
||||
const int fs_smps_offset = fs_imgs_offset + SG_MAX_SHADERSTAGE_IMAGES;
|
||||
const int fs_sbufs_offset = fs_smps_offset + SG_MAX_SHADERSTAGE_SAMPLERS;
|
||||
SOKOL_ASSERT((fs_sbufs_offset + SG_MAX_SHADERSTAGE_STORAGEBUFFERS) == _SG_WGPU_BINDGROUPSCACHE_NUM_ITEMS);
|
||||
int item_idx = 0;
|
||||
key->items[item_idx++] = _sg_wgpu_bindgroups_cache_pip_item(bnd->pip->slot.id);
|
||||
for (int i = 0; i < bnd->num_vs_imgs; i++) {
|
||||
SOKOL_ASSERT(bnd->vs_imgs[i]);
|
||||
key->items[vs_imgs_offset + i] = bnd->vs_imgs[i]->slot.id;
|
||||
SOKOL_ASSERT(item_idx < _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS);
|
||||
key->items[item_idx++] = _sg_wgpu_bindgroups_cache_image_item(bnd->vs_imgs[i]->slot.id);
|
||||
}
|
||||
for (int i = 0; i < bnd->num_vs_smps; i++) {
|
||||
SOKOL_ASSERT(bnd->vs_smps[i]);
|
||||
key->items[vs_smps_offset + i] = bnd->vs_smps[i]->slot.id;
|
||||
SOKOL_ASSERT(item_idx < _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS);
|
||||
key->items[item_idx++] = _sg_wgpu_bindgroups_cache_sampler_item(bnd->vs_smps[i]->slot.id);
|
||||
}
|
||||
for (int i = 0; i < bnd->num_vs_sbufs; i++) {
|
||||
SOKOL_ASSERT(bnd->vs_sbufs[i]);
|
||||
key->items[vs_sbufs_offset + i] = bnd->vs_sbufs[i]->slot.id;
|
||||
SOKOL_ASSERT(item_idx < _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS);
|
||||
key->items[item_idx++] = _sg_wgpu_bindgroups_cache_sbuf_item(bnd->vs_sbufs[i]->slot.id);
|
||||
}
|
||||
for (int i = 0; i < bnd->num_fs_imgs; i++) {
|
||||
SOKOL_ASSERT(bnd->fs_imgs[i]);
|
||||
key->items[fs_imgs_offset + i] = bnd->fs_imgs[i]->slot.id;
|
||||
SOKOL_ASSERT(item_idx < _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS);
|
||||
key->items[item_idx++] = _sg_wgpu_bindgroups_cache_image_item(bnd->fs_imgs[i]->slot.id);
|
||||
}
|
||||
for (int i = 0; i < bnd->num_fs_smps; i++) {
|
||||
SOKOL_ASSERT(bnd->fs_smps[i]);
|
||||
key->items[fs_smps_offset + i] = bnd->fs_smps[i]->slot.id;
|
||||
SOKOL_ASSERT(item_idx < _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS);
|
||||
key->items[item_idx++] = _sg_wgpu_bindgroups_cache_sampler_item(bnd->fs_smps[i]->slot.id);
|
||||
}
|
||||
for (int i = 0; i < bnd->num_fs_sbufs; i++) {
|
||||
SOKOL_ASSERT(bnd->fs_sbufs[i]);
|
||||
key->items[fs_sbufs_offset + i] = bnd->fs_sbufs[i]->slot.id;
|
||||
SOKOL_ASSERT(item_idx < _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS);
|
||||
key->items[item_idx++] = _sg_wgpu_bindgroups_cache_sbuf_item(bnd->fs_sbufs[i]->slot.id);
|
||||
}
|
||||
SOKOL_ASSERT(item_idx == (1 + bnd->num_vs_imgs + bnd->num_vs_smps + bnd->num_vs_sbufs + bnd->num_fs_imgs + bnd->num_fs_smps + bnd->num_fs_sbufs));
|
||||
key->hash = _sg_wgpu_hash(&key->items, (int)sizeof(key->items), 0x1234567887654321);
|
||||
}
|
||||
|
||||
|
@ -14199,6 +14264,33 @@ _SOKOL_PRIVATE uint32_t _sg_wgpu_bindgroups_cache_get(uint64_t hash) {
|
|||
return _sg.wgpu.bindgroups_cache.items[index].id;
|
||||
}
|
||||
|
||||
// called from wgpu resource destroy functions to also invalidate any
|
||||
// bindgroups cache slot and bindgroup referencing that resource
|
||||
_SOKOL_PRIVATE void _sg_wgpu_bindgroups_cache_invalidate(_sg_wgpu_bindgroups_cache_item_type_t type, uint32_t id) {
|
||||
const uint64_t key_item = _sg_wgpu_bindgroups_cache_item(type, id);
|
||||
SOKOL_ASSERT(_sg.wgpu.bindgroups_cache.items);
|
||||
for (uint32_t cache_item_idx = 0; cache_item_idx < _sg.wgpu.bindgroups_cache.num; cache_item_idx++) {
|
||||
const uint32_t bg_id = _sg.wgpu.bindgroups_cache.items[cache_item_idx].id;
|
||||
if (bg_id != SG_INVALID_ID) {
|
||||
_sg_wgpu_bindgroup_t* bg = _sg_wgpu_lookup_bindgroup(bg_id);
|
||||
SOKOL_ASSERT(bg && (bg->slot.state == SG_RESOURCESTATE_VALID));
|
||||
// check if resource is in bindgroup, if yes discard bindgroup and invalidate cache slot
|
||||
bool invalidate_cache_item = false;
|
||||
for (int key_item_idx = 0; key_item_idx < _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS; key_item_idx++) {
|
||||
if (bg->key.items[key_item_idx] == key_item) {
|
||||
invalidate_cache_item = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (invalidate_cache_item) {
|
||||
_sg_wgpu_discard_bindgroup(bg); bg = 0;
|
||||
_sg_wgpu_bindgroups_cache_set(cache_item_idx, SG_INVALID_ID);
|
||||
_sg_stats_add(wgpu.bindings.num_bindgroup_cache_invalidates, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sg_wgpu_bindings_cache_clear(void) {
|
||||
memset(&_sg.wgpu.bindings_cache, 0, sizeof(_sg.wgpu.bindings_cache));
|
||||
}
|
||||
|
@ -14259,7 +14351,7 @@ _SOKOL_PRIVATE void _sg_wgpu_bindings_cache_bg_update(const _sg_wgpu_bindgroup_t
|
|||
}
|
||||
}
|
||||
|
||||
_SOKOL_PRIVATE void _sg_wgpu_set_bindings_bindgroup(_sg_wgpu_bindgroup_t* bg) {
|
||||
_SOKOL_PRIVATE void _sg_wgpu_set_bindgroup(_sg_wgpu_bindgroup_t* bg) {
|
||||
if (_sg_wgpu_bindings_cache_bg_dirty(bg)) {
|
||||
_sg_wgpu_bindings_cache_bg_update(bg);
|
||||
_sg_stats_add(wgpu.bindings.num_set_bindgroup, 1);
|
||||
|
@ -14305,7 +14397,7 @@ _SOKOL_PRIVATE bool _sg_wgpu_apply_bindgroup(_sg_bindings_t* bnd) {
|
|||
_sg_wgpu_bindgroups_cache_set(key.hash, bg->slot.id);
|
||||
}
|
||||
if (bg && bg->slot.state == SG_RESOURCESTATE_VALID) {
|
||||
_sg_wgpu_set_bindings_bindgroup(bg);
|
||||
_sg_wgpu_set_bindgroup(bg);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -14314,7 +14406,7 @@ _SOKOL_PRIVATE bool _sg_wgpu_apply_bindgroup(_sg_bindings_t* bnd) {
|
|||
_sg_wgpu_bindgroup_t* bg = _sg_wgpu_create_bindgroup(bnd);
|
||||
if (bg) {
|
||||
if (bg->slot.state == SG_RESOURCESTATE_VALID) {
|
||||
_sg_wgpu_set_bindings_bindgroup(bg);
|
||||
_sg_wgpu_set_bindgroup(bg);
|
||||
}
|
||||
_sg_wgpu_discard_bindgroup(bg);
|
||||
} else {
|
||||
|
@ -14322,7 +14414,7 @@ _SOKOL_PRIVATE bool _sg_wgpu_apply_bindgroup(_sg_bindings_t* bnd) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
_sg_wgpu_set_bindings_bindgroup(0);
|
||||
_sg_wgpu_set_bindgroup(0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -14455,8 +14547,10 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_buffer(_sg_buffer_t* buf, const
|
|||
|
||||
_SOKOL_PRIVATE void _sg_wgpu_discard_buffer(_sg_buffer_t* buf) {
|
||||
SOKOL_ASSERT(buf);
|
||||
if (buf->cmn.type == SG_BUFFERTYPE_STORAGEBUFFER) {
|
||||
_sg_wgpu_bindgroups_cache_invalidate(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_STORAGEBUFFER, buf->slot.id);
|
||||
}
|
||||
if (buf->wgpu.buf) {
|
||||
wgpuBufferDestroy(buf->wgpu.buf);
|
||||
wgpuBufferRelease(buf->wgpu.buf);
|
||||
}
|
||||
}
|
||||
|
@ -14592,12 +14686,12 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_image(_sg_image_t* img, const s
|
|||
|
||||
_SOKOL_PRIVATE void _sg_wgpu_discard_image(_sg_image_t* img) {
|
||||
SOKOL_ASSERT(img);
|
||||
_sg_wgpu_bindgroups_cache_invalidate(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_IMAGE, img->slot.id);
|
||||
if (img->wgpu.view) {
|
||||
wgpuTextureViewRelease(img->wgpu.view);
|
||||
img->wgpu.view = 0;
|
||||
}
|
||||
if (img->wgpu.tex) {
|
||||
wgpuTextureDestroy(img->wgpu.tex);
|
||||
wgpuTextureRelease(img->wgpu.tex);
|
||||
img->wgpu.tex = 0;
|
||||
}
|
||||
|
@ -14638,6 +14732,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_sampler(_sg_sampler_t* smp, con
|
|||
|
||||
_SOKOL_PRIVATE void _sg_wgpu_discard_sampler(_sg_sampler_t* smp) {
|
||||
SOKOL_ASSERT(smp);
|
||||
_sg_wgpu_bindgroups_cache_invalidate(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_SAMPLER, smp->slot.id);
|
||||
if (smp->wgpu.smp) {
|
||||
wgpuSamplerRelease(smp->wgpu.smp);
|
||||
smp->wgpu.smp = 0;
|
||||
|
@ -14875,6 +14970,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_pipeline(_sg_pipeline_t* pip, _
|
|||
|
||||
_SOKOL_PRIVATE void _sg_wgpu_discard_pipeline(_sg_pipeline_t* pip) {
|
||||
SOKOL_ASSERT(pip);
|
||||
_sg_wgpu_bindgroups_cache_invalidate(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_PIPELINE, pip->slot.id);
|
||||
if (pip == _sg.wgpu.cur_pipeline) {
|
||||
_sg.wgpu.cur_pipeline = 0;
|
||||
_sg.wgpu.cur_pipeline_id.id = SG_INVALID_ID;
|
||||
|
@ -16219,8 +16315,6 @@ _SOKOL_PRIVATE bool _sg_validate_sampler_desc(const sg_sampler_desc* desc) {
|
|||
_sg_validate_begin();
|
||||
_SG_VALIDATE(desc->_start_canary == 0, VALIDATE_SAMPLERDESC_CANARY);
|
||||
_SG_VALIDATE(desc->_end_canary == 0, VALIDATE_SAMPLERDESC_CANARY);
|
||||
_SG_VALIDATE(desc->min_filter != SG_FILTER_NONE, VALIDATE_SAMPLERDESC_MINFILTER_NONE);
|
||||
_SG_VALIDATE(desc->mag_filter != SG_FILTER_NONE, VALIDATE_SAMPLERDESC_MAGFILTER_NONE);
|
||||
// restriction from WebGPU: when anisotropy > 1, all filters must be linear
|
||||
if (desc->max_anisotropy > 1) {
|
||||
_SG_VALIDATE((desc->min_filter == SG_FILTER_LINEAR)
|
||||
|
@ -17040,7 +17134,7 @@ _SOKOL_PRIVATE sg_sampler_desc _sg_sampler_desc_defaults(const sg_sampler_desc*
|
|||
sg_sampler_desc def = *desc;
|
||||
def.min_filter = _sg_def(def.min_filter, SG_FILTER_NEAREST);
|
||||
def.mag_filter = _sg_def(def.mag_filter, SG_FILTER_NEAREST);
|
||||
def.mipmap_filter = _sg_def(def.mipmap_filter, SG_FILTER_NONE);
|
||||
def.mipmap_filter = _sg_def(def.mipmap_filter, SG_FILTER_NEAREST);
|
||||
def.wrap_u = _sg_def(def.wrap_u, SG_WRAP_REPEAT);
|
||||
def.wrap_v = _sg_def(def.wrap_v, SG_WRAP_REPEAT);
|
||||
def.wrap_w = _sg_def(def.wrap_w, SG_WRAP_REPEAT);
|
||||
|
|
|
@ -1661,7 +1661,6 @@ static int _sfons_render_create(void* user_ptr, int width, int height) {
|
|||
_sfons_clear(&smp_desc, sizeof(smp_desc));
|
||||
smp_desc.min_filter = SG_FILTER_LINEAR;
|
||||
smp_desc.mag_filter = SG_FILTER_LINEAR;
|
||||
smp_desc.mipmap_filter = SG_FILTER_NONE;
|
||||
sfons->smp = sg_make_sampler(&smp_desc);
|
||||
}
|
||||
|
||||
|
|
|
@ -1287,7 +1287,6 @@ _SOKOL_PRIVATE const char* _sgimgui_pixelformat_string(sg_pixel_format fmt) {
|
|||
|
||||
_SOKOL_PRIVATE const char* _sgimgui_filter_string(sg_filter f) {
|
||||
switch (f) {
|
||||
case SG_FILTER_NONE: return "SG_FILTER_NONE";
|
||||
case SG_FILTER_NEAREST: return "SG_FILTER_NEAREST";
|
||||
case SG_FILTER_LINEAR: return "SG_FILTER_LINEAR";
|
||||
default: return "???";
|
||||
|
@ -4287,7 +4286,7 @@ _SOKOL_PRIVATE void _sgimgui_draw_frame_stats_panel(sgimgui_t* ctx) {
|
|||
ImGuiTableFlags_SizingFixedFit |
|
||||
ImGuiTableFlags_Borders;
|
||||
if (igBeginTable("##frame_stats_table", 2, flags, IMVEC2(0, 0), 0)) {
|
||||
igTableSetupScrollFreeze(0, 2);
|
||||
igTableSetupScrollFreeze(0, 1);
|
||||
igTableSetupColumn("key", ImGuiTableColumnFlags_None, 0, 0);
|
||||
igTableSetupColumn("value", ImGuiTableColumnFlags_None, 0, 0);
|
||||
igTableHeadersRow();
|
||||
|
@ -4335,6 +4334,7 @@ _SOKOL_PRIVATE void _sgimgui_draw_frame_stats_panel(sgimgui_t* ctx) {
|
|||
_sgimgui_frame_stats(wgpu.bindings.num_bindgroup_cache_hits);
|
||||
_sgimgui_frame_stats(wgpu.bindings.num_bindgroup_cache_misses);
|
||||
_sgimgui_frame_stats(wgpu.bindings.num_bindgroup_cache_collisions);
|
||||
_sgimgui_frame_stats(wgpu.bindings.num_bindgroup_cache_invalidates);
|
||||
_sgimgui_frame_stats(wgpu.bindings.num_bindgroup_cache_hash_vs_key_mismatch);
|
||||
break;
|
||||
case SG_BACKEND_METAL_MACOS:
|
||||
|
|
140
source/engine/thirdparty/sokol/util/sokol_gl.h
vendored
140
source/engine/thirdparty/sokol/util/sokol_gl.h
vendored
|
@ -372,8 +372,8 @@
|
|||
the last call to sgl_draw() through sokol-gfx, and will 'rewind' the internal
|
||||
vertex-, uniform- and command-buffers.
|
||||
|
||||
--- each sokol-gl context tracks an internal error code, to query the
|
||||
current error code for the currently active context call:
|
||||
--- each sokol-gl context tracks internal error states which can
|
||||
be obtains via:
|
||||
|
||||
sgl_error_t sgl_error()
|
||||
|
||||
|
@ -381,18 +381,28 @@
|
|||
|
||||
sgl_error_t sgl_context_error(ctx);
|
||||
|
||||
...which can return the following error codes:
|
||||
...this returns a struct with the following booleans:
|
||||
|
||||
SGL_NO_ERROR - all OK, no error occurred since last sgl_draw()
|
||||
SGL_ERROR_VERTICES_FULL - internal vertex buffer is full (checked in sgl_end())
|
||||
SGL_ERROR_UNIFORMS_FULL - the internal uniforms buffer is full (checked in sgl_end())
|
||||
SGL_ERROR_COMMANDS_FULL - the internal command buffer is full (checked in sgl_end())
|
||||
SGL_ERROR_STACK_OVERFLOW - matrix- or pipeline-stack overflow
|
||||
SGL_ERROR_STACK_UNDERFLOW - matrix- or pipeline-stack underflow
|
||||
SGL_ERROR_NO_CONTEXT - the active context no longer exists
|
||||
.any - true if any of the below errors is true
|
||||
.vertices_full - internal vertex buffer is full (checked in sgl_end())
|
||||
.uniforms_full - the internal uniforms buffer is full (checked in sgl_end())
|
||||
.commands_full - the internal command buffer is full (checked in sgl_end())
|
||||
.stack_overflow - matrix- or pipeline-stack overflow
|
||||
.stack_underflow - matrix- or pipeline-stack underflow
|
||||
.no_context - the active context no longer exists
|
||||
|
||||
...if sokol-gl is in an error-state, sgl_draw() will skip any rendering,
|
||||
and reset the error code to SGL_NO_ERROR.
|
||||
...depending on the above error state, sgl_draw() may skip rendering
|
||||
completely, or only draw partial geometry
|
||||
|
||||
--- you can get the number of recorded vertices and draw commands in the current
|
||||
frame and active sokol-gl context via:
|
||||
|
||||
int sgl_num_vertices()
|
||||
int sgl_num_commands()
|
||||
|
||||
...this allows you to check whether the vertex or command pools are running
|
||||
full before the overflow actually happens (in this case you could also
|
||||
check the error booleans in the result of sgl_error()).
|
||||
|
||||
RENDER LAYERS
|
||||
=============
|
||||
|
@ -762,14 +772,14 @@ typedef struct sgl_context { uint32_t id; } sgl_context;
|
|||
Errors are reset each frame after calling sgl_draw(),
|
||||
get the last error code with sgl_error()
|
||||
*/
|
||||
typedef enum sgl_error_t {
|
||||
SGL_NO_ERROR = 0,
|
||||
SGL_ERROR_VERTICES_FULL,
|
||||
SGL_ERROR_UNIFORMS_FULL,
|
||||
SGL_ERROR_COMMANDS_FULL,
|
||||
SGL_ERROR_STACK_OVERFLOW,
|
||||
SGL_ERROR_STACK_UNDERFLOW,
|
||||
SGL_ERROR_NO_CONTEXT,
|
||||
typedef struct sgl_error_t {
|
||||
bool any;
|
||||
bool vertices_full;
|
||||
bool uniforms_full;
|
||||
bool commands_full;
|
||||
bool stack_overflow;
|
||||
bool stack_underflow;
|
||||
bool no_context;
|
||||
} sgl_error_t;
|
||||
|
||||
/*
|
||||
|
@ -832,6 +842,10 @@ SOKOL_GL_API_DECL void sgl_set_context(sgl_context ctx);
|
|||
SOKOL_GL_API_DECL sgl_context sgl_get_context(void);
|
||||
SOKOL_GL_API_DECL sgl_context sgl_default_context(void);
|
||||
|
||||
/* get information about recorded vertices and commands in current context */
|
||||
SOKOL_GL_API_DECL int sgl_num_vertices(void);
|
||||
SOKOL_GL_API_DECL int sgl_num_commands(void);
|
||||
|
||||
/* draw recorded commands (call inside a sokol-gfx render pass) */
|
||||
SOKOL_GL_API_DECL void sgl_draw(void);
|
||||
SOKOL_GL_API_DECL void sgl_context_draw(sgl_context ctx);
|
||||
|
@ -2342,7 +2356,7 @@ typedef struct {
|
|||
|
||||
/* state tracking */
|
||||
int base_vertex;
|
||||
int vtx_count; /* number of times vtx function has been called, used for non-triangle primitives */
|
||||
int quad_vtx_count; /* number of times vtx function has been called, used for non-triangle primitives */
|
||||
sgl_error_t error;
|
||||
bool in_begin;
|
||||
int layer_id;
|
||||
|
@ -2903,10 +2917,24 @@ static void _sgl_destroy_context(sgl_context ctx_id) {
|
|||
// ██ ██ ██ ███████ ██████
|
||||
//
|
||||
// >>misc
|
||||
|
||||
static sgl_error_t _sgl_error_defaults(void) {
|
||||
sgl_error_t defaults = {0};
|
||||
return defaults;
|
||||
}
|
||||
|
||||
static int _sgl_num_vertices(_sgl_context_t* ctx) {
|
||||
return ctx->vertices.next;
|
||||
}
|
||||
|
||||
static int _sgl_num_commands(_sgl_context_t* ctx) {
|
||||
return ctx->commands.next;
|
||||
}
|
||||
|
||||
static void _sgl_begin(_sgl_context_t* ctx, _sgl_primitive_type_t mode) {
|
||||
ctx->in_begin = true;
|
||||
ctx->base_vertex = ctx->vertices.next;
|
||||
ctx->vtx_count = 0;
|
||||
ctx->quad_vtx_count = 0;
|
||||
ctx->cur_prim_type = mode;
|
||||
}
|
||||
|
||||
|
@ -2916,7 +2944,7 @@ static void _sgl_rewind(_sgl_context_t* ctx) {
|
|||
ctx->uniforms.next = 0;
|
||||
ctx->commands.next = 0;
|
||||
ctx->base_vertex = 0;
|
||||
ctx->error = SGL_NO_ERROR;
|
||||
ctx->error = _sgl_error_defaults();
|
||||
ctx->layer_id = 0;
|
||||
ctx->matrix_dirty = true;
|
||||
}
|
||||
|
@ -2938,7 +2966,8 @@ static _sgl_vertex_t* _sgl_next_vertex(_sgl_context_t* ctx) {
|
|||
if (ctx->vertices.next < ctx->vertices.cap) {
|
||||
return &ctx->vertices.ptr[ctx->vertices.next++];
|
||||
} else {
|
||||
ctx->error = SGL_ERROR_VERTICES_FULL;
|
||||
ctx->error.vertices_full = true;
|
||||
ctx->error.any = true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -2947,7 +2976,8 @@ static _sgl_uniform_t* _sgl_next_uniform(_sgl_context_t* ctx) {
|
|||
if (ctx->uniforms.next < ctx->uniforms.cap) {
|
||||
return &ctx->uniforms.ptr[ctx->uniforms.next++];
|
||||
} else {
|
||||
ctx->error = SGL_ERROR_UNIFORMS_FULL;
|
||||
ctx->error.uniforms_full = true;
|
||||
ctx->error.any = true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -2964,7 +2994,8 @@ static _sgl_command_t* _sgl_next_command(_sgl_context_t* ctx) {
|
|||
if (ctx->commands.next < ctx->commands.cap) {
|
||||
return &ctx->commands.ptr[ctx->commands.next++];
|
||||
} else {
|
||||
ctx->error = SGL_ERROR_COMMANDS_FULL;
|
||||
ctx->error.commands_full = true;
|
||||
ctx->error.any = true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -2991,7 +3022,7 @@ static void _sgl_vtx(_sgl_context_t* ctx, float x, float y, float z, float u, fl
|
|||
SOKOL_ASSERT(ctx->in_begin);
|
||||
_sgl_vertex_t* vtx;
|
||||
/* handle non-native primitive types */
|
||||
if ((ctx->cur_prim_type == SGL_PRIMITIVETYPE_QUADS) && ((ctx->vtx_count & 3) == 3)) {
|
||||
if ((ctx->cur_prim_type == SGL_PRIMITIVETYPE_QUADS) && ((ctx->quad_vtx_count & 3) == 3)) {
|
||||
/* for quads, before writing the last quad vertex, reuse
|
||||
the first and third vertex to start the second triangle in the quad
|
||||
*/
|
||||
|
@ -3007,7 +3038,7 @@ static void _sgl_vtx(_sgl_context_t* ctx, float x, float y, float z, float u, fl
|
|||
vtx->rgba = rgba;
|
||||
vtx->psize = ctx->point_size;
|
||||
}
|
||||
ctx->vtx_count++;
|
||||
ctx->quad_vtx_count++;
|
||||
}
|
||||
|
||||
static void _sgl_identity(_sgl_matrix_t* m) {
|
||||
|
@ -3342,7 +3373,7 @@ static bool _sgl_is_default_context(sgl_context ctx_id) {
|
|||
|
||||
static void _sgl_draw(_sgl_context_t* ctx, int layer_id) {
|
||||
SOKOL_ASSERT(ctx);
|
||||
if ((ctx->error == SGL_NO_ERROR) && (ctx->vertices.next > 0) && (ctx->commands.next > 0)) {
|
||||
if ((ctx->vertices.next > 0) && (ctx->commands.next > 0)) {
|
||||
sg_push_debug_group("sokol-gl");
|
||||
|
||||
uint32_t cur_pip_id = SG_INVALID_ID;
|
||||
|
@ -3356,6 +3387,8 @@ static void _sgl_draw(_sgl_context_t* ctx, int layer_id) {
|
|||
sg_update_buffer(ctx->vbuf, &range);
|
||||
}
|
||||
|
||||
// render all successfully recorded commands (this may be less than the
|
||||
// issued commands if we're in an error state)
|
||||
for (int i = 0; i < ctx->commands.next; i++) {
|
||||
const _sgl_command_t* cmd = &ctx->commands.ptr[i];
|
||||
if (cmd->layer_id != layer_id) {
|
||||
|
@ -3463,7 +3496,10 @@ SOKOL_API_IMPL sgl_error_t sgl_error(void) {
|
|||
if (ctx) {
|
||||
return ctx->error;
|
||||
} else {
|
||||
return SGL_ERROR_NO_CONTEXT;
|
||||
sgl_error_t err = _sgl_error_defaults();
|
||||
err.no_context = true;
|
||||
err.any = true;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3472,7 +3508,10 @@ SOKOL_API_IMPL sgl_error_t sgl_context_error(sgl_context ctx_id) {
|
|||
if (ctx) {
|
||||
return ctx->error;
|
||||
} else {
|
||||
return SGL_ERROR_NO_CONTEXT;
|
||||
sgl_error_t err = _sgl_error_defaults();
|
||||
err.no_context = true;
|
||||
err.any = true;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3521,6 +3560,26 @@ SOKOL_API_IMPL sgl_context sgl_default_context(void) {
|
|||
return SGL_DEFAULT_CONTEXT;
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL int sgl_num_vertices(void) {
|
||||
SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie);
|
||||
_sgl_context_t* ctx = _sgl.cur_ctx;
|
||||
if (ctx) {
|
||||
return _sgl_num_vertices(ctx);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL int sgl_num_commands(void) {
|
||||
SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie);
|
||||
_sgl_context_t* ctx = _sgl.cur_ctx;
|
||||
if (ctx) {
|
||||
return _sgl_num_commands(ctx);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
SOKOL_API_IMPL sgl_pipeline sgl_make_pipeline(const sg_pipeline_desc* desc) {
|
||||
SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie);
|
||||
_sgl_context_t* ctx = _sgl.cur_ctx;
|
||||
|
@ -3576,7 +3635,8 @@ SOKOL_API_IMPL void sgl_push_pipeline(void) {
|
|||
ctx->pip_tos++;
|
||||
ctx->pip_stack[ctx->pip_tos] = ctx->pip_stack[ctx->pip_tos-1];
|
||||
} else {
|
||||
ctx->error = SGL_ERROR_STACK_OVERFLOW;
|
||||
ctx->error.stack_overflow = true;
|
||||
ctx->error.any = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3589,7 +3649,8 @@ SOKOL_API_IMPL void sgl_pop_pipeline(void) {
|
|||
if (ctx->pip_tos > 0) {
|
||||
ctx->pip_tos--;
|
||||
} else {
|
||||
ctx->error = SGL_ERROR_STACK_UNDERFLOW;
|
||||
ctx->error.stack_underflow = true;
|
||||
ctx->error.any = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3778,6 +3839,7 @@ SOKOL_API_IMPL void sgl_end(void) {
|
|||
SOKOL_ASSERT(ctx->in_begin);
|
||||
SOKOL_ASSERT(ctx->vertices.next >= ctx->base_vertex);
|
||||
ctx->in_begin = false;
|
||||
|
||||
bool matrix_dirty = ctx->matrix_dirty;
|
||||
if (matrix_dirty) {
|
||||
ctx->matrix_dirty = false;
|
||||
|
@ -3787,6 +3849,12 @@ SOKOL_API_IMPL void sgl_end(void) {
|
|||
uni->tm = *_sgl_matrix_texture(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
// don't record any new commands when we're in an error state
|
||||
if (ctx->error.any) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check if command can be merged with current command
|
||||
sg_pipeline pip = _sgl_get_pipeline(ctx->pip_stack[ctx->pip_tos], ctx->cur_prim_type);
|
||||
sg_image img = ctx->texturing_enabled ? ctx->cur_img : _sgl.def_img;
|
||||
|
@ -4205,7 +4273,8 @@ SOKOL_GL_API_DECL void sgl_push_matrix(void) {
|
|||
_sgl_matrix_t* dst = _sgl_matrix(ctx);
|
||||
*dst = *src;
|
||||
} else {
|
||||
ctx->error = SGL_ERROR_STACK_OVERFLOW;
|
||||
ctx->error.stack_overflow = true;
|
||||
ctx->error.any = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4220,7 +4289,8 @@ SOKOL_GL_API_DECL void sgl_pop_matrix(void) {
|
|||
if (ctx->matrix_tos[ctx->cur_matrix_mode] > 0) {
|
||||
ctx->matrix_tos[ctx->cur_matrix_mode]--;
|
||||
} else {
|
||||
ctx->error = SGL_ERROR_STACK_UNDERFLOW;
|
||||
ctx->error.stack_underflow = true;
|
||||
ctx->error.any = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1844,13 +1844,13 @@ static const char* _simgui_fs_source_dummy = "";
|
|||
#endif
|
||||
|
||||
#if !defined(SOKOL_IMGUI_NO_SOKOL_APP)
|
||||
static void _simgui_set_clipboard(void* user_data, const char* text) {
|
||||
(void)user_data;
|
||||
static void _simgui_set_clipboard(ImGuiContext* ctx, const char* text) {
|
||||
(void)ctx;
|
||||
sapp_set_clipboard_string(text);
|
||||
}
|
||||
|
||||
static const char* _simgui_get_clipboard(void* user_data) {
|
||||
(void)user_data;
|
||||
static const char* _simgui_get_clipboard(ImGuiContext* ctx) {
|
||||
(void)ctx;
|
||||
return sapp_get_clipboard_string();
|
||||
}
|
||||
#endif
|
||||
|
@ -2200,6 +2200,7 @@ SOKOL_API_IMPL void simgui_setup(const simgui_desc_t* desc) {
|
|||
ImGui::CreateContext();
|
||||
ImGui::StyleColorsDark();
|
||||
ImGuiIO* io = &ImGui::GetIO();
|
||||
ImGuiPlatformIO* pio = &ImGui::GetPlatformIO();
|
||||
if (!_simgui.desc.no_default_font) {
|
||||
io->Fonts->AddFontDefault();
|
||||
}
|
||||
|
@ -2207,6 +2208,7 @@ SOKOL_API_IMPL void simgui_setup(const simgui_desc_t* desc) {
|
|||
igCreateContext(NULL);
|
||||
igStyleColorsDark(igGetStyle());
|
||||
ImGuiIO* io = igGetIO();
|
||||
ImGuiPlatformIO* pio = igGetPlatformIO();
|
||||
if (!_simgui.desc.no_default_font) {
|
||||
ImFontAtlas_AddFontDefault(io->Fonts, NULL);
|
||||
}
|
||||
|
@ -2218,8 +2220,8 @@ SOKOL_API_IMPL void simgui_setup(const simgui_desc_t* desc) {
|
|||
if (!_simgui.desc.disable_set_mouse_cursor) {
|
||||
io->BackendFlags |= ImGuiBackendFlags_HasMouseCursors;
|
||||
}
|
||||
io->SetClipboardTextFn = _simgui_set_clipboard;
|
||||
io->GetClipboardTextFn = _simgui_get_clipboard;
|
||||
pio->Platform_SetClipboardTextFn = _simgui_set_clipboard;
|
||||
pio->Platform_GetClipboardTextFn = _simgui_get_clipboard;
|
||||
#endif
|
||||
io->ConfigWindowsResizeFromEdges = !_simgui.desc.disable_windows_resize_from_edges;
|
||||
|
||||
|
@ -2400,7 +2402,6 @@ SOKOL_API_IMPL void simgui_create_fonts_texture(const simgui_font_tex_desc_t* de
|
|||
font_smp_desc.wrap_v = SG_WRAP_CLAMP_TO_EDGE;
|
||||
font_smp_desc.min_filter = desc->min_filter;
|
||||
font_smp_desc.mag_filter = desc->mag_filter;
|
||||
font_smp_desc.mipmap_filter = SG_FILTER_NONE;
|
||||
font_smp_desc.label = "sokol-imgui-font-sampler";
|
||||
_simgui.font_smp = sg_make_sampler(&font_smp_desc);
|
||||
|
||||
|
|
|
@ -236,7 +236,7 @@
|
|||
.overrides = {
|
||||
.min_filter = SG_FILTER_NEAREST,
|
||||
.mag_filter = SG_FILTER_NEAREST,
|
||||
.mipmap_filter = SG_FILTER_NONE,
|
||||
.mipmap_filter = SG_FILTER_NEAREST,
|
||||
.wrap_u = SG_WRAP_MIRROR,
|
||||
.wrap_v = SG_WRAP_MIRROR,
|
||||
.premul_alpha_enabled = ...,
|
||||
|
@ -4573,15 +4573,19 @@ static sg_filter _sspine_as_sampler_filter(spAtlasFilter filter) {
|
|||
|
||||
static sg_filter _sspine_as_sampler_mipmap_filter(spAtlasFilter filter) {
|
||||
switch (filter) {
|
||||
case SP_ATLAS_UNKNOWN_FILTER: return _SG_FILTER_DEFAULT;
|
||||
case SP_ATLAS_NEAREST: return SG_FILTER_NONE;
|
||||
case SP_ATLAS_LINEAR: return SG_FILTER_NONE;
|
||||
case SP_ATLAS_MIPMAP: return SG_FILTER_NEAREST;
|
||||
case SP_ATLAS_MIPMAP_NEAREST_NEAREST: return SG_FILTER_NEAREST;
|
||||
case SP_ATLAS_MIPMAP_LINEAR_NEAREST: return SG_FILTER_NEAREST;
|
||||
case SP_ATLAS_MIPMAP_NEAREST_LINEAR: return SG_FILTER_LINEAR;
|
||||
case SP_ATLAS_MIPMAP_LINEAR_LINEAR: return SG_FILTER_LINEAR;
|
||||
default: return SG_FILTER_NEAREST;
|
||||
case SP_ATLAS_UNKNOWN_FILTER:
|
||||
return _SG_FILTER_DEFAULT;
|
||||
case SP_ATLAS_NEAREST:
|
||||
case SP_ATLAS_LINEAR:
|
||||
case SP_ATLAS_MIPMAP:
|
||||
case SP_ATLAS_MIPMAP_NEAREST_NEAREST:
|
||||
case SP_ATLAS_MIPMAP_LINEAR_NEAREST:
|
||||
return SG_FILTER_NEAREST;
|
||||
case SP_ATLAS_MIPMAP_NEAREST_LINEAR:
|
||||
case SP_ATLAS_MIPMAP_LINEAR_LINEAR:
|
||||
return SG_FILTER_LINEAR;
|
||||
default:
|
||||
return SG_FILTER_NEAREST;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,22 +1,31 @@
|
|||
#include "timer.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "stb_ds.h"
|
||||
|
||||
timer *timers;
|
||||
timer **timers;
|
||||
|
||||
timer *timer_make()
|
||||
{
|
||||
return NULL;
|
||||
timer *t = calloc(sizeof(*t),1);
|
||||
arrput(timers, t);
|
||||
return t;
|
||||
}
|
||||
|
||||
void timer_free(timer *t)
|
||||
{
|
||||
for (int i = 0; i < arrlen(timers); i++) {
|
||||
if (timers[i] == t) {
|
||||
arrdelswap(timers,i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(t);
|
||||
}
|
||||
|
||||
void timer_update(double dt)
|
||||
{
|
||||
for (int i = 0; i < arrlen(timers); i++) {
|
||||
timers[i].remain -= dt;
|
||||
timers[i]->remain -= dt;
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ typedef struct timer {
|
|||
double remain;
|
||||
} timer;
|
||||
|
||||
|
||||
timer *timer_make();
|
||||
void timer_free(timer *t);
|
||||
void timer_update(double dt);
|
||||
|
|
|
@ -114,30 +114,37 @@ void c_event(const sapp_event *e)
|
|||
char lcfmt[5];
|
||||
switch (e->type) {
|
||||
case SAPP_EVENTTYPE_MOUSE_MOVE:
|
||||
if (gui_wantmouse()) return;
|
||||
script_evalf("prosperon.mousemove([%g, %g], [%g, %g]);", e->mouse_x, e->mouse_y, e->mouse_dx, -e->mouse_dy);
|
||||
break;
|
||||
|
||||
case SAPP_EVENTTYPE_MOUSE_SCROLL:
|
||||
if (gui_wantmouse()) return;
|
||||
script_evalf("prosperon.mousescroll([%g, %g]);", e->scroll_x, e->scroll_y);
|
||||
break;
|
||||
|
||||
case SAPP_EVENTTYPE_KEY_DOWN:
|
||||
if (gui_wantkeys()) return;
|
||||
script_evalf("prosperon.keydown(%d, %d);", e->key_code, e->key_repeat);
|
||||
break;
|
||||
|
||||
case SAPP_EVENTTYPE_KEY_UP:
|
||||
if (gui_wantkeys()) return;
|
||||
script_evalf("prosperon.keyup(%d);", e->key_code);
|
||||
break;
|
||||
|
||||
case SAPP_EVENTTYPE_MOUSE_UP:
|
||||
if (gui_wantmouse()) return;
|
||||
script_evalf("prosperon.mouseup(%d);", e->mouse_button);
|
||||
break;
|
||||
|
||||
case SAPP_EVENTTYPE_MOUSE_DOWN:
|
||||
if (gui_wantmouse()) return;
|
||||
script_evalf("prosperon.mousedown(%d);", e->mouse_button);
|
||||
break;
|
||||
|
||||
case SAPP_EVENTTYPE_CHAR:
|
||||
if (gui_wantkeys()) return;
|
||||
if (iswcntrl(e->char_code)) break;
|
||||
snprintf(lcfmt, 5, "%lc", e->char_code);
|
||||
script_evalf("prosperon.textinput(`%s`);", lcfmt);
|
||||
|
@ -176,9 +183,11 @@ void c_event(const sapp_event *e)
|
|||
break;
|
||||
|
||||
case SAPP_EVENTTYPE_MOUSE_ENTER:
|
||||
if (gui_wantmouse()) return;
|
||||
script_evalf("prosperon.mouseenter();");
|
||||
break;
|
||||
case SAPP_EVENTTYPE_MOUSE_LEAVE:
|
||||
if (gui_wantmouse()) return;
|
||||
script_evalf("prosperon.mouseleave();");
|
||||
break;
|
||||
case SAPP_EVENTTYPE_TOUCHES_BEGAN:
|
||||
|
|
Loading…
Reference in a new issue