Compare commits
8 commits
9a98ce5e43
...
845ee6ade3
Author | SHA1 | Date | |
---|---|---|---|
John Alanbrook | 845ee6ade3 | ||
John Alanbrook | fb88641883 | ||
John Alanbrook | 2f8827fd78 | ||
John Alanbrook | 805c9298e6 | ||
John Alanbrook | bb5e6b883a | ||
John Alanbrook | acb0fcdcd9 | ||
John Alanbrook | 9626da4ff8 | ||
John Alanbrook | d36ac1957f |
|
@ -1,6 +1,9 @@
|
||||||
# GUI
|
# GUI
|
||||||
Game GUIs are written by registering an entity's *gui* property to a function.
|
Game GUIs are written by registering an entity's `gui` property to a function, or its `hud` property.
|
||||||
|
|
||||||
The GUI system which ships with Prosperon is called *MUM*. MUM is a declarative, immediate mode interface system. Immediate to eliminate the issue of data synchronization in the game.
|
`gui` draws in window space, where the bottom left corner is `[0,0]`. `hud` draws in screen space. In either of these, you can call "render" functions directly.
|
||||||
|
|
||||||
All GUI objects derive from MUM. MUM has a list of properties, used for rendering. Mum also has functions which cause drawing to appear on the screen.
|
`draw` draws in world space, and mum functions can equally be used there.
|
||||||
|
|
||||||
|
## MUM
|
||||||
|
The GUI system which ships with Prosperon is called *MUM*. MUM is a declarative, immediate mode HUD system. While Imgui is designed to make it easy to make editor-like controls, mum is designed to be easy to make video game huds.
|
||||||
|
|
|
@ -1331,6 +1331,11 @@ Object.defineProperty(Number.prototype, 'lerp', {
|
||||||
return (to - this) * t + this;
|
return (to - this) * t + this;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Object.defineProperty(Number.prototype, 'clamp', {
|
||||||
|
value: function(from,to) {
|
||||||
|
return Math.clamp(this,from,to);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Math.clamp = function (x, l, h) { return x > h ? h : x < l ? l : x; }
|
Math.clamp = function (x, l, h) { return x > h ? h : x < l ? l : x; }
|
||||||
|
|
||||||
|
@ -1447,6 +1452,15 @@ bbox.pointin = function(bb, p)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bbox.zero = function(bb) {
|
||||||
|
var newbb = Object.assign({},bb);
|
||||||
|
newbb.r -= newbb.l;
|
||||||
|
newbb.t -= newbb.b;
|
||||||
|
newbb.b = 0;
|
||||||
|
newbb.l = 0;
|
||||||
|
return newbb;
|
||||||
|
}
|
||||||
|
|
||||||
bbox.move = function(bb, pos) {
|
bbox.move = function(bb, pos) {
|
||||||
var newbb = Object.assign({}, bb);
|
var newbb = Object.assign({}, bb);
|
||||||
newbb.t += pos.y;
|
newbb.t += pos.y;
|
||||||
|
@ -1456,6 +1470,11 @@ bbox.move = function(bb, pos) {
|
||||||
return newbb;
|
return newbb;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bbox.moveto = function(bb, pos) {
|
||||||
|
bb = bbox.zero(bb);
|
||||||
|
return bbox.move(bb, pos);
|
||||||
|
}
|
||||||
|
|
||||||
bbox.expand = function(oldbb, x) {
|
bbox.expand = function(oldbb, x) {
|
||||||
if (!oldbb || !x) return;
|
if (!oldbb || !x) return;
|
||||||
var bb = {};
|
var bb = {};
|
||||||
|
|
|
@ -13,8 +13,11 @@ var make_point_obj = function(o, p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var fullrect = [0,0,1,1];
|
||||||
|
|
||||||
var sprite = {
|
var sprite = {
|
||||||
loop: true,
|
loop: true,
|
||||||
|
rect: fullrect,
|
||||||
anim:{},
|
anim:{},
|
||||||
playing: 0,
|
playing: 0,
|
||||||
play(str = 0) {
|
play(str = 0) {
|
||||||
|
@ -63,7 +66,7 @@ var sprite = {
|
||||||
this.texture = game.texture(p);
|
this.texture = game.texture(p);
|
||||||
|
|
||||||
this.diffuse = this.texture;
|
this.diffuse = this.texture;
|
||||||
this.rect = [0,0,1,1];
|
this.rect = fullrect;
|
||||||
|
|
||||||
var anim = SpriteAnim.make(p);
|
var anim = SpriteAnim.make(p);
|
||||||
if (!anim) return;
|
if (!anim) return;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
var debug = {};
|
var debug = {};
|
||||||
|
|
||||||
|
debug.build = function(fn) { fn(); }
|
||||||
|
|
||||||
debug.fn_break = function(fn,obj = globalThis) {
|
debug.fn_break = function(fn,obj = globalThis) {
|
||||||
if (typeof fn !== 'function') return;
|
if (typeof fn !== 'function') return;
|
||||||
|
|
||||||
|
@ -50,10 +52,8 @@ debug.draw = function() {
|
||||||
|
|
||||||
function assert(op, str = `assertion failed [value '${op}']`)
|
function assert(op, str = `assertion failed [value '${op}']`)
|
||||||
{
|
{
|
||||||
if (!op) {
|
if (!op)
|
||||||
console.error(str);
|
console.panic(str);
|
||||||
os.quit();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var Gizmos = {
|
var Gizmos = {
|
||||||
|
@ -236,6 +236,13 @@ debug.log.time = function(fn, name, avg=0)
|
||||||
debug.log.time[name].push(profile.now()-start);
|
debug.log.time[name].push(profile.now()-start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug.kill = function()
|
||||||
|
{
|
||||||
|
assert = function() {};
|
||||||
|
debug.build = function() {};
|
||||||
|
debug.fn_break = function() {};
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
debug,
|
debug,
|
||||||
Gizmos,
|
Gizmos,
|
||||||
|
|
|
@ -128,8 +128,10 @@ profile.report = function (start, msg = "[undefined report]") {
|
||||||
};
|
};
|
||||||
|
|
||||||
profile.addreport = function (cache, line, start) {
|
profile.addreport = function (cache, line, start) {
|
||||||
|
cache ??= profcache;
|
||||||
cache[line] ??= [];
|
cache[line] ??= [];
|
||||||
cache[line].push(profile.now() - start);
|
cache[line].push(profile.now() - start);
|
||||||
|
return profile.now();
|
||||||
};
|
};
|
||||||
|
|
||||||
profile.printreport = function (cache, name) {
|
profile.printreport = function (cache, name) {
|
||||||
|
@ -324,6 +326,14 @@ game.engine_start = function (s) {
|
||||||
game.startengine = 0;
|
game.startengine = 0;
|
||||||
var frames = [];
|
var frames = [];
|
||||||
|
|
||||||
|
prosperon.release_mode = function()
|
||||||
|
{
|
||||||
|
prosperon.debug = false;
|
||||||
|
mum.debug = false;
|
||||||
|
debug.kill();
|
||||||
|
}
|
||||||
|
prosperon.debug = true;
|
||||||
|
|
||||||
function process() {
|
function process() {
|
||||||
var startframe = profile.now();
|
var startframe = profile.now();
|
||||||
var dt = profile.secs(profile.now()) - frame_t;
|
var dt = profile.secs(profile.now()) - frame_t;
|
||||||
|
@ -571,7 +581,9 @@ Register.add_cb("update", true).doc = "Called once per frame.";
|
||||||
Register.add_cb("physupdate", true);
|
Register.add_cb("physupdate", true);
|
||||||
Register.add_cb("gui", true);
|
Register.add_cb("gui", true);
|
||||||
Register.add_cb("hud", true);
|
Register.add_cb("hud", true);
|
||||||
Register.add_cb("debug", true);
|
Register.add_cb("draw_dbg", true);
|
||||||
|
Register.add_cb("gui_dbg", true);
|
||||||
|
Register.add_cb("hud_dbg", true);
|
||||||
Register.add_cb("draw", true);
|
Register.add_cb("draw", true);
|
||||||
|
|
||||||
var Event = {
|
var Event = {
|
||||||
|
|
|
@ -40,6 +40,8 @@ function keycode(name) { return charCodeAt(name); }
|
||||||
|
|
||||||
function keyname_extd(key)
|
function keyname_extd(key)
|
||||||
{
|
{
|
||||||
|
if (typeof key === 'string') return key;
|
||||||
|
|
||||||
if (key > 289 && key < 302) {
|
if (key > 289 && key < 302) {
|
||||||
var num = key-289;
|
var num = key-289;
|
||||||
return `f${num}`;
|
return `f${num}`;
|
||||||
|
@ -56,7 +58,7 @@ function keyname_extd(key)
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
prosperon.keys = [];
|
var downkeys = {};
|
||||||
|
|
||||||
function modstr()
|
function modstr()
|
||||||
{
|
{
|
||||||
|
@ -69,7 +71,7 @@ function modstr()
|
||||||
|
|
||||||
prosperon.keydown = function(key, repeat)
|
prosperon.keydown = function(key, repeat)
|
||||||
{
|
{
|
||||||
prosperon.keys[key] = true;
|
downkeys[key] = true;
|
||||||
|
|
||||||
if (key == 341 || key == 345)
|
if (key == 341 || key == 345)
|
||||||
mod.ctrl = 1;
|
mod.ctrl = 1;
|
||||||
|
@ -91,7 +93,8 @@ prosperon.keydown = function(key, repeat)
|
||||||
|
|
||||||
prosperon.keyup = function(key)
|
prosperon.keyup = function(key)
|
||||||
{
|
{
|
||||||
prosperon.keys[key] = false;
|
delete downkeys[key];
|
||||||
|
|
||||||
if (key == 341 || key == 345)
|
if (key == 341 || key == 345)
|
||||||
mod.ctrl = 0;
|
mod.ctrl = 0;
|
||||||
|
|
||||||
|
@ -127,9 +130,11 @@ prosperon.mousescroll = function(dx){
|
||||||
};
|
};
|
||||||
prosperon.mousedown = function(b){
|
prosperon.mousedown = function(b){
|
||||||
player[0].raw_input(modstr() + input.mouse.button[b], "pressed");
|
player[0].raw_input(modstr() + input.mouse.button[b], "pressed");
|
||||||
|
downkeys[input.mouse.button[b]] = true;
|
||||||
};
|
};
|
||||||
prosperon.mouseup = function(b){
|
prosperon.mouseup = function(b){
|
||||||
player[0].raw_input(input.mouse.button[b], "released");
|
player[0].raw_input(input.mouse.button[b], "released");
|
||||||
|
delete downkeys[input.mouse.button[b]];
|
||||||
};
|
};
|
||||||
|
|
||||||
input.mouse = {};
|
input.mouse = {};
|
||||||
|
@ -181,8 +186,8 @@ input.mouse.normal.doc = "Set the mouse to show again after hiding.";
|
||||||
|
|
||||||
input.keyboard = {};
|
input.keyboard = {};
|
||||||
input.keyboard.down = function(code) {
|
input.keyboard.down = function(code) {
|
||||||
if (typeof code === 'number') return prosperon.keys[code];
|
if (typeof code === 'number') return downkeys[code];
|
||||||
if (typeof code === 'string') return (prosperon.keys[code.uc().charCodeAt()] || prosperon.keys[code.lc().charCodeAt()]);
|
if (typeof code === 'string') return (downkeys[code.uc().charCodeAt()] || downkeys[code.lc().charCodeAt()]);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,11 +215,9 @@ input.print_pawn_kbm = function(pawn) {
|
||||||
|
|
||||||
input.procdown = function()
|
input.procdown = function()
|
||||||
{
|
{
|
||||||
for (var k of prosperon.keys) {
|
for (var k in downkeys)
|
||||||
if (!k) continue;
|
|
||||||
player[0].raw_input(keyname_extd(k), "down");
|
player[0].raw_input(keyname_extd(k), "down");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
input.print_md_kbm = function(pawn) {
|
input.print_md_kbm = function(pawn) {
|
||||||
if (!('inputs' in pawn)) return;
|
if (!('inputs' in pawn)) return;
|
||||||
|
@ -330,7 +333,10 @@ var Player = {
|
||||||
fn = pawn.inputs[cmd].released;
|
fn = pawn.inputs[cmd].released;
|
||||||
break;
|
break;
|
||||||
case 'down':
|
case 'down':
|
||||||
|
if (typeof pawn.inputs[cmd].down === 'function')
|
||||||
fn = pawn.inputs[cmd].down;
|
fn = pawn.inputs[cmd].down;
|
||||||
|
else if (pawn.inputs[cmd].down)
|
||||||
|
fn = pawn.inputs[cmd];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof fn === 'function') {
|
if (typeof fn === 'function') {
|
||||||
|
|
265
scripts/mum.js
265
scripts/mum.js
|
@ -1,107 +1,264 @@
|
||||||
globalThis.mum = {};
|
globalThis.mum = {};
|
||||||
|
|
||||||
var panel;
|
var panel;
|
||||||
|
|
||||||
|
var selected = undefined;
|
||||||
|
|
||||||
|
mum.inputs = {};
|
||||||
|
mum.inputs.lm = function()
|
||||||
|
{
|
||||||
|
if (!selected) return;
|
||||||
|
if (!selected.action) return;
|
||||||
|
selected.action();
|
||||||
|
}
|
||||||
|
|
||||||
mum.base = {
|
mum.base = {
|
||||||
padding:[0,0], /* Each element inset with this padding on all sides */
|
pos: null, // If set, puts the cursor to this position before drawing the element
|
||||||
offset:[0,0],
|
offset:[0,0], // Move x,y to the right and down before drawing
|
||||||
pos: [0,0],
|
padding:[0,0], // Pad inwards after drawing, to prepare for the next element
|
||||||
font: "fonts/c64.ttf",
|
font: "fonts/c64.ttf",
|
||||||
selectable: false,
|
selectable: false,
|
||||||
selected: false,
|
selected: false,
|
||||||
font_size: 16,
|
font_size: 16,
|
||||||
text_align: "left", /* left, center, right */
|
|
||||||
scale: 1,
|
scale: 1,
|
||||||
angle: 0,
|
angle: 0,
|
||||||
anchor: [0,1],
|
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,
|
background_image: null,
|
||||||
hovered: {},
|
slice: null,
|
||||||
|
hover: {
|
||||||
|
color: Color.red,
|
||||||
|
},
|
||||||
text_shadow: {
|
text_shadow: {
|
||||||
pos: [0,0],
|
pos: [0,0],
|
||||||
color: Color.white,
|
color: Color.white,
|
||||||
},
|
},
|
||||||
text_outline: 1, /* outline in pixels */
|
border: 0, // Draw a border around the element. For text, an outline.
|
||||||
|
overflow: "wrap", // how to deal with overflow from parent element
|
||||||
|
wrap: -1,
|
||||||
|
text_align: "left", /* left, center, right */
|
||||||
|
shader: null, // Use this shader, instead of the engine provided one
|
||||||
color: Color.white,
|
color: Color.white,
|
||||||
margin: [0,0], /* Distance between elements for things like columns */
|
opacity:1,
|
||||||
width: null,
|
width:0,
|
||||||
height: null,
|
height:0,
|
||||||
max_width: Infinity,
|
max_width: Infinity,
|
||||||
max_height: Infinity,
|
max_height: Infinity,
|
||||||
image_repeat: false,
|
image_repeat: false,
|
||||||
image_repeat_offset: [0,0],
|
image_repeat_offset: [0,0],
|
||||||
debug: false, /* set to true to draw debug boxes */
|
debug: false, /* set to true to draw debug boxes */
|
||||||
hide: false,
|
hide: false,
|
||||||
|
tooltip: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// data is passed into each function, and various stats are generated
|
||||||
|
// drawpos: the point to start the drawing from
|
||||||
|
// wh: an array of [width,height]
|
||||||
|
// bound: a boundingbox around the drawn UI element
|
||||||
|
// extent: a boundingbox around the total extents of the element (ie before padding)
|
||||||
|
|
||||||
|
function show_debug() { return prosperon.debug && mum.debug; }
|
||||||
|
|
||||||
|
mum.debug = false;
|
||||||
|
|
||||||
var post = function() {};
|
var post = function() {};
|
||||||
var posts = [];
|
var posts = [];
|
||||||
|
|
||||||
var context = mum.base;
|
mum.style = mum.base;
|
||||||
var contexts = [];
|
|
||||||
|
|
||||||
var cursor = [0,0];
|
var cursor = [0,0];
|
||||||
|
|
||||||
var end = function()
|
|
||||||
{
|
|
||||||
post();
|
|
||||||
context = contexts.pop();
|
|
||||||
if (!context) context = mum.base;
|
|
||||||
}
|
|
||||||
|
|
||||||
var listpost = function()
|
|
||||||
{
|
|
||||||
var height = 0;
|
|
||||||
if (context.height) height += context.height;
|
|
||||||
else height += (context.bb.t - context.bb.b);
|
|
||||||
cursor.y -= height;
|
|
||||||
cursor.y -= context.padding.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
var pre = function(data)
|
var pre = function(data)
|
||||||
{
|
{
|
||||||
if (data.hide || context.hide) return true;
|
if (data.hide) return true;
|
||||||
data.__proto__ = context;
|
data.__proto__ = mum.style;
|
||||||
contexts.push(context);
|
|
||||||
context = data;
|
if (data.pos) cursor = data.pos.slice();
|
||||||
|
data.drawpos = cursor.slice().add(data.offset);
|
||||||
|
|
||||||
|
if (data.opacity !== 1) {
|
||||||
|
data.color = data.color.slice();
|
||||||
|
data.color[3] = data.opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.wh = [data.width,data.height];
|
||||||
|
}
|
||||||
|
|
||||||
|
var anchor_calc = function(data)
|
||||||
|
{
|
||||||
|
var aa = [0,1].sub(data.anchor);
|
||||||
|
data.drawpos = data.drawpos.add([data.width,data.height]).scale(aa);
|
||||||
|
}
|
||||||
|
|
||||||
|
var end = function(data)
|
||||||
|
{
|
||||||
|
cursor = cursor.add(data.padding);
|
||||||
|
post(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
mum.list = function(fn, data = {})
|
mum.list = function(fn, data = {})
|
||||||
{
|
{
|
||||||
if (pre(data)) return;
|
if (pre(data)) return;
|
||||||
|
var aa = [0,1].sub(data.anchor);
|
||||||
|
cursor = cursor.add([data.width,data.height].scale(aa)).add(data.offset).add(data.padding);
|
||||||
|
|
||||||
cursor = context.pos;
|
|
||||||
cursor = cursor.add(context.offset);
|
|
||||||
posts.push(post);
|
posts.push(post);
|
||||||
post = listpost;
|
post = mum.list.post.bind(data);
|
||||||
|
|
||||||
|
if (show_debug())
|
||||||
|
render.boundingbox({
|
||||||
|
t:cursor.y,
|
||||||
|
b:cursor.y-data.height,
|
||||||
|
l:cursor.x,
|
||||||
|
r:cursor.x+data.width
|
||||||
|
});
|
||||||
|
|
||||||
|
//if (data.background_image) mum.image(null, Object.create(data))
|
||||||
|
if (data.background_image) {
|
||||||
|
var imgpos = data.pos.slice();
|
||||||
|
imgpos.y -= data.height/2;
|
||||||
|
imgpos.x -= data.width/2;
|
||||||
|
var imgscale = [data.width,data.height];
|
||||||
|
if (data.slice)
|
||||||
|
render.slice9(game.texture(data.background_image), imgpos, data.slice, imgscale);
|
||||||
|
else
|
||||||
|
render.image(game.texture(data.background_image), imgpos, [data.width,data.height]);
|
||||||
|
}
|
||||||
|
|
||||||
fn();
|
fn();
|
||||||
|
|
||||||
|
data.bb.l -= data.padding.x;
|
||||||
|
data.bb.r += data.padding.x;
|
||||||
|
data.bb.t += data.padding.y;
|
||||||
|
data.bb.b -= data.padding.y;
|
||||||
|
|
||||||
|
if (show_debug())
|
||||||
|
render.boundingbox(data.bb);
|
||||||
|
|
||||||
post = posts.pop();
|
post = posts.pop();
|
||||||
end();
|
end(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
mum.image = function(path, data = {})
|
mum.list.post = function(e)
|
||||||
{
|
{
|
||||||
if (pre(data)) return;
|
cursor.y -= (e.bb.t - e.bb.b);
|
||||||
|
cursor.y -= e.padding.y;
|
||||||
|
|
||||||
var tex = game.texture(path);
|
if (this.bb)
|
||||||
context.bb = render.image(tex, cursor, context.size);
|
this.bb = bbox.expand(this.bb,e.bb)
|
||||||
|
else
|
||||||
end();
|
this.bb = e.bb;
|
||||||
}
|
|
||||||
|
|
||||||
mum.button = function(str, data = {padding:[4,4]})
|
|
||||||
{
|
|
||||||
if (pre(data)) return;
|
|
||||||
var bb = render.text(str, cursor.add(context.padding), context.size, context.color);
|
|
||||||
render.rectangle([bb.l-context.padding.x, bb.b-context.padding.y], [bb.r+context.padding.y, bb.t+context.padding.y], Color.black);
|
|
||||||
context.bb = bb;
|
|
||||||
end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mum.label = function(str, data = {})
|
mum.label = function(str, data = {})
|
||||||
{
|
{
|
||||||
if (pre(data)) return;
|
if (pre(data)) return;
|
||||||
render.set_font(data.font, data.font_size);
|
|
||||||
context.bb = render.text(str, cursor, context.size, context.color);
|
|
||||||
|
|
||||||
end();
|
render.set_font(data.font, data.font_size);
|
||||||
|
|
||||||
|
data.bb = render.text_bb(str, data.scale, -1, cursor);
|
||||||
|
data.wh = bbox.towh(data.bb);
|
||||||
|
|
||||||
|
var aa = [0,1].sub(data.anchor);
|
||||||
|
|
||||||
|
data.drawpos.y -= (data.bb.t-cursor.y);
|
||||||
|
data.drawpos = data.drawpos.add(data.wh.scale(aa)).add(data.offset);
|
||||||
|
|
||||||
|
data.bb = render.text_bb(str, data.scale, data.wrap, data.drawpos);
|
||||||
|
|
||||||
|
if (data.action && bbox.pointin(data.bb, input.mouse.screenpos())) {
|
||||||
|
if (data.hover) {
|
||||||
|
data.hover.__proto__ = data;
|
||||||
|
data = data.hover;
|
||||||
|
selected = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data.bb = render.text(str, data.drawpos, data.scale, data.color, data.wrap);
|
||||||
|
|
||||||
|
if (show_debug())
|
||||||
|
render.boundingbox(data.bb);
|
||||||
|
|
||||||
|
end(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
mum.image = function(path, data = {})
|
||||||
|
{
|
||||||
|
if (pre(data)) return;
|
||||||
|
path ??= data.background_image;
|
||||||
|
var tex = path;
|
||||||
|
if (typeof path === 'string')
|
||||||
|
tex = game.texture(path);
|
||||||
|
|
||||||
|
data.width ??= tex.width;
|
||||||
|
data.height ??= tex.height;
|
||||||
|
|
||||||
|
var aa = [0,0].sub(data.anchor);
|
||||||
|
data.drawpos = data.drawpos.add(aa.scale([data.width,data.height]));
|
||||||
|
|
||||||
|
if (data.slice)
|
||||||
|
render.slice9(tex, data.drawpos, data.slice, [data.width,data.height]);
|
||||||
|
else {
|
||||||
|
cursor.y -= tex.height*data.scale;
|
||||||
|
data.bb = render.image(tex, data.drawpos, [data.scale*tex.width, data.scale*tex.height]);
|
||||||
|
}
|
||||||
|
|
||||||
|
end(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
mum.rectangle = function(data = {})
|
||||||
|
{
|
||||||
|
if (pre(data)) return;
|
||||||
|
var aa = [0,0].sub(data.anchor);
|
||||||
|
data.drawpos = data.drawpos.add(aa.scale([data.width,data.height]));
|
||||||
|
|
||||||
|
render.rectangle(data.drawpos, data.drawpos.add([data.width,data.height]), data.color);
|
||||||
|
|
||||||
|
end(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
var btnbb;
|
||||||
|
var btnpost = function()
|
||||||
|
{
|
||||||
|
btnbb = data.bb;
|
||||||
|
}
|
||||||
|
|
||||||
|
mum.button = function(str, data = {padding:[4,4], color:Color.black})
|
||||||
|
{
|
||||||
|
if (pre(data)) return;
|
||||||
|
posts.push(post);
|
||||||
|
post = btnpost;
|
||||||
|
if (typeof str === 'string')
|
||||||
|
render.text(str, cursor.add(data.padding), data.scale, data.color);
|
||||||
|
else
|
||||||
|
str();
|
||||||
|
|
||||||
|
if (data.action && data.hover && bbox.pointin(btnbb, input.mouse.screenpos())) {
|
||||||
|
data.hover.__proto__ = data;
|
||||||
|
data = data.hover;
|
||||||
|
}
|
||||||
|
render.rectangle([btnbb.l-data.padding.x, btnbb.b-data.padding.y], [btnbb.r+data.padding.y, btnbb.t+data.padding.y], data.color);
|
||||||
|
data.bb = btnbb;
|
||||||
|
|
||||||
|
post = posts.pop();
|
||||||
|
end(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
mum.window = function(fn, data = {})
|
||||||
|
{
|
||||||
|
if (pre(data)) return;
|
||||||
|
|
||||||
|
render.rectangle(cursor, cursor.add(data.size), data.color);
|
||||||
|
cursor.y += data.height;
|
||||||
|
cursor = cursor.add(data.padding);
|
||||||
|
fn();
|
||||||
|
end(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
mum.ex_hud = function()
|
||||||
|
{
|
||||||
|
mum.label("TOP LEFT", {pos:[0,game.size.y], anchor:[0,1]});
|
||||||
|
mum.label("BOTTOM LEFT", {pos:[0,0], anchor:[0,0]});
|
||||||
|
mum.label("TOP RIGHT", {pos:game.size, anchor:[1,1]});
|
||||||
|
mum.label("BOTTOM RIGHT", {pos:[game.size.x, 0], anchor:[1,0]});
|
||||||
}
|
}
|
|
@ -4,6 +4,44 @@ render.doc = {
|
||||||
wireframe: "Show only wireframes of models."
|
wireframe: "Show only wireframes of models."
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var cur = {};
|
||||||
|
|
||||||
|
render.use_shader = function(shader)
|
||||||
|
{
|
||||||
|
if (cur.shader === shader) return;
|
||||||
|
cur.shader = shader;
|
||||||
|
cur.globals = {};
|
||||||
|
cur.bind = undefined;
|
||||||
|
cur.mesh = undefined;
|
||||||
|
render.setpipeline(shader.pipe);
|
||||||
|
}
|
||||||
|
|
||||||
|
render.use_mat = function(mat)
|
||||||
|
{
|
||||||
|
if (!cur.shader) return;
|
||||||
|
if (cur.mat === mat) return;
|
||||||
|
|
||||||
|
render.shader_apply_material(cur.shader, mat, cur.mat);
|
||||||
|
|
||||||
|
cur.mat = mat;
|
||||||
|
|
||||||
|
cur.images = [];
|
||||||
|
if (!cur.shader.fs.images) return;
|
||||||
|
for (var img of cur.shader.fs.images)
|
||||||
|
if (mat[img.name])
|
||||||
|
cur.images.push(mat[img.name]);
|
||||||
|
else
|
||||||
|
cur.images.push(game.texture("icons/no_tex.gif"));
|
||||||
|
}
|
||||||
|
|
||||||
|
var models_array = [];
|
||||||
|
|
||||||
|
render.set_model = function(t)
|
||||||
|
{
|
||||||
|
if (cur.shader.vs.unimap.model)
|
||||||
|
render.setunim4(0, cur.shader.vs.unimap.model.slot, t);
|
||||||
|
}
|
||||||
|
|
||||||
var shaderlang = {
|
var shaderlang = {
|
||||||
macos: "metal_macos",
|
macos: "metal_macos",
|
||||||
windows: "hlsl5",
|
windows: "hlsl5",
|
||||||
|
@ -93,24 +131,38 @@ function shader_directive(shader, name, map)
|
||||||
|
|
||||||
function global_uni(uni, stage)
|
function global_uni(uni, stage)
|
||||||
{
|
{
|
||||||
|
cur.globals[stage] ??= {};
|
||||||
|
if (cur.globals[stage][uni.name]) return true;
|
||||||
switch(uni.name) {
|
switch(uni.name) {
|
||||||
case "time":
|
case "time":
|
||||||
|
cur.globals[stage][uni.name]
|
||||||
render.setuniv(stage, uni.slot, profile.secs(profile.now()));
|
render.setuniv(stage, uni.slot, profile.secs(profile.now()));
|
||||||
|
cur.globals[stage][uni.name] = true;
|
||||||
return true;
|
return true;
|
||||||
case "projection":
|
case "projection":
|
||||||
render.setuniproj(stage, uni.slot);
|
render.setuniproj(stage, uni.slot);
|
||||||
|
cur.globals[stage][uni.name] = true;
|
||||||
return true;
|
return true;
|
||||||
case "view":
|
case "view":
|
||||||
render.setuniview(stage, uni.slot);
|
render.setuniview(stage, uni.slot);
|
||||||
|
cur.globals[stage][uni.name] = true;
|
||||||
return true;
|
return true;
|
||||||
case "vp":
|
case "vp":
|
||||||
render.setunivp(stage, uni.slot);
|
render.setunivp(stage, uni.slot);
|
||||||
|
cur.globals[stage][uni.name] = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var setcam = render.set_camera;
|
||||||
|
render.set_camera = function(cam)
|
||||||
|
{
|
||||||
|
delete cur.shader;
|
||||||
|
setcam(cam);
|
||||||
|
}
|
||||||
|
|
||||||
render.make_shader = function(shader)
|
render.make_shader = function(shader)
|
||||||
{
|
{
|
||||||
var file = shader;
|
var file = shader;
|
||||||
|
@ -260,22 +312,26 @@ var shader_unisize = {
|
||||||
16: render.setuniv4
|
16: render.setuniv4
|
||||||
};
|
};
|
||||||
|
|
||||||
render.shader_apply_material = function(shader, material = {})
|
render.shader_apply_material = function(shader, material = {}, old = {})
|
||||||
{
|
{
|
||||||
for (var p in shader.vs.unimap) {
|
for (var p in shader.vs.unimap) {
|
||||||
if (global_uni(shader.vs.unimap[p], 0)) continue;
|
if (global_uni(shader.vs.unimap[p], 0)) continue;
|
||||||
if (!(p in material)) continue;
|
if (material[p] === old[p]) continue;
|
||||||
|
assert(p in material, `shader ${shader.name} has no uniform for ${p}`);
|
||||||
var s = shader.vs.unimap[p];
|
var s = shader.vs.unimap[p];
|
||||||
shader_unisize[s.size](0, s.slot, material[p]);
|
shader_unisize[s.size](0, s.slot, material[p]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var p in shader.fs.unimap) {
|
for (var p in shader.fs.unimap) {
|
||||||
if (global_uni(shader.fs.unimap[p], 1)) continue;
|
if (global_uni(shader.fs.unimap[p], 1)) continue;
|
||||||
if (!(p in material)) continue;
|
if (material[p] === old[p]) continue;
|
||||||
|
assert(p in material, `shader ${shader.name} has no uniform for ${p}`);
|
||||||
var s = shader.fs.unimap[p];
|
var s = shader.fs.unimap[p];
|
||||||
shader_unisize[s.size](1, s.slot, material[p]);
|
shader_unisize[s.size](1, s.slot, material[p]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!material.diffuse) return;
|
if (!material.diffuse) return;
|
||||||
|
if (material.diffuse === old.diffuse) return;
|
||||||
|
|
||||||
if ("diffuse_size" in shader.fs.unimap)
|
if ("diffuse_size" in shader.fs.unimap)
|
||||||
render.setuniv2(1, shader.fs.unimap.diffuse_size.slot, [material.diffuse.width, material.diffuse.height]);
|
render.setuniv2(1, shader.fs.unimap.diffuse_size.slot, [material.diffuse.width, material.diffuse.height]);
|
||||||
|
@ -284,41 +340,49 @@ render.shader_apply_material = function(shader, material = {})
|
||||||
render.setuniv2(0, shader.vs.unimap.diffuse_size.slot, [material.diffuse.width, material.diffuse.height]);
|
render.setuniv2(0, shader.vs.unimap.diffuse_size.slot, [material.diffuse.width, material.diffuse.height]);
|
||||||
}
|
}
|
||||||
|
|
||||||
render.sg_bind = function(shader, mesh = {}, material = {}, ssbo)
|
render.sg_bind = function(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 = {};
|
var bind = {};
|
||||||
bind.attrib = [];
|
bind.attrib = [];
|
||||||
if (shader.vs.inputs)
|
if (cur.shader.vs.inputs)
|
||||||
for (var a of shader.vs.inputs) {
|
for (var a of cur.shader.vs.inputs) {
|
||||||
if (!(a.name in mesh)) {
|
if (!(a.name in mesh)) {
|
||||||
if (!(a.name.slice(2) in mesh)) {
|
if (!(a.name.slice(2) in mesh)) {
|
||||||
console.error(`cannot draw shader ${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.`);
|
||||||
return undefined;
|
return undefined;
|
||||||
} else
|
} else
|
||||||
bind.attrib.push(mesh[a.name.slice(2)]);
|
bind.attrib.push(mesh[a.name.slice(2)]);
|
||||||
} else
|
} else
|
||||||
bind.attrib.push(mesh[a.name]);
|
bind.attrib.push(mesh[a.name]);
|
||||||
}
|
}
|
||||||
bind.images = [];
|
|
||||||
if (shader.fs.images)
|
|
||||||
for (var img of shader.fs.images) {
|
|
||||||
if (material[img.name])
|
|
||||||
bind.images.push(material[img.name]);
|
|
||||||
else
|
|
||||||
bind.images.push(game.texture("icons/no_tex.gif"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shader.indexed) {
|
if (cur.shader.indexed) {
|
||||||
bind.index = mesh.index;
|
bind.index = mesh.index;
|
||||||
bind.count = mesh.count;
|
bind.count = mesh.count;
|
||||||
} else
|
} else
|
||||||
bind.count = mesh.verts;
|
bind.count = mesh.verts;
|
||||||
|
|
||||||
bind.ssbo = [];
|
bind.ssbo = [];
|
||||||
if (shader.vs.storage_buffers)
|
if (cur.shader.vs.storage_buffers)
|
||||||
for (var b of shader.vs.storage_buffers)
|
for (var b of cur.shader.vs.storage_buffers)
|
||||||
bind.ssbo.push(ssbo);
|
bind.ssbo.push(ssbo);
|
||||||
|
|
||||||
|
bind.inst = 1;
|
||||||
|
bind.images = cur.images;
|
||||||
|
|
||||||
|
cur.bind = bind;
|
||||||
|
|
||||||
|
render.setbind(cur.bind);
|
||||||
|
|
||||||
return bind;
|
return bind;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,35 +473,29 @@ render.circle = function(pos, radius, color) {
|
||||||
coord: pos,
|
coord: pos,
|
||||||
shade: color
|
shade: color
|
||||||
};
|
};
|
||||||
render.setpipeline(circleshader.pipe);
|
render.use_shader(circleshader);
|
||||||
render.shader_apply_material(circleshader, mat);
|
render.use_mat(mat);
|
||||||
var bind = render.sg_bind(circleshader, shape.quad, mat);
|
render.draw(shape.quad);
|
||||||
bind.inst = 1;
|
|
||||||
render.spdraw(bind);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render.poly = function(points, color, transform) {
|
render.poly = function(points, color, transform) {
|
||||||
var buffer = render.poly_prim(points);
|
var buffer = render.poly_prim(points);
|
||||||
var mat = { shade: color};
|
var mat = { shade: color};
|
||||||
render.setpipeline(polyshader.pipe);
|
render.use_shader(polyshader);
|
||||||
render.setunim4(0,polyshader.vs.unimap.model.slot, transform);
|
render.set_model(transform);
|
||||||
render.shader_apply_material(polyshader, mat);
|
render.use_mat(mat);
|
||||||
var bind = render.sg_bind(polyshader, buffer, mat);
|
render.draw(buffer);
|
||||||
bind.inst = 1;
|
|
||||||
render.spdraw(bind);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render.line = function(points, color = Color.white, thickness = 1, transform) {
|
render.line = function(points, color = Color.white, thickness = 1, transform) {
|
||||||
var buffer = os.make_line_prim(points, thickness, 0, false);
|
var buffer = os.make_line_prim(points, thickness, 0, false);
|
||||||
render.setpipeline(polyshader.pipe);
|
render.use_shader(polyshader);
|
||||||
var mat = {
|
var mat = {
|
||||||
shade: color
|
shade: color
|
||||||
};
|
};
|
||||||
render.shader_apply_material(polyshader, mat);
|
render.use_mat(mat);
|
||||||
render.setunim4(0,polyshader.vs.unimap.model.slot, transform);
|
render.set_model(transform);
|
||||||
var bind = render.sg_bind(polyshader, buffer, mat);
|
render.draw(buffer);
|
||||||
bind.inst = 1;
|
|
||||||
render.spdraw(bind);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* All draw in screen space */
|
/* All draw in screen space */
|
||||||
|
@ -479,7 +537,7 @@ render.coordinate = function(pos, size, color) {
|
||||||
}
|
}
|
||||||
|
|
||||||
render.boundingbox = function(bb, color = Color.white) {
|
render.boundingbox = function(bb, color = Color.white) {
|
||||||
render.poly(bbox.topoints(bb), color);
|
render.line(bbox.topoints(bb).wrapped(1), color);
|
||||||
}
|
}
|
||||||
|
|
||||||
render.rectangle = function(lowerleft, upperright, color) {
|
render.rectangle = function(lowerleft, upperright, color) {
|
||||||
|
@ -499,19 +557,22 @@ render.window = function(pos, wh, color) {
|
||||||
render.box(p,wh,color);
|
render.box(p,wh,color);
|
||||||
};
|
};
|
||||||
|
|
||||||
render.text = function(str, pos, size = 1, color = Color.white, wrap = -1, anchor = [0,1], cursor = -1) {
|
render.text_bb = function(str, size = 1, wrap = -1, pos = [0,0])
|
||||||
|
{
|
||||||
var bb = render.text_size(str,size,wrap);
|
var bb = render.text_size(str,size,wrap);
|
||||||
var w = (bb.r - bb.l);
|
var w = (bb.r - bb.l);
|
||||||
var h = (bb.t - bb.b);
|
var h = (bb.t - bb.b);
|
||||||
|
|
||||||
//render.text draws with an anchor on top left corner
|
|
||||||
var p = pos.slice();
|
|
||||||
bb.r += pos.x;
|
bb.r += pos.x;
|
||||||
bb.l += pos.x;
|
bb.l += pos.x;
|
||||||
bb.t += pos.y;
|
bb.t += pos.y;
|
||||||
bb.b += pos.y;
|
bb.b += pos.y;
|
||||||
gui.text(str, p, size, color, wrap, cursor);
|
return bb;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
return bb;
|
return bb;
|
||||||
|
|
||||||
p.x -= w * anchor.x;
|
p.x -= w * anchor.x;
|
||||||
|
@ -524,19 +585,19 @@ render.text = function(str, pos, size = 1, color = Color.white, wrap = -1, ancho
|
||||||
return bb;
|
return bb;
|
||||||
};
|
};
|
||||||
|
|
||||||
render.image = function(tex, pos, scale = 1, rotation = 0, color = Color.white, dimensions = [tex.width, tex.height]) {
|
render.image = function(tex, pos, scale = [tex.width, tex.height], rotation = 0, color = Color.white) {
|
||||||
var t = os.make_transform();
|
var t = os.make_transform();
|
||||||
t.pos = pos;
|
t.pos = pos;
|
||||||
t.scale = [scale,scale,scale];
|
t.scale = [scale.x/tex.width,scale.y/tex.height,1];
|
||||||
render.setpipeline(render.spriteshader.pipe);
|
render.use_shader(render.spriteshader);
|
||||||
render.setunim4(0, render.spriteshader.vs.unimap.model.slot, t);
|
render.set_model(t);
|
||||||
render.shader_apply_material(render.spriteshader, {
|
render.use_mat({
|
||||||
shade: color,
|
shade: color,
|
||||||
diffuse: tex
|
diffuse: tex,
|
||||||
|
rect:[0,0,1,1]
|
||||||
});
|
});
|
||||||
var bind = render.sg_bind(render.spriteshader, shape.quad, {diffuse:tex});
|
|
||||||
bind.inst = 1;
|
render.draw(shape.quad);
|
||||||
render.spdraw(bind);
|
|
||||||
|
|
||||||
var bb = {};
|
var bb = {};
|
||||||
bb.b = pos.y;
|
bb.b = pos.y;
|
||||||
|
@ -546,19 +607,30 @@ render.image = function(tex, pos, scale = 1, rotation = 0, color = Color.white,
|
||||||
return bb;
|
return bb;
|
||||||
}
|
}
|
||||||
|
|
||||||
render.slice9 = function(tex, pos, bb, scale = 1, color = Color.white)
|
|
||||||
|
// pos is the lower left corner, scale is the width and height
|
||||||
|
render.slice9 = function(tex, pos, bb, scale = [tex.width,tex.height], color = Color.white)
|
||||||
{
|
{
|
||||||
var t = os.make_transform();
|
var t = os.make_transform();
|
||||||
t.pos = pos;
|
t.pos = pos;
|
||||||
t.scale = [scale,scale,scale];
|
t.scale = [scale.x/tex.width,scale.y/tex.height,1];
|
||||||
render.setpipeline(render.slice9.pipe);
|
var border;
|
||||||
render.setunim4(0, render.slice9.vs.unimap.model.slot, t);
|
if (typeof bb === 'number')
|
||||||
render.shader_apply_material(render.slice9, {
|
border = [bb/tex.width,bb/tex.height,bb/tex.width,bb/tex.height];
|
||||||
shade: color
|
else
|
||||||
|
border = [bb.l/tex.width, bb.b/tex.height, bb.r/tex.width, bb.t/tex.height];
|
||||||
|
|
||||||
|
render.use_shader(slice9shader);
|
||||||
|
render.set_model(t);
|
||||||
|
render.use_mat({
|
||||||
|
shade: color,
|
||||||
|
diffuse:tex,
|
||||||
|
rect:[0,0,1,1],
|
||||||
|
border: border,
|
||||||
|
scale: [scale.x/tex.width,scale.y/tex.height]
|
||||||
});
|
});
|
||||||
var bind = render.sg_bind(render.slice9, shape.quad, {diffuse:tex});
|
|
||||||
bind.inst = 1;
|
render.draw(shape.quad);
|
||||||
render.spdraw(bind);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var textssbo = render.text_ssbo();
|
var textssbo = render.text_ssbo();
|
||||||
|
@ -566,11 +638,10 @@ var textssbo = render.text_ssbo();
|
||||||
render.flush_text = function()
|
render.flush_text = function()
|
||||||
{
|
{
|
||||||
if (!render.textshader) return;
|
if (!render.textshader) return;
|
||||||
render.setpipeline(render.textshader.pipe);
|
render.use_shader(render.textshader);
|
||||||
render.shader_apply_material(render.textshader);
|
render.use_mat({text:render.font.texture});
|
||||||
var textbind = render.sg_bind(render.textshader, shape.quad, {text:render.font.texture}, textssbo);
|
|
||||||
textbind.inst = render.flushtext();
|
render.draw(shape.quad, textssbo, render.flushtext());
|
||||||
render.spdraw(textbind);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render.fontcache = {};
|
render.fontcache = {};
|
||||||
|
@ -591,5 +662,10 @@ 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.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.rectangle.doc = "Draw a rectangle, with its corners at lowerleft and upperright.";
|
||||||
|
|
||||||
|
render.draw = function(mesh, ssbo, inst = 1)
|
||||||
|
{
|
||||||
|
render.sg_bind(mesh, ssbo);
|
||||||
|
render.spdraw(cur.bind.count, inst);
|
||||||
|
}
|
||||||
|
|
||||||
return {render};
|
return {render};
|
||||||
|
|
|
@ -14,6 +14,7 @@ if (os.sys() === 'macos') {
|
||||||
appy.inputs['S-g'] = os.gc;
|
appy.inputs['S-g'] = os.gc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
appy.inputs.f12 = function() { mum.debug = !mum.debug; }
|
||||||
appy.inputs.f11 = window.toggle_fullscreen;
|
appy.inputs.f11 = window.toggle_fullscreen;
|
||||||
appy.inputs['M-f4'] = prosperon.quit;
|
appy.inputs['M-f4'] = prosperon.quit;
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,10 @@ void vert()
|
||||||
|
|
||||||
@block frag
|
@block frag
|
||||||
uniform vec4 border;
|
uniform vec4 border;
|
||||||
// borders in pixels, x = left, y = bottom, z = right, w = top
|
uniform vec2 scale;
|
||||||
#define B vec4(10., 20., 30., 20.)
|
uniform vec4 shade;
|
||||||
|
|
||||||
|
// border given as [left,down,right,top], in scaled coordinates
|
||||||
|
|
||||||
vec2 uv9slice(vec2 uv, vec2 s, vec4 b)
|
vec2 uv9slice(vec2 uv, vec2 s, vec4 b)
|
||||||
{
|
{
|
||||||
|
@ -21,20 +23,9 @@ vec2 uv9slice(vec2 uv, vec2 s, vec4 b)
|
||||||
|
|
||||||
void frag()
|
void frag()
|
||||||
{
|
{
|
||||||
vec2 uv = fragCoord/iResolution.xy;
|
vec2 ruv = uv9slice(uv, scale, border);
|
||||||
vec2 ts = vec2(textureSize(iChannel0, 0));
|
color = texture(sampler2D(diffuse,smp), ruv);
|
||||||
// scaling factor
|
if (color.a < 0.1) discard;
|
||||||
// probably available as uniform irl
|
|
||||||
vec2 s = iResolution.xy / ts;
|
|
||||||
|
|
||||||
// border by texture size, shouldn't be > .5
|
|
||||||
// probably available as uniform irl
|
|
||||||
vec4 b = min(B / ts.xyxy, vec4(.499));
|
|
||||||
uv = uv9slice(uv, s, b);
|
|
||||||
|
|
||||||
vec3 col = vec3(texture(iChannel0, uv).x);
|
|
||||||
|
|
||||||
fragColor = vec4(col,1.0);
|
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
#blend mix
|
||||||
#depth off
|
#depth off
|
||||||
#primitive triangle
|
#primitive triangle
|
||||||
#cull none
|
#cull none
|
||||||
#blend mix
|
|
||||||
|
|
||||||
@vs vs
|
@vs vs
|
||||||
in vec3 a_pos;
|
in vec3 a_pos;
|
||||||
|
|
|
@ -655,9 +655,8 @@ sg_bindings js2bind(JSValue v)
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValue ssbo = js_getpropstr(v, "ssbo");
|
JSValue ssbo = js_getpropstr(v, "ssbo");
|
||||||
for (int i = 0; i < js_arrlen(ssbo); i++) {
|
for (int i = 0; i < js_arrlen(ssbo); i++)
|
||||||
bind.vs.storage_buffers[i] = *js2sg_buffer(js_getpropidx(ssbo,i));
|
bind.vs.storage_buffers[i] = *js2sg_buffer(js_getpropidx(ssbo,i));
|
||||||
}
|
|
||||||
|
|
||||||
return bind;
|
return bind;
|
||||||
}
|
}
|
||||||
|
@ -948,12 +947,33 @@ JSC_CCALL(render_setunim4,
|
||||||
sg_apply_uniforms(js2number(argv[0]), js2number(argv[1]), SG_RANGE_REF(m.e));
|
sg_apply_uniforms(js2number(argv[0]), js2number(argv[1]), SG_RANGE_REF(m.e));
|
||||||
);
|
);
|
||||||
|
|
||||||
JSC_CCALL(render_spdraw,
|
JSC_CCALL(render_setbind,
|
||||||
sg_bindings bind = js2bind(argv[0]);
|
sg_bindings bind = js2bind(argv[0]);
|
||||||
sg_apply_bindings(&bind);
|
sg_apply_bindings(&bind);
|
||||||
int p = js2number(js_getpropstr(argv[0], "count"));
|
)
|
||||||
int n = js2number(js_getpropstr(argv[0], "inst"));
|
|
||||||
sg_draw(0,p,n);
|
JSC_CCALL(render_make_t_ssbo,
|
||||||
|
JSValue array = argv[0];
|
||||||
|
HMM_Mat4 ms[js_arrlen(array)];
|
||||||
|
for (int i = 0; i < js_arrlen(array); i++)
|
||||||
|
ms[i] = transform2mat(*js2transform(js_getpropidx(array, i)));
|
||||||
|
|
||||||
|
sg_buffer *rr = malloc(sizeof(sg_buffer));
|
||||||
|
*rr = sg_make_buffer(&(sg_buffer_desc){
|
||||||
|
.data = {
|
||||||
|
.ptr = ms,
|
||||||
|
.size = sizeof(HMM_Mat4)*js_arrlen(array),
|
||||||
|
},
|
||||||
|
.type = SG_BUFFERTYPE_STORAGEBUFFER,
|
||||||
|
.usage = SG_USAGE_IMMUTABLE,
|
||||||
|
.label = "transform buffer"
|
||||||
|
});
|
||||||
|
|
||||||
|
return sg_buffer2js(rr);
|
||||||
|
)
|
||||||
|
|
||||||
|
JSC_CCALL(render_spdraw,
|
||||||
|
sg_draw(0,js2number(argv[0]),js2number(argv[1]));
|
||||||
)
|
)
|
||||||
|
|
||||||
JSC_CCALL(render_setpipeline,
|
JSC_CCALL(render_setpipeline,
|
||||||
|
@ -988,7 +1008,8 @@ static const JSCFunctionListEntry js_render_funcs[] = {
|
||||||
MIST_FUNC_DEF(render, pipeline, 1),
|
MIST_FUNC_DEF(render, pipeline, 1),
|
||||||
MIST_FUNC_DEF(render, setuniv3, 2),
|
MIST_FUNC_DEF(render, setuniv3, 2),
|
||||||
MIST_FUNC_DEF(render, setuniv, 2),
|
MIST_FUNC_DEF(render, setuniv, 2),
|
||||||
MIST_FUNC_DEF(render, spdraw, 1),
|
MIST_FUNC_DEF(render, spdraw, 2),
|
||||||
|
MIST_FUNC_DEF(render, setbind, 1),
|
||||||
MIST_FUNC_DEF(render, setuniproj, 2),
|
MIST_FUNC_DEF(render, setuniproj, 2),
|
||||||
MIST_FUNC_DEF(render, setuniview, 2),
|
MIST_FUNC_DEF(render, setuniview, 2),
|
||||||
MIST_FUNC_DEF(render, setunivp, 2),
|
MIST_FUNC_DEF(render, setunivp, 2),
|
||||||
|
@ -1001,6 +1022,7 @@ static const JSCFunctionListEntry js_render_funcs[] = {
|
||||||
MIST_FUNC_DEF(render, gfx_gui, 0),
|
MIST_FUNC_DEF(render, gfx_gui, 0),
|
||||||
MIST_FUNC_DEF(render, imgui_end, 0),
|
MIST_FUNC_DEF(render, imgui_end, 0),
|
||||||
MIST_FUNC_DEF(render, imgui_init, 0),
|
MIST_FUNC_DEF(render, imgui_init, 0),
|
||||||
|
MIST_FUNC_DEF(render, make_t_ssbo, 1)
|
||||||
};
|
};
|
||||||
|
|
||||||
JSC_CCALL(gui_scissor, sg_apply_scissor_rect(js2number(argv[0]), js2number(argv[1]), js2number(argv[2]), js2number(argv[3]), 0))
|
JSC_CCALL(gui_scissor, sg_apply_scissor_rect(js2number(argv[0]), js2number(argv[1]), js2number(argv[2]), js2number(argv[3]), 0))
|
||||||
|
|
|
@ -58,9 +58,9 @@ void mesh_add_material(primitive *prim, cgltf_material *mat)
|
||||||
cgltf_buffer_view *buf = img->buffer_view;
|
cgltf_buffer_view *buf = img->buffer_view;
|
||||||
pmat->diffuse = texture_fromdata(buf->buffer->data, buf->size);
|
pmat->diffuse = texture_fromdata(buf->buffer->data, buf->size);
|
||||||
} else {
|
} else {
|
||||||
char *path = makepath(dirname(cpath), img->uri);
|
// char *path = makepath(dirname(cpath), img->uri);
|
||||||
pmat->diffuse = texture_from_file(path);
|
// pmat->diffuse = texture_from_file(path);
|
||||||
free(path);
|
// free(path);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
pmat->diffuse = texture_from_file("icons/moon.gif");
|
pmat->diffuse = texture_from_file("icons/moon.gif");
|
||||||
|
|
|
@ -126,17 +126,6 @@ char *dirname(const char *path)
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *makepath(char *dir, char *file)
|
|
||||||
{
|
|
||||||
int d = strlen(dir) + strlen(file) + 2;
|
|
||||||
char *path = malloc(d);
|
|
||||||
path[0] = 0;
|
|
||||||
strncat(path, dir, d);
|
|
||||||
strncat(path, "/", d);
|
|
||||||
strncat(path, file, d);
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *seprint(char *fmt, ...)
|
char *seprint(char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
|
@ -12,7 +12,6 @@ extern int LOADED_GAME;
|
||||||
void resources_init();
|
void resources_init();
|
||||||
char *get_filename_from_path(char *path, int extension);
|
char *get_filename_from_path(char *path, int extension);
|
||||||
char *dirname(const char *path);
|
char *dirname(const char *path);
|
||||||
char *makepath(char *dir, char *file);
|
|
||||||
char *str_replace_ext(const char *s, const char *newext);
|
char *str_replace_ext(const char *s, const char *newext);
|
||||||
FILE *res_open(char *path, const char *tag);
|
FILE *res_open(char *path, const char *tag);
|
||||||
char **ls(const char *path);
|
char **ls(const char *path);
|
||||||
|
|
Loading…
Reference in a new issue