Compare commits
5 commits
0052a89c41
...
97e258ae7c
Author | SHA1 | Date | |
---|---|---|---|
John Alanbrook | 97e258ae7c | ||
John Alanbrook | 79e4772f93 | ||
John Alanbrook | e86e126894 | ||
John Alanbrook | 41eadce13e | ||
John Alanbrook | 71fda604ee |
2
Makefile
2
Makefile
|
@ -66,7 +66,7 @@ else ifeq ($(OPT), 1)
|
|||
CPPFLAGS += -O3 -flto
|
||||
INFO :=$(INFO)_opt
|
||||
else
|
||||
CPPFLAGS += -O0
|
||||
CPPFLAGS += -O2
|
||||
endif
|
||||
|
||||
CPPFLAGS += -DHAVE_CEIL -DCP_USE_CGTYPES=0 -DCP_USE_DOUBLES=0 -DHAVE_FLOOR -DHAVE_FMOD -DHAVE_LRINT -DHAVE_LRINTF $(includeflag) -MD $(WARNING_FLAGS) -I. -DVER=\"$(SEM)\" -DCOM=\"$(COM)\" -DINFO=\"$(INFO)\" #-DENABLE_SINC_MEDIUM_CONVERTER -DENABLE_SINC_FAST_CONVERTER -DCP_COLLISION_TYPE_TYPE=uintptr_t -DCP_BITMASK_TYPE=uintptr_t
|
||||
|
|
|
@ -820,6 +820,12 @@ Object.defineProperty(String.prototype, 'splice', {
|
|||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(String.prototype, 'sub', {
|
||||
value: function(index, str) {
|
||||
return this.slice(0,index) + str + this.slice(index+str.length);
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(String.prototype, 'rm', {
|
||||
value: function(index, endidx = index+1) { return this.slice(0,index) + this.slice(endidx); }
|
||||
});
|
||||
|
@ -1551,10 +1557,63 @@ Math.sortpointsccw = function(points)
|
|||
return ccw.map(function(x) { return x.add(cm); });
|
||||
}
|
||||
|
||||
var yaml = {};
|
||||
yaml.tojson = function(yaml)
|
||||
{
|
||||
yaml = yaml.replace(/(\w+):/g, '"$1":');
|
||||
yaml = yaml.replace(/: ([\w\.]+)/g, ': "$1"');
|
||||
|
||||
yaml = yaml.split("\n");
|
||||
var cont = {};
|
||||
var cur = 0;
|
||||
for (var i = 0; i < yaml.length; i++) {
|
||||
var line = yaml[i];
|
||||
var indent = line.search(/\S/);
|
||||
|
||||
if (indent > cur) {
|
||||
if (line[indent] == "-") {
|
||||
cont[indent] = "array";
|
||||
yaml[i] = line.sub(indent, '[');
|
||||
} else {
|
||||
cont[indent] = "obj";
|
||||
yaml[i] = line.sub(indent-1, '{');
|
||||
}
|
||||
}
|
||||
|
||||
if (indent < cur) {
|
||||
while (cur > indent) {
|
||||
if (cont[cur] === "obj")
|
||||
yaml[i-1] = yaml[i-1] + "}";
|
||||
else if (cont[cur] === "array")
|
||||
yaml[i-1] = yaml[i-1] + "]";
|
||||
|
||||
delete cont[cur];
|
||||
cur--;
|
||||
}
|
||||
}
|
||||
|
||||
if (indent === cur) {
|
||||
if (yaml[i][indent] === '-')
|
||||
yaml[i] = yaml[i].sub(indent,',');
|
||||
else
|
||||
yaml[i-1] = yaml[i-1] + ',';
|
||||
}
|
||||
|
||||
cur = indent;
|
||||
}
|
||||
yaml = "{" + yaml.join("\n") + "}";
|
||||
yaml = yaml.replace(/\s/g, '');
|
||||
yaml = yaml.replace(/,}/g, '}');
|
||||
yaml = yaml.replace(/,]/g, ']');
|
||||
return yaml;
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
convert,
|
||||
time,
|
||||
json,
|
||||
Vector,
|
||||
bbox
|
||||
bbox,
|
||||
yaml
|
||||
};
|
||||
|
|
|
@ -13,6 +13,10 @@ this.view2world = function(pos) {
|
|||
pos = pos.scale(this.zoom);
|
||||
pos = pos.add(this.pos);
|
||||
}
|
||||
if (window.mode === window.modetypes.expand) {
|
||||
pos = pos.sub(window.size.scale(0.5));
|
||||
pos = pos.scale([window.rendersize.x/window.size.x, window.rendersize.y/window.size.y]);
|
||||
}
|
||||
return pos;
|
||||
};
|
||||
this.world2view = function(pos) {
|
||||
|
@ -25,6 +29,9 @@ this.world2view = function(pos) {
|
|||
pos = pos.sub(this.pos);
|
||||
pos = pos.scale(1/this.zoom);
|
||||
pos = pos.add(window.size.scale(0.5));
|
||||
}
|
||||
if (window.mode === window.modetypes.expand) {
|
||||
|
||||
}
|
||||
return pos;
|
||||
};
|
||||
|
|
|
@ -177,7 +177,7 @@ Object.mixin(os.sprite(true), {
|
|||
height() { return this.dimensions().y; },
|
||||
});
|
||||
globalThis.allsprites = {};
|
||||
os.sprite(true).make = function(go)
|
||||
os.sprite().make = function(go)
|
||||
{
|
||||
var sp = os.sprite();
|
||||
sp.go = go;
|
||||
|
|
|
@ -344,7 +344,7 @@ var editor = {
|
|||
root = root ? root + "." : root;
|
||||
Object.entries(obj.objects).forEach(function(x) {
|
||||
var p = root + x[0];
|
||||
render.text(p, x[1].screenpos(), 1, editor.color_depths[depth]);
|
||||
render.text(p, x[1].this2screen(), 1, editor.color_depths[depth]);
|
||||
editor.draw_objects_names(x[1], p, depth+1);
|
||||
});
|
||||
},
|
||||
|
@ -402,7 +402,7 @@ var editor = {
|
|||
if (this.comp_info && this.sel_comp)
|
||||
render.text(input.print_pawn_kbm(this.sel_comp,false), [100,700],1);
|
||||
|
||||
render.cross(editor.edit_level.screenpos(),3,Color.blue);
|
||||
render.cross(editor.edit_level.this2screen(),3,Color.blue);
|
||||
|
||||
var thiso = editor.get_this();
|
||||
var clvl = thiso;
|
||||
|
@ -447,16 +447,16 @@ var editor = {
|
|||
render.text("$$$$$$", [0,ypos],1,editor.color_depths[depth]);
|
||||
|
||||
this.selectlist.forEach(function(x) {
|
||||
render.text(x.urstr(), x.screenpos().add([0, render.font.linegap*2]), 1, Color.editor.ur);
|
||||
render.text(x.pos.map(function(x) { return Math.round(x); }), x.screenpos());
|
||||
render.cross(x.screenpos(), 10, Color.blue);
|
||||
render.text(x.urstr(), x.this2screen().add([0, render.font.linegap*2]), 1, Color.editor.ur);
|
||||
render.text(x.pos.map(function(x) { return Math.round(x); }), x.this2screen());
|
||||
render.cross(x.this2screen(), 10, Color.blue);
|
||||
});
|
||||
|
||||
Object.entries(thiso.objects).forEach(function(x) {
|
||||
var p = x[1].namestr();
|
||||
render.text(p, x[1].screenpos().add([0,render.font.linegap]),1,editor.color_depths[depth]);
|
||||
render.point(x[1].screenpos(),5,Color.blue.alpha(0.3));
|
||||
render.point(x[1].screenpos(), 1, Color.red);
|
||||
render.text(p, x[1].this2screen().add([0,render.font.linegap]),1,editor.color_depths[depth]);
|
||||
render.point(x[1].this2screen(),5,Color.blue.alpha(0.3));
|
||||
render.point(x[1].this2screen(), 1, Color.red);
|
||||
});
|
||||
|
||||
var mg = physics.pos_query(input.mouse.worldpos());
|
||||
|
@ -474,7 +474,7 @@ var editor = {
|
|||
for (var key in this.selectlist[0].components) {
|
||||
var selected = this.sel_comp === this.selectlist[0].components[key];
|
||||
var str = (selected ? ">" : " ") + key + " [" + this.selectlist[0].components[key].toString() + "]";
|
||||
render.text(str, this.selectlist[0].screenpos().add([0,-render.font.linegap*(i++)]));
|
||||
render.text(str, this.selectlist[0].this2screen().add([0,-render.font.linegap*(i++)]));
|
||||
}
|
||||
|
||||
if (this.sel_comp) {
|
||||
|
@ -879,7 +879,7 @@ editor.inputs['C-s'] = function() {
|
|||
}
|
||||
|
||||
var savejs = saveobj.json_obj();
|
||||
var tur = saveobj.get_ur();
|
||||
var tur = saveobj.ur;
|
||||
if (!tur) {
|
||||
console.warn(`Can't save object because it has no ur.`);
|
||||
return;
|
||||
|
|
|
@ -289,7 +289,6 @@ game.engine_start = function(s) {
|
|||
gggstart(function() {
|
||||
global.mixin("scripts/sound.js");
|
||||
world_start();
|
||||
go_init();
|
||||
window.set_icon(os.make_texture("icons/moon.gif"))
|
||||
Object.readonly(window.__proto__, 'vsync');
|
||||
Object.readonly(window.__proto__, 'enable_dragndrop');
|
||||
|
@ -330,9 +329,9 @@ function process()
|
|||
}
|
||||
var st = profile.now();
|
||||
if (!game.camera)
|
||||
prosperon.window_render(world, 1);
|
||||
prosperon.window_render(world.transform, 1);
|
||||
else
|
||||
prosperon.window_render(game.camera, game.camera.zoom);
|
||||
prosperon.window_render(game.camera.transform, game.camera.zoom);
|
||||
|
||||
render.set_camera();
|
||||
|
||||
|
@ -627,7 +626,8 @@ global.mixin("scripts/actor");
|
|||
global.mixin("scripts/entity");
|
||||
|
||||
function world_start() {
|
||||
globalThis.world = os.make_gameobject();
|
||||
globalThis.world = Object.create(entity);
|
||||
world.transform = os.make_transform2d();
|
||||
world.objects = {};
|
||||
world.toString = function() { return "world"; };
|
||||
world.ur = "world";
|
||||
|
|
|
@ -12,16 +12,398 @@ function obj_unique_name(name, obj) {
|
|||
return n;
|
||||
}
|
||||
|
||||
var gameobject = {
|
||||
function unique_name(list, name = "new_object") {
|
||||
var str = name.replaceAll('.', '_');
|
||||
var n = 1;
|
||||
var t = str;
|
||||
while (list.indexOf(t) !== -1) {
|
||||
t = str + n;
|
||||
n++;
|
||||
}
|
||||
return t;
|
||||
};
|
||||
|
||||
var entity = {
|
||||
get_comp_by_name(name) {
|
||||
var comps = [];
|
||||
for (var c of Object.values(this.components))
|
||||
if (c.comp === name) comps.push(c);
|
||||
|
||||
|
||||
if (comps.length) return comps;
|
||||
return undefined;
|
||||
},
|
||||
|
||||
path_from(o) {
|
||||
var p = this.toString();
|
||||
var c = this.master;
|
||||
while (c && c !== o && c !== world) {
|
||||
p = c.toString() + "." + p;
|
||||
c = c.master;
|
||||
}
|
||||
if (c === world) p = "world." + p;
|
||||
return p;
|
||||
},
|
||||
|
||||
full_path() { return this.path_from(world); },
|
||||
|
||||
clear() {
|
||||
for (var k in this.objects) {
|
||||
this.objects[k].kill();
|
||||
};
|
||||
this.objects = {};
|
||||
},
|
||||
|
||||
sync() {
|
||||
this.components.forEach(function(x) { x.sync?.(); });
|
||||
this.objects.forEach(function(x) { x.sync(); });
|
||||
},
|
||||
|
||||
delay(fn, seconds) {
|
||||
var timers = this.timers;
|
||||
var stop = function() {
|
||||
timers.remove(stop);
|
||||
execute = undefined;
|
||||
stop = undefined;
|
||||
rm?.();
|
||||
rm = undefined;
|
||||
update = undefined;
|
||||
}
|
||||
|
||||
function execute() {
|
||||
fn();
|
||||
stop?.();
|
||||
}
|
||||
|
||||
stop.remain = seconds;
|
||||
stop.seconds = seconds;
|
||||
stop.pct = function() { return 1 - (stop.remain/stop.seconds); };
|
||||
|
||||
function update(dt) {
|
||||
stop.remain -= dt;
|
||||
if (stop.remain <= 0) execute();
|
||||
}
|
||||
|
||||
var rm = Register.update.register(update);
|
||||
timers.push(stop);
|
||||
return stop;
|
||||
},
|
||||
|
||||
cry(file) { return audio.cry(file); },
|
||||
|
||||
get pos() { return this.transform.pos; },
|
||||
set pos(x) { this.transform.pos = x; },
|
||||
get angle() { return this.transform.angle; },
|
||||
set angle(x) { this.transform.angle = x; },
|
||||
get scale() { return this.transform.scale; },
|
||||
set scale(x) { this.transform.scale = x; },
|
||||
|
||||
move(vec) { this.pos = this.pos.add(vec); },
|
||||
rotate(x) { this.angle += x; },
|
||||
grow(vec) {
|
||||
if (typeof vec === 'number') vec = [vec,vec];
|
||||
this.scale = this.scale.map((x,i) => x*vec[i]);
|
||||
},
|
||||
|
||||
/* 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}`);
|
||||
return;
|
||||
}
|
||||
|
||||
var name = unique_name(Object.keys(parent), this.name);
|
||||
this.name = name;
|
||||
|
||||
this.master?.remove_obj(this);
|
||||
this.master = parent;
|
||||
parent.objects[this.guid] = this;
|
||||
parent[name] = this;
|
||||
Object.hide(parent, name);
|
||||
},
|
||||
|
||||
remove_obj(obj) {
|
||||
delete this.objects[obj.guid];
|
||||
delete this[obj.name];
|
||||
Object.unhide(this, obj.name);
|
||||
},
|
||||
|
||||
spawn(text, config, callback) {
|
||||
var st = profile.now();
|
||||
var ent = Object.create(entity);
|
||||
ent.transform = os.make_transform2d();
|
||||
|
||||
ent.guid = prosperon.guid();
|
||||
|
||||
ent.components = {};
|
||||
ent.objects = {};
|
||||
ent.timers = [];
|
||||
|
||||
if (!text)
|
||||
ent.ur = emptyur;
|
||||
else if (typeof text === 'object' && text) {// assume it's an ur
|
||||
ent.ur = text;
|
||||
text = ent.ur.text;
|
||||
config = [ent.ur.data, config].filter(x => x).flat();
|
||||
}
|
||||
else {
|
||||
ent.ur = getur(text, config);
|
||||
text = ent.ur.text;
|
||||
config = [ent.ur.data, config];
|
||||
}
|
||||
|
||||
if (typeof text === 'string')
|
||||
use(text, ent);
|
||||
else if (Array.isArray(text))
|
||||
text.forEach(path => use(path,ent));
|
||||
|
||||
if (typeof config === 'string')
|
||||
Object.merge(ent, json.decode(Resources.replstrs(config)));
|
||||
else if (Array.isArray(config))
|
||||
config.forEach(function(path) {
|
||||
if (typeof path === 'string') {
|
||||
console.info(`ingesting ${path} ...`);
|
||||
Object.merge(ent, json.decode(Resources.replstrs(path)));
|
||||
}
|
||||
else if (typeof path === 'object')
|
||||
Object.merge(ent,path);
|
||||
});
|
||||
|
||||
ent.reparent(this);
|
||||
|
||||
for (var [prop, p] of Object.entries(ent)) {
|
||||
if (!p) continue;
|
||||
if (typeof p !== 'object') continue;
|
||||
if (component.isComponent(p)) continue;
|
||||
if (!p.comp) continue;
|
||||
ent[prop] = component[p.comp].make(ent);
|
||||
Object.merge(ent[prop], p);
|
||||
ent.components[prop] = ent[prop];
|
||||
};
|
||||
|
||||
check_registers(ent);
|
||||
|
||||
if (typeof ent.load === 'function') ent.load();
|
||||
if (sim.playing())
|
||||
if (typeof ent.start === 'function') ent.start();
|
||||
|
||||
Object.hide(ent, 'ur', 'components', 'objects', 'timers', 'guid', 'master');
|
||||
|
||||
ent._ed = {
|
||||
selectable: true,
|
||||
dirty: false,
|
||||
inst: false,
|
||||
urdiff: {}
|
||||
};
|
||||
|
||||
Object.hide(ent, '_ed');
|
||||
|
||||
ent.sync();
|
||||
|
||||
if (!Object.empty(ent.objects)) {
|
||||
var o = ent.objects;
|
||||
delete ent.objects;
|
||||
ent.objects = {};
|
||||
for (var i in o) {
|
||||
console.info(`creating ${i} on ${ent.toString()}`);
|
||||
var newur = o[i].ur;
|
||||
delete o[i].ur;
|
||||
var n = ent.spawn(ur[newur], o[i]);
|
||||
ent.rename_obj(n.toString(), i);
|
||||
}
|
||||
}
|
||||
|
||||
if (ent.tag) game.tag_add(ent.tag, ent);
|
||||
|
||||
if (callback) callback(ent);
|
||||
|
||||
|
||||
ent.ur.fresh ??= json.decode(json.encode(ent));
|
||||
ent.ur.fresh.objects = {};
|
||||
for (var i in ent.objects)
|
||||
ent.ur.fresh.objects[i] = ent.objects[i].instance_obj();
|
||||
|
||||
profile.addreport(entityreport, ent.ur.name, st);
|
||||
return ent;
|
||||
},
|
||||
|
||||
disable() { this.components.forEach(function(x) { x.disable(); }); },
|
||||
enable() { this.components.forEach(function(x) { x.enable(); }); },
|
||||
|
||||
this2screen(pos) { return game.camera.world2view(this.this2world(pos)); },
|
||||
screen2this(pos) { return this.world2this(game.camera.view2world(pos)); },
|
||||
|
||||
/* Make a unique object the same as its prototype */
|
||||
revert() { Object.merge(this, this.ur.fresh); },
|
||||
|
||||
name: "new_object",
|
||||
toString() { return this.name; },
|
||||
width() {
|
||||
var bb = this.boundingbox();
|
||||
return bb.r - bb.l;
|
||||
},
|
||||
|
||||
height() {
|
||||
var bb = this.boundingbox();
|
||||
return bb.t - bb.b;
|
||||
},
|
||||
|
||||
flipx() { return this.scale.x < 0; },
|
||||
flipy() { return this.scale.y < 0; },
|
||||
|
||||
mirror(plane) { this.scale = Vector.reflect(this.scale, plane); },
|
||||
|
||||
/* Bounding box of the object in world dimensions */
|
||||
boundingbox() {
|
||||
var boxes = [];
|
||||
boxes.push({
|
||||
t: 0,
|
||||
r: 0,
|
||||
b: 0,
|
||||
l: 0
|
||||
});
|
||||
|
||||
for (var key in this.components) {
|
||||
if ('boundingbox' in this.components[key])
|
||||
boxes.push(this.components[key].boundingbox());
|
||||
}
|
||||
for (var key in this.objects)
|
||||
boxes.push(this.objects[key].boundingbox());
|
||||
|
||||
var bb = boxes.shift();
|
||||
|
||||
boxes.forEach(function(x) { bb = bbox.expand(bb, x); });
|
||||
|
||||
bb = bbox.move(bb, this.pos);
|
||||
|
||||
return bb ? bb : bbox.fromcwh([0, 0], [0, 0]);
|
||||
},
|
||||
|
||||
/* The unique components of this object. Its diff. */
|
||||
json_obj(depth=0) {
|
||||
var fresh = this.ur.fresh;
|
||||
var thiso = json.decode(json.encode(this)); // TODO: SLOW. Used to ignore properties in toJSON of components.
|
||||
var d = ediff(thiso, fresh);
|
||||
|
||||
d ??= {};
|
||||
|
||||
fresh.objects ??= {};
|
||||
var curobjs = {};
|
||||
for (var o in this.objects)
|
||||
curobjs[o] = this.objects[o].instance_obj();
|
||||
|
||||
var odiff = ediff(curobjs, fresh.objects);
|
||||
if (odiff)
|
||||
d.objects = curobjs;
|
||||
|
||||
delete d.pos;
|
||||
delete d.angle;
|
||||
delete d.scale;
|
||||
delete d.velocity;
|
||||
delete d.angularvelocity;
|
||||
return d;
|
||||
},
|
||||
|
||||
/* The object needed to store an object as an instance of a master */
|
||||
instance_obj() {
|
||||
var t = this.transform();
|
||||
t.ur = this.ur.name;
|
||||
return t;
|
||||
},
|
||||
|
||||
transform() {
|
||||
var t = {};
|
||||
t.pos = this.get_pos(this.master).map(x => Math.places(x, 0));
|
||||
t.angle = Math.places(this.get_angle(this.master), 4);
|
||||
t.scale = this.get_scale(this.master).map(x => Math.places(x, 2));;
|
||||
return t;
|
||||
},
|
||||
|
||||
dup(diff) {
|
||||
var n = this.master.spawn(this.ur);
|
||||
Object.totalmerge(n, this.transform());
|
||||
return n;
|
||||
},
|
||||
|
||||
kill() {
|
||||
if (this.__kill) return;
|
||||
this.__kill = true;
|
||||
console.spam(`Killing entity of type ${this.ur}`);
|
||||
|
||||
this.timers.forEach(t => t());
|
||||
this.timers = [];
|
||||
Event.rm_obj(this);
|
||||
input.do_uncontrol(this);
|
||||
|
||||
if (this.master) {
|
||||
this.master.remove_obj(this);
|
||||
this.master = undefined;
|
||||
}
|
||||
|
||||
for (var key in this.components) {
|
||||
this.components[key].kill?.();
|
||||
this.components[key].gameobject = undefined;
|
||||
this[key].enabled = false;
|
||||
delete this.components[key];
|
||||
delete this[key];
|
||||
}
|
||||
delete this.components;
|
||||
|
||||
this.clear();
|
||||
if (typeof this.stop === 'function') this.stop();
|
||||
|
||||
game.tag_clear_guid(this.guid);
|
||||
|
||||
for (var i in this) {
|
||||
if (typeof this[i] === 'object') delete this[i];
|
||||
if (typeof this[i] === 'function') delete this[i];
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
make_objs(objs) {
|
||||
for (var prop in objs) {
|
||||
say(`spawning ${json.encode(objs[prop])}`);
|
||||
var newobj = this.spawn(objs[prop]);
|
||||
}
|
||||
},
|
||||
|
||||
rename_obj(name, newname) {
|
||||
if (!this.objects[name]) {
|
||||
console.warn(`No object with name ${name}. Could not rename to ${newname}.`);
|
||||
return;
|
||||
}
|
||||
if (name === newname) {
|
||||
Object.hide(this, name);
|
||||
return;
|
||||
}
|
||||
if (this.objects[newname])
|
||||
return;
|
||||
|
||||
this.objects[newname] = this.objects[name];
|
||||
this[newname] = this[name];
|
||||
this[newname].toString = function() { return newname; };
|
||||
Object.hide(this, newname);
|
||||
delete this.objects[name];
|
||||
delete this[name];
|
||||
return this.objects[newname];
|
||||
},
|
||||
|
||||
add_component(comp, data, name = comp.toString()) {
|
||||
if (typeof comp.make !== 'function') return;
|
||||
name = obj_unique_name(name, this);
|
||||
this[name] = comp.make(this);
|
||||
this[name].comp = comp.toString();
|
||||
this.components[name] = this[name];
|
||||
if (data)
|
||||
Object.assign(this[name], data);
|
||||
return this[name];
|
||||
},
|
||||
};
|
||||
|
||||
var gameobject = {
|
||||
check_dirty() {
|
||||
this._ed.urdiff = this.json_obj();
|
||||
this._ed.dirty = !Object.empty(this._ed.urdiff);
|
||||
|
@ -50,9 +432,6 @@ var gameobject = {
|
|||
return str;
|
||||
},
|
||||
|
||||
full_path() {
|
||||
return this.path_from(world);
|
||||
},
|
||||
/* pin this object to the to object */
|
||||
pin(to) {
|
||||
var p = joint.pin(this,to);
|
||||
|
@ -95,63 +474,6 @@ var gameobject = {
|
|||
var p = joint.motor(this, to, rate);
|
||||
},
|
||||
|
||||
path_from(o) {
|
||||
var p = this.toString();
|
||||
var c = this.master;
|
||||
while (c && c !== o && c !== world) {
|
||||
p = c.toString() + "." + p;
|
||||
c = c.master;
|
||||
}
|
||||
if (c === world) p = "world." + p;
|
||||
return p;
|
||||
},
|
||||
|
||||
clear() {
|
||||
for (var k in this.objects) {
|
||||
this.objects[k].kill();
|
||||
};
|
||||
this.objects = {};
|
||||
},
|
||||
|
||||
delay(fn, seconds) {
|
||||
var timers = this.timers;
|
||||
var stop = function() {
|
||||
timers.remove(stop);
|
||||
execute = undefined;
|
||||
stop = undefined;
|
||||
rm?.();
|
||||
rm = undefined;
|
||||
update = undefined;
|
||||
}
|
||||
|
||||
function execute() {
|
||||
fn();
|
||||
stop?.();
|
||||
}
|
||||
|
||||
stop.remain = seconds;
|
||||
stop.seconds = seconds;
|
||||
stop.pct = function() { return 1 - (stop.remain/stop.seconds); };
|
||||
|
||||
function update(dt) {
|
||||
stop.remain -= dt;
|
||||
if (stop.remain <= 0) execute();
|
||||
}
|
||||
|
||||
var rm = Register.update.register(update);
|
||||
timers.push(stop);
|
||||
return stop;
|
||||
},
|
||||
|
||||
cry(file) { return audio.cry(file); },
|
||||
|
||||
set pos(x) { this.set_pos(x); },
|
||||
get pos() { return this.rpos; },
|
||||
set angle(x) { this.set_angle(x); },
|
||||
get angle() { return this.rangle; },
|
||||
set scale(x) { this.set_scale(x); },
|
||||
get scale() { return this.rscale; },
|
||||
|
||||
set_pos(x, relative = world) {
|
||||
var newpos = relative.this2world(x);
|
||||
var move = newpos.sub(this.pos);
|
||||
|
@ -197,285 +519,8 @@ var gameobject = {
|
|||
return this.scale.map((x,i) => x/masterscale[i]);
|
||||
},
|
||||
|
||||
/* Moving, rotating, scaling functions, world relative */
|
||||
move(vec) { this.set_pos(this.pos.add(vec)); },
|
||||
rotate(x) { this.set_angle(this.angle + x); },
|
||||
grow(vec) {
|
||||
if (typeof vec === 'number') vec = [vec,vec,vec];
|
||||
this.set_scale(this.scale.map((x, i) => x * vec[i]));
|
||||
},
|
||||
|
||||
screenpos() { return game.camera.world2view(this.pos); },
|
||||
|
||||
get_ur() { return this.ur; },
|
||||
|
||||
/* spawn an entity
|
||||
text can be:
|
||||
the file path of a script
|
||||
an ur object
|
||||
nothing
|
||||
*/
|
||||
spawn(text, config, callback) {
|
||||
var st = profile.now();
|
||||
var ent = os.make_gameobject();
|
||||
ent.guid = prosperon.guid();
|
||||
ent.components = {};
|
||||
ent.objects = {};
|
||||
ent.timers = [];
|
||||
|
||||
Object.mixin(ent, {
|
||||
set category(n) {
|
||||
if (n === 0) {
|
||||
this.categories = n;
|
||||
return;
|
||||
}
|
||||
var cat = (1 << (n-1));
|
||||
this.categories = cat;
|
||||
},
|
||||
get category() {
|
||||
if (this.categories === 0) return 0;
|
||||
var pos = 0;
|
||||
var num = this.categories;
|
||||
while (num > 0) {
|
||||
if (num & 1) {
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
num >>>= 1;
|
||||
}
|
||||
|
||||
return pos+1;
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof text === 'object' && text) {// assume it's an ur
|
||||
ent.ur = text;
|
||||
text = ent.ur.text;
|
||||
config = [ent.ur.data, config].filter(x => x).flat();
|
||||
}
|
||||
else {
|
||||
ent.ur = getur(text, config);
|
||||
text = ent.ur.text;
|
||||
config = [ent.ur.data, config];
|
||||
}
|
||||
|
||||
if (typeof text === 'string')
|
||||
use(text, ent);
|
||||
else if (Array.isArray(text))
|
||||
text.forEach(path => use(path,ent));
|
||||
|
||||
if (typeof config === 'string')
|
||||
Object.merge(ent, json.decode(Resources.replstrs(config)));
|
||||
else if (Array.isArray(config))
|
||||
config.forEach(function(path) {
|
||||
if (typeof path === 'string') {
|
||||
console.info(`ingesting ${path} ...`);
|
||||
Object.merge(ent, json.decode(Resources.replstrs(path)));
|
||||
}
|
||||
else if (typeof path === 'object')
|
||||
Object.merge(ent,path);
|
||||
});
|
||||
|
||||
ent.reparent(this);
|
||||
|
||||
for (var [prop, p] of Object.entries(ent)) {
|
||||
if (!p) continue;
|
||||
if (typeof p !== 'object') continue;
|
||||
if (component.isComponent(p)) continue;
|
||||
if (!p.comp) continue;
|
||||
ent[prop] = component[p.comp].make(ent);
|
||||
Object.merge(ent[prop], p);
|
||||
ent.components[prop] = ent[prop];
|
||||
};
|
||||
|
||||
check_registers(ent);
|
||||
|
||||
if (typeof ent.load === 'function') ent.load();
|
||||
if (sim.playing())
|
||||
if (typeof ent.start === 'function') ent.start();
|
||||
|
||||
Object.hide(ent, 'ur', 'components', 'objects', 'timers', 'guid', 'master', 'categories');
|
||||
|
||||
ent._ed = {
|
||||
selectable: true,
|
||||
dirty: false,
|
||||
inst: false,
|
||||
urdiff: {}
|
||||
};
|
||||
|
||||
Object.hide(ent, '_ed');
|
||||
|
||||
ent.sync();
|
||||
|
||||
if (!Object.empty(ent.objects)) {
|
||||
var o = ent.objects;
|
||||
delete ent.objects;
|
||||
ent.objects = {};
|
||||
for (var i in o) {
|
||||
console.info(`creating ${i} on ${ent.toString()}`);
|
||||
var newur = o[i].ur;
|
||||
delete o[i].ur;
|
||||
var n = ent.spawn(ur[newur], o[i]);
|
||||
ent.rename_obj(n.toString(), i);
|
||||
}
|
||||
}
|
||||
|
||||
if (ent.tag) game.tag_add(ent.tag, ent);
|
||||
|
||||
if (callback) callback(ent);
|
||||
|
||||
ent.ur.fresh ??= json.decode(json.encode(ent));
|
||||
ent.ur.fresh.objects = {};
|
||||
for (var i in ent.objects)
|
||||
ent.ur.fresh.objects[i] = ent.objects[i].instance_obj();
|
||||
|
||||
profile.addreport(entityreport, ent.ur.name, st);
|
||||
return ent;
|
||||
},
|
||||
|
||||
/* 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}`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.master?.remove_obj(this);
|
||||
|
||||
this.master = parent;
|
||||
|
||||
function unique_name(list, name = "new_object") {
|
||||
var str = name.replaceAll('.', '_');
|
||||
var n = 1;
|
||||
var t = str;
|
||||
while (list.indexOf(t) !== -1) {
|
||||
t = str + n;
|
||||
n++;
|
||||
}
|
||||
return t;
|
||||
};
|
||||
|
||||
var name = unique_name(Object.keys(parent.objects), this.ur.name);
|
||||
|
||||
parent.objects[name] = this;
|
||||
parent[name] = this;
|
||||
Object.hide(parent, name);
|
||||
this.toString = function() { return name; };
|
||||
},
|
||||
|
||||
remove_obj(obj) {
|
||||
delete this.objects[obj.toString()];
|
||||
delete this[obj.toString()];
|
||||
Object.unhide(this, obj.toString());
|
||||
},
|
||||
|
||||
components: {},
|
||||
objects: {},
|
||||
master: undefined,
|
||||
|
||||
this2screen(pos) { return game.camera.world2view(this.this2world(pos)); },
|
||||
screen2this(pos) { return this.world2this(game.camera.view2world(pos)); },
|
||||
|
||||
in_air() { return this.in_air(); },
|
||||
|
||||
hide() { this.components.forEach(x => x.hide?.());
|
||||
this.objects.forEach(x => x.hide?.()); },
|
||||
|
||||
show() { this.components.forEach(function(x) { x.show?.(); });
|
||||
this.objects.forEach(function(x) { x.show?.(); }); },
|
||||
|
||||
width() {
|
||||
var bb = this.boundingbox();
|
||||
return bb.r - bb.l;
|
||||
},
|
||||
|
||||
height() {
|
||||
var bb = this.boundingbox();
|
||||
return bb.t - bb.b;
|
||||
},
|
||||
|
||||
/* Make a unique object the same as its prototype */
|
||||
revert() { Object.merge(this, this.ur.fresh); },
|
||||
|
||||
toString() { return "new_object"; },
|
||||
|
||||
flipx() { return this.scale.x < 0; },
|
||||
flipy() { return this.scale.y < 0; },
|
||||
|
||||
mirror(plane) { this.scale = Vector.reflect(this.scale, plane); },
|
||||
|
||||
disable() { this.components.forEach(function(x) { x.disable(); }); },
|
||||
enable() { this.components.forEach(function(x) { x.enable(); }); },
|
||||
|
||||
/* Bounding box of the object in world dimensions */
|
||||
boundingbox() {
|
||||
var boxes = [];
|
||||
boxes.push({
|
||||
t: 0,
|
||||
r: 0,
|
||||
b: 0,
|
||||
l: 0
|
||||
});
|
||||
|
||||
for (var key in this.components) {
|
||||
if ('boundingbox' in this.components[key])
|
||||
boxes.push(this.components[key].boundingbox());
|
||||
}
|
||||
for (var key in this.objects)
|
||||
boxes.push(this.objects[key].boundingbox());
|
||||
|
||||
var bb = boxes.shift();
|
||||
|
||||
boxes.forEach(function(x) { bb = bbox.expand(bb, x); });
|
||||
|
||||
bb = bbox.move(bb, this.pos);
|
||||
|
||||
return bb ? bb : bbox.fromcwh([0, 0], [0, 0]);
|
||||
},
|
||||
|
||||
/* The unique components of this object. Its diff. */
|
||||
json_obj(depth=0) {
|
||||
var fresh = this.ur.fresh;
|
||||
var thiso = json.decode(json.encode(this)); // TODO: SLOW. Used to ignore properties in toJSON of components.
|
||||
var d = ediff(thiso, fresh);
|
||||
|
||||
d ??= {};
|
||||
|
||||
fresh.objects ??= {};
|
||||
var curobjs = {};
|
||||
for (var o in this.objects)
|
||||
curobjs[o] = this.objects[o].instance_obj();
|
||||
|
||||
var odiff = ediff(curobjs, fresh.objects);
|
||||
if (odiff)
|
||||
d.objects = curobjs;
|
||||
|
||||
delete d.pos;
|
||||
delete d.angle;
|
||||
delete d.scale;
|
||||
delete d.velocity;
|
||||
delete d.angularvelocity;
|
||||
return d;
|
||||
},
|
||||
|
||||
/* The object needed to store an object as an instance of a master */
|
||||
instance_obj() {
|
||||
var t = this.transform();
|
||||
t.ur = this.ur.name;
|
||||
return t;
|
||||
},
|
||||
|
||||
transform() {
|
||||
var t = {};
|
||||
t.pos = this.get_pos(this.master).map(x => Math.places(x, 0));
|
||||
t.angle = Math.places(this.get_angle(this.master), 4);
|
||||
t.scale = this.get_scale(this.master).map(x => Math.places(x, 2));;
|
||||
return t;
|
||||
},
|
||||
|
||||
/* Velocity and angular velocity of the object */
|
||||
phys_obj() {
|
||||
var phys = {};
|
||||
|
@ -483,111 +528,32 @@ var gameobject = {
|
|||
phys.angularvelocity = this.angularvelocity;
|
||||
return phys;
|
||||
},
|
||||
|
||||
phys_mat() {
|
||||
return {
|
||||
friction: this.friction,
|
||||
elasticity: this.elasticity
|
||||
|
||||
set category(n) {
|
||||
if (n === 0) {
|
||||
this.categories = n;
|
||||
return;
|
||||
}
|
||||
var cat = (1 << (n-1));
|
||||
this.categories = cat;
|
||||
},
|
||||
|
||||
dup(diff) {
|
||||
var n = this.master.spawn(this.ur);
|
||||
Object.totalmerge(n, this.transform());
|
||||
return n;
|
||||
},
|
||||
|
||||
kill() {
|
||||
if (this.__kill) return;
|
||||
this.__kill = true;
|
||||
console.spam(`Killing entity of type ${this.ur}`);
|
||||
|
||||
this.timers.forEach(t => t());
|
||||
this.timers = [];
|
||||
Event.rm_obj(this);
|
||||
input.do_uncontrol(this);
|
||||
|
||||
if (this.master) {
|
||||
this.master.remove_obj(this);
|
||||
this.master = undefined;
|
||||
get category() {
|
||||
if (this.categories === 0) return 0;
|
||||
var pos = 0;
|
||||
var num = this.categories;
|
||||
while (num > 0) {
|
||||
if (num & 1) {
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
num >>>= 1;
|
||||
}
|
||||
|
||||
for (var key in this.components) {
|
||||
this.components[key].kill?.();
|
||||
this.components[key].gameobject = undefined;
|
||||
this[key].enabled = false;
|
||||
delete this.components[key];
|
||||
delete this[key];
|
||||
}
|
||||
delete this.components;
|
||||
|
||||
this.clear();
|
||||
if (typeof this.stop === 'function') this.stop();
|
||||
|
||||
game.tag_clear_guid(this.guid);
|
||||
|
||||
for (var i in this) {
|
||||
if (typeof this[i] === 'object') delete this[i];
|
||||
if (typeof this[i] === 'function') delete this[i];
|
||||
}
|
||||
},
|
||||
|
||||
up() { return [0, 1].rotate(this.angle); },
|
||||
down() { return [0, -1].rotate(this.angle); },
|
||||
right() { return [1, 0].rotate(this.angle); },
|
||||
left() { return [-1, 0].rotate(this.angle); },
|
||||
|
||||
make_objs(objs) {
|
||||
for (var prop in objs) {
|
||||
say(`spawning ${json.encode(objs[prop])}`);
|
||||
var newobj = this.spawn(objs[prop]);
|
||||
}
|
||||
},
|
||||
|
||||
rename_obj(name, newname) {
|
||||
if (!this.objects[name]) {
|
||||
console.warn(`No object with name ${name}. Could not rename to ${newname}.`);
|
||||
return;
|
||||
}
|
||||
if (name === newname) {
|
||||
Object.hide(this, name);
|
||||
return;
|
||||
}
|
||||
if (this.objects[newname])
|
||||
return;
|
||||
|
||||
this.objects[newname] = this.objects[name];
|
||||
this[newname] = this[name];
|
||||
this[newname].toString = function() { return newname; };
|
||||
Object.hide(this, newname);
|
||||
delete this.objects[name];
|
||||
delete this[name];
|
||||
return this.objects[newname];
|
||||
},
|
||||
|
||||
add_component(comp, data, name = comp.toString()) {
|
||||
if (typeof comp.make !== 'function') return;
|
||||
name = obj_unique_name(name, this);
|
||||
this[name] = comp.make(this);
|
||||
this[name].comp = comp.toString();
|
||||
this.components[name] = this[name];
|
||||
if (data)
|
||||
Object.assign(this[name], data);
|
||||
return this[name];
|
||||
},
|
||||
}
|
||||
|
||||
function go_init() {
|
||||
var gop = os.make_gameobject().__proto__;
|
||||
Object.mixin(gop, gameobject);
|
||||
gop.sync = function() {
|
||||
this.selfsync();
|
||||
this.components.forEach(function(x) { x.sync?.(); });
|
||||
this.objects.forEach(function(x) { x.sync?.(); });
|
||||
return pos+1;
|
||||
}
|
||||
}
|
||||
|
||||
gameobject.spawn.doc = `Spawn an entity of type 'ur' on this entity. Returns the spawned entity.`;
|
||||
entity.spawn.doc = `Spawn an entity of type 'ur' on this entity. Returns the spawned entity.`;
|
||||
|
||||
gameobject.doc = {
|
||||
doc: "All objects in the game created through spawning have these attributes.",
|
||||
|
@ -695,8 +661,18 @@ function apply_ur(u, ent) {
|
|||
}
|
||||
}
|
||||
|
||||
var emptyur = {
|
||||
name: "empty"
|
||||
}
|
||||
|
||||
var getur = function(text, data)
|
||||
{
|
||||
if (!text && !data) {
|
||||
console.info('empty ur');
|
||||
return {
|
||||
name: "empty"
|
||||
};
|
||||
}
|
||||
var urstr = text + "+" + data;
|
||||
if (!ur[urstr]) {
|
||||
ur[urstr] = {
|
||||
|
@ -784,4 +760,4 @@ game.ur.save = function(str)
|
|||
}
|
||||
}
|
||||
|
||||
return { go_init }
|
||||
return { entity }
|
|
@ -124,9 +124,9 @@ render.text = function(str, pos, size = 1, color = Color.white, wrap = -1, ancho
|
|||
};
|
||||
|
||||
render.image = function(tex, pos, rotation = 0, color = Color.white, dimensions = [tex.width, tex.height]) {
|
||||
var scale = [dimensions.x/tex.width, dimensions.y/tex.height];
|
||||
gui.img(tex,pos, scale, 0.0, false, [0.0,0.0], color);
|
||||
return bbox.fromcwh([0,0], [tex.width,tex.height]);
|
||||
//var scale = [dimensions.x/tex.width, dimensions.y/tex.height];
|
||||
//gui.img(tex,pos, scale, 0.0, false, [0.0,0.0], color);
|
||||
//return bbox.fromcwh([0,0], [tex.width,tex.height]);
|
||||
}
|
||||
|
||||
render.fontcache = {};
|
||||
|
|
|
@ -476,9 +476,54 @@ Cmdline.register_cmd("l", function(n) {
|
|||
console.level = n;
|
||||
}, "Set log level.");
|
||||
|
||||
function convertYAMLtoJSON(yamlString) {
|
||||
const lines = yamlString.split('\n');
|
||||
const jsonObj = {};
|
||||
|
||||
let currentKey = '';
|
||||
let currentValue = '';
|
||||
let currentDepth = 0;
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i].trim();
|
||||
if (!line || line.startsWith('#')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const depth = (line.match(/^\s+/g) || [''])[0].length;
|
||||
const keyValue = line.split(':');
|
||||
const key = keyValue[0].trim();
|
||||
const value = keyValue[1].trim();
|
||||
|
||||
if (depth > currentDepth) {
|
||||
jsonObj[currentKey] = convertYAMLtoJSON(currentValue);
|
||||
currentKey = key;
|
||||
currentValue = value;
|
||||
} else if (depth === currentDepth) {
|
||||
jsonObj[currentKey] = convertYAMLtoJSON(currentValue);
|
||||
currentKey = key;
|
||||
currentValue = value;
|
||||
} else {
|
||||
jsonObj[currentKey] = convertYAMLtoJSON(currentValue);
|
||||
currentKey = '';
|
||||
currentValue = '';
|
||||
i--; // To reprocess the current line with updated values
|
||||
}
|
||||
|
||||
currentDepth = depth;
|
||||
}
|
||||
|
||||
if (currentKey) {
|
||||
jsonObj[currentKey] = convertYAMLtoJSON(currentValue);
|
||||
}
|
||||
|
||||
return jsonObj;
|
||||
}
|
||||
|
||||
return {
|
||||
Resources,
|
||||
Cmdline,
|
||||
cmd_args
|
||||
cmd_args,
|
||||
convertYAMLtoJSON
|
||||
};
|
||||
|
||||
|
|
|
@ -5,9 +5,6 @@
|
|||
#include "stb_ds.h"
|
||||
#include "gameobject.h"
|
||||
|
||||
//#include "diffuse.sglsl.h"
|
||||
#include "unlit.sglsl.h"
|
||||
|
||||
#include "render.h"
|
||||
|
||||
#include "HandmadeMath.h"
|
||||
|
@ -30,50 +27,8 @@ static void processnode();
|
|||
static void processmesh();
|
||||
static void processtexture();
|
||||
|
||||
static sg_shader model_shader;
|
||||
static sg_pipeline model_pipe;
|
||||
struct bone_weights {
|
||||
char b1;
|
||||
char b2;
|
||||
char b3;
|
||||
char b4;
|
||||
};
|
||||
|
||||
struct joints {
|
||||
char j1;
|
||||
char j2;
|
||||
char j3;
|
||||
char j4;
|
||||
};
|
||||
|
||||
void model_init() {
|
||||
model_shader = sg_make_shader(unlit_shader_desc(sg_query_backend()));
|
||||
|
||||
model_pipe = sg_make_pipeline(&(sg_pipeline_desc){
|
||||
.shader = model_shader,
|
||||
.layout = {
|
||||
.attrs = {
|
||||
[0].format = SG_VERTEXFORMAT_FLOAT3,
|
||||
[1].format = SG_VERTEXFORMAT_USHORT2N,
|
||||
[1].buffer_index = 1,
|
||||
[2].format = SG_VERTEXFORMAT_UINT10_N2,
|
||||
[2].buffer_index = 2,
|
||||
[3] = {
|
||||
.format = SG_VERTEXFORMAT_UBYTE4N,
|
||||
.buffer_index = 3
|
||||
},
|
||||
[4] = {
|
||||
.format = SG_VERTEXFORMAT_UBYTE4,
|
||||
.buffer_index = 4
|
||||
}
|
||||
},
|
||||
},
|
||||
.index_type = SG_INDEXTYPE_UINT16,
|
||||
.cull_mode = SG_CULLMODE_FRONT,
|
||||
.depth.write_enabled = true,
|
||||
.depth.compare = SG_COMPAREFUNC_LESS_EQUAL
|
||||
});
|
||||
}
|
||||
static cgltf_data *cdata;
|
||||
static char *cpath;
|
||||
|
||||
cgltf_attribute *get_attr_type(cgltf_primitive *p, cgltf_attribute_type t)
|
||||
{
|
||||
|
@ -109,17 +64,21 @@ void mesh_add_material(primitive *prim, cgltf_material *mat)
|
|||
{
|
||||
if (!mat) return;
|
||||
|
||||
if (mat->has_pbr_metallic_roughness) {
|
||||
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;
|
||||
prim->bind.fs.images[0] = texture_fromdata(buf->buffer->data, buf->size)->id;
|
||||
} else
|
||||
prim->bind.fs.images[0] = texture_from_file(img->uri)->id;
|
||||
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
|
||||
prim->bind.fs.images[0] = texture_from_file("icons/moon.gif")->id;
|
||||
|
||||
prim->bind.fs.samplers[0] = std_sampler;
|
||||
pmat->diffuse = texture_from_file("icons/moon.gif");
|
||||
}
|
||||
|
||||
sg_buffer texcoord_floats(float *f, int verts, int comp)
|
||||
|
@ -147,6 +106,24 @@ sg_buffer normal_floats(float *f, int verts, int comp)
|
|||
});
|
||||
}
|
||||
|
||||
sg_buffer ubyten_buffer(float *f, int v, int c)
|
||||
{
|
||||
unsigned char b[v*c];
|
||||
for (int i = 0; i < (v*c); i++)
|
||||
b[i] = f[i]*255;
|
||||
|
||||
return sg_make_buffer(&(sg_buffer_desc){.data=SG_RANGE(b)});
|
||||
}
|
||||
|
||||
sg_buffer ubyte_buffer(float *f, int v, int c)
|
||||
{
|
||||
unsigned char b[v*c];
|
||||
for (int i = 0; i < (v*c); i++)
|
||||
b[i] = f[i];
|
||||
|
||||
return sg_make_buffer(&(sg_buffer_desc){.data=SG_RANGE(b)});
|
||||
}
|
||||
|
||||
sg_buffer joint_buf(float *f, int v, int c)
|
||||
{
|
||||
char joints[v*c];
|
||||
|
@ -183,7 +160,7 @@ struct primitive mesh_add_primitive(cgltf_primitive *prim)
|
|||
for (int i = 0; i < n; i++)
|
||||
idxs[i] = fidx[i];
|
||||
|
||||
retp.bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
|
||||
retp.idx = sg_make_buffer(&(sg_buffer_desc){
|
||||
.data.ptr = idxs,
|
||||
.data.size = sizeof(*idxs) * n,
|
||||
.type = SG_BUFFERTYPE_INDEXBUFFER,
|
||||
|
@ -201,7 +178,7 @@ struct primitive mesh_add_primitive(cgltf_primitive *prim)
|
|||
for (int z = 0; z < c; z++)
|
||||
idxs[z] = z;
|
||||
|
||||
retp.bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
|
||||
retp.idx = sg_make_buffer(&(sg_buffer_desc){
|
||||
.data.ptr = idxs,
|
||||
.data.size = sizeof(uint16_t) * c,
|
||||
.type = SG_BUFFERTYPE_INDEXBUFFER});
|
||||
|
@ -211,7 +188,6 @@ struct primitive mesh_add_primitive(cgltf_primitive *prim)
|
|||
|
||||
printf("adding material\n");
|
||||
mesh_add_material(&retp, prim->material);
|
||||
int has_norm = 0;
|
||||
|
||||
for (int k = 0; k < prim->attributes_count; k++) {
|
||||
cgltf_attribute attribute = prim->attributes[k];
|
||||
|
@ -224,7 +200,7 @@ struct primitive mesh_add_primitive(cgltf_primitive *prim)
|
|||
|
||||
switch (attribute.type) {
|
||||
case cgltf_attribute_type_position:
|
||||
retp.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
|
||||
retp.pos = sg_make_buffer(&(sg_buffer_desc){
|
||||
.data.ptr = vs,
|
||||
.data.size = sizeof(float) * n,
|
||||
.label = "mesh vert buffer"
|
||||
|
@ -232,26 +208,26 @@ struct primitive mesh_add_primitive(cgltf_primitive *prim)
|
|||
break;
|
||||
|
||||
case cgltf_attribute_type_normal:
|
||||
has_norm = 1;
|
||||
retp.bind.vertex_buffers[2] = normal_floats(vs, verts, comp);
|
||||
retp.norm = normal_floats(vs, verts, comp);
|
||||
break;
|
||||
|
||||
case cgltf_attribute_type_tangent:
|
||||
break;
|
||||
|
||||
case cgltf_attribute_type_color:
|
||||
retp.color = ubyten_buffer(vs,verts,comp);
|
||||
break;
|
||||
|
||||
case cgltf_attribute_type_weights:
|
||||
retp.bind.vertex_buffers[3] = weight_buf(vs, verts, comp);
|
||||
retp.weight = ubyten_buffer(vs, verts, comp);
|
||||
break;
|
||||
|
||||
case cgltf_attribute_type_joints:
|
||||
retp.bind.vertex_buffers[4] = joint_buf(vs, verts, comp);
|
||||
retp.bone = ubyte_buffer(vs, verts, comp);
|
||||
break;
|
||||
|
||||
case cgltf_attribute_type_texcoord:
|
||||
retp.bind.vertex_buffers[1] = texcoord_floats(vs, verts, comp);
|
||||
retp.uv = texcoord_floats(vs, verts, comp);
|
||||
break;
|
||||
case cgltf_attribute_type_invalid:
|
||||
YughWarn("Invalid type.");
|
||||
|
@ -259,12 +235,31 @@ struct primitive mesh_add_primitive(cgltf_primitive *prim)
|
|||
|
||||
case cgltf_attribute_type_custom:
|
||||
break;
|
||||
|
||||
case cgltf_attribute_type_max_enum:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_norm) {
|
||||
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);
|
||||
|
@ -283,7 +278,7 @@ struct primitive mesh_add_primitive(cgltf_primitive *prim)
|
|||
face_norms[i] = face_norms[i+1] = face_norms[i+2] = packed_norm;
|
||||
}
|
||||
|
||||
retp.bind.vertex_buffers[2] = sg_make_buffer(&(sg_buffer_desc){
|
||||
retp.norm = sg_make_buffer(&(sg_buffer_desc){
|
||||
.data.ptr = face_norms,
|
||||
.data.size = sizeof(uint32_t) * verts});
|
||||
}
|
||||
|
@ -291,7 +286,7 @@ struct primitive mesh_add_primitive(cgltf_primitive *prim)
|
|||
return retp;
|
||||
}
|
||||
|
||||
static cgltf_data *cdata;
|
||||
|
||||
|
||||
void model_add_cgltf_mesh(mesh *m, cgltf_mesh *gltf_mesh)
|
||||
{
|
||||
|
@ -382,7 +377,7 @@ void model_add_cgltf_skin(model *model, cgltf_skin *skin)
|
|||
sk.root = model->nodes+(skin->skeleton-cdata->nodes);
|
||||
|
||||
for (int i = 0; i < 50; i++)
|
||||
sk.binds[i] = HMM_M4D(1);
|
||||
sk.binds[i] = MAT1;
|
||||
|
||||
for (int i = 0; i < skin->joints_count; i++) {
|
||||
int offset = skin->joints[i]-cdata->nodes;
|
||||
|
@ -417,6 +412,7 @@ void model_process_node(model *model, cgltf_node *node)
|
|||
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);
|
||||
|
@ -458,8 +454,28 @@ 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->idx;
|
||||
b.fs.images[0] = p->mat->diffuse->id;
|
||||
b.fs.samplers[0] = tex_sampler;
|
||||
return b;
|
||||
}
|
||||
|
||||
void model_draw_go(model *model, gameobject *go, gameobject *cam)
|
||||
{
|
||||
HMM_Mat4 view = t3d_go2world(cam);
|
||||
HMM_Mat4 proj = HMM_Perspective_RH_NO(20, 1, 0.01, 10000);
|
||||
HMM_Mat4 vp = HMM_MulM4(proj, view);
|
||||
HMM_Mat4 gom = transform3d2mat(go2t3(go));
|
||||
|
||||
animation_run(&model->anim, apptime());
|
||||
|
||||
skin *sk = &model->skin;
|
||||
|
@ -470,34 +486,21 @@ void model_draw_go(model *model, gameobject *go, gameobject *cam)
|
|||
local = HMM_MulM4(md->parent->t, local);
|
||||
md->t = local;
|
||||
sk->binds[i] = HMM_MulM4(md->t, sk->invbind[i]);
|
||||
|
||||
//printf("TRANSLATION OF %d IS " HMMFMT_VEC3 "\n", i, HMMPRINT_VEC3(md->pos));
|
||||
}
|
||||
|
||||
HMM_Mat4 view = t3d_go2world(cam);
|
||||
HMM_Mat4 proj = HMM_Perspective_RH_NO(20, 1, 0.01, 10000);
|
||||
HMM_Mat4 vp = HMM_MulM4(proj, view);
|
||||
HMM_Mat4 gom = transform3d2mat(go2t3(go));
|
||||
|
||||
sg_apply_pipeline(model_pipe);
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, SLOT_vs_p, SG_RANGE_REF(vp.e));
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, SLOT_skinv, &(sg_range){
|
||||
/*sg_apply_uniforms(SG_SHADERSTAGE_VS, SLOT_skinv, &(sg_range){
|
||||
.ptr = sk->binds,
|
||||
.size = sizeof(*sk->binds)*50
|
||||
});
|
||||
float ambient[4] = {1.0,1.0,1.0,1.0};
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_FS, SLOT_lightf, SG_RANGE_REF(ambient));
|
||||
*/
|
||||
|
||||
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_apply_bindings(&(msh.primitives[j].bind));
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, SLOT_vmodel, &(sg_range){
|
||||
.ptr = mod.em,
|
||||
.size = sizeof(mod)
|
||||
});
|
||||
sg_draw(0, model->meshes[i].primitives[j].idx_count, 1);
|
||||
sg_bindings b = primitive_bind(msh.primitives+j);
|
||||
sg_apply_bindings(&b);
|
||||
sg_draw(0, msh.primitives[j].idx_count, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,13 @@
|
|||
#include "anim.h"
|
||||
#include "texture.h"
|
||||
|
||||
extern HMM_Vec3 eye;
|
||||
#define MAT_POS 0
|
||||
#define MAT_UV 1
|
||||
#define MAT_NORM 2
|
||||
#define MAT_BONE 3
|
||||
#define MAT_WEIGHT 4
|
||||
#define MAT_COLOR 5
|
||||
#define MAT_TAN 6
|
||||
|
||||
typedef struct material {
|
||||
texture *diffuse;
|
||||
|
@ -26,7 +32,14 @@ typedef struct material {
|
|||
struct model;
|
||||
|
||||
typedef struct primitive {
|
||||
sg_bindings bind;
|
||||
sg_buffer pos;
|
||||
sg_buffer norm;
|
||||
sg_buffer uv;
|
||||
sg_buffer bone;
|
||||
sg_buffer weight;
|
||||
sg_buffer color;
|
||||
sg_buffer idx;
|
||||
material *mat;
|
||||
uint32_t idx_count;
|
||||
} primitive;
|
||||
|
||||
|
@ -60,6 +73,7 @@ typedef struct skin {
|
|||
typedef struct model {
|
||||
struct mesh *meshes;
|
||||
md5joint *nodes;
|
||||
material *mats;
|
||||
skin skin;
|
||||
struct animation anim;
|
||||
} model;
|
||||
|
@ -70,8 +84,6 @@ void model_free(model *m);
|
|||
|
||||
void model_draw_go(model *m, gameobject *go, gameobject *cam);
|
||||
|
||||
void model_init();
|
||||
|
||||
material *material_make();
|
||||
void material_free(material *mat);
|
||||
|
||||
|
|
|
@ -221,6 +221,7 @@ typedef union HMM_Vec2 {
|
|||
};
|
||||
|
||||
float Elements[2];
|
||||
float e[2];
|
||||
|
||||
cpVect cp;
|
||||
|
||||
|
@ -279,6 +280,7 @@ typedef union HMM_Vec3 {
|
|||
};
|
||||
|
||||
float Elements[3];
|
||||
float e[3];
|
||||
|
||||
} HMM_Vec3;
|
||||
|
||||
|
@ -403,6 +405,7 @@ typedef union HMM_Mat3 {
|
|||
typedef union HMM_Mat4 {
|
||||
float Elements[4][4];
|
||||
HMM_Vec4 Columns[4];
|
||||
HMM_Vec4 col[4];
|
||||
float e[4][4];
|
||||
float em[16];
|
||||
} HMM_Mat4;
|
||||
|
@ -421,6 +424,8 @@ static const HMM_Vec3 vBKWD = {0,0,-1};
|
|||
static const HMM_Vec3 vLEFT = {-1,0,0};
|
||||
static const HMM_Vec3 vRIGHT = {1,0,0};
|
||||
|
||||
static const HMM_Mat4 MAT1 = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
|
||||
|
||||
/*
|
||||
* Angle unit conversion functions
|
||||
*/
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include <window.h>
|
||||
#include "resources.h"
|
||||
#include "debugdraw.h"
|
||||
#include "text.sglsl.h"
|
||||
#include "render.h"
|
||||
|
||||
#include "stb_image_write.h"
|
||||
|
@ -22,9 +21,7 @@
|
|||
|
||||
struct sFont *use_font;
|
||||
|
||||
static sg_shader fontshader;
|
||||
static sg_bindings bind_text;
|
||||
static sg_pipeline pipe_text;
|
||||
struct text_vert {
|
||||
struct draw_p pos;
|
||||
struct draw_p wh;
|
||||
|
@ -36,26 +33,6 @@ struct text_vert {
|
|||
static struct text_vert *text_buffer;
|
||||
|
||||
void font_init() {
|
||||
fontshader = sg_make_shader(text_shader_desc(sg_query_backend()));
|
||||
pipe_text = sg_make_pipeline(&(sg_pipeline_desc){
|
||||
.shader = fontshader,
|
||||
.layout = {
|
||||
.attrs = {
|
||||
[ATTR_vs_vert].format = SG_VERTEXFORMAT_FLOAT2,
|
||||
[ATTR_vs_vert].buffer_index = 1,
|
||||
[ATTR_vs_pos].format = SG_VERTEXFORMAT_FLOAT2,
|
||||
[ATTR_vs_wh].format = SG_VERTEXFORMAT_FLOAT2,
|
||||
[ATTR_vs_uv].format = SG_VERTEXFORMAT_USHORT2N,
|
||||
[ATTR_vs_st].format = SG_VERTEXFORMAT_USHORT2N,
|
||||
[ATTR_vs_vColor].format = SG_VERTEXFORMAT_UBYTE4N,
|
||||
},
|
||||
.buffers[0].step_func = SG_VERTEXSTEP_PER_INSTANCE
|
||||
},
|
||||
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
|
||||
.colors[0].blend = blend_trans,
|
||||
.label = "text",
|
||||
});
|
||||
|
||||
bind_text.vertex_buffers[1] = sprite_quad;
|
||||
|
||||
bind_text.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
|
||||
|
@ -201,7 +178,7 @@ void draw_char_box(struct Character c, HMM_Vec2 cursor, float scale, struct rgba
|
|||
draw_box(b, wh, color);
|
||||
}
|
||||
|
||||
void text_flush(HMM_Mat4 *proj) {
|
||||
void text_flush() {
|
||||
if (arrlen(text_buffer) == 0) return;
|
||||
|
||||
sg_range verts;
|
||||
|
@ -217,9 +194,7 @@ void text_flush(HMM_Mat4 *proj) {
|
|||
|
||||
sg_append_buffer(bind_text.vertex_buffers[0], &verts);
|
||||
|
||||
sg_apply_pipeline(pipe_text);
|
||||
sg_apply_bindings(&bind_text);
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(*proj));
|
||||
sg_draw(0, 4, arrlen(text_buffer));
|
||||
arrsetlen(text_buffer, 0);
|
||||
}
|
||||
|
@ -377,7 +352,7 @@ int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, f
|
|||
if (*wordstart == '\e')
|
||||
wordstart = esc_color(wordstart, &usecolor, color);
|
||||
|
||||
sdrawCharacter(use_font->Characters[*wordstart], HMM_AddV2(cursor, HMM_MulV2F((HMM_Vec2){1,-1},scale)), scale, (rgba){0,0,0,255});
|
||||
//sdrawCharacter(use_font->Characters[*wordstart], HMM_AddV2(cursor, HMM_MulV2F((HMM_Vec2){1,-1},scale)), scale, (rgba){0,0,0,255});
|
||||
sdrawCharacter(use_font->Characters[*wordstart], cursor, scale, usecolor);
|
||||
|
||||
cursor.X += use_font->Characters[*wordstart].Advance * tracking * scale;
|
||||
|
|
|
@ -40,7 +40,6 @@ void text_settype(struct sFont *font);
|
|||
struct boundingbox text_bb(const char *text, float scale, float lw, float tracking);
|
||||
int renderText(const char *text, HMM_Vec2 pos, float scale, struct rgba color, float lw, int caret, float tracking);
|
||||
|
||||
// void text_frame();
|
||||
void text_flush(HMM_Mat4 *proj);
|
||||
void text_flush();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -204,9 +204,3 @@ HMM_Vec3 go_pos3d(gameobject *go)
|
|||
HMM_Vec2 pos2d = go_pos(go);
|
||||
return (HMM_Vec3){pos2d.x, pos2d.y, go->drawlayer};
|
||||
}
|
||||
|
||||
void gameobject_draw_debug(gameobject *go) {
|
||||
if (!go || !go->body) return;
|
||||
|
||||
cpBodyEachShape(go->body, body_draw_shapes_dbg, NULL);
|
||||
}
|
||||
|
|
|
@ -61,7 +61,10 @@ const char *js2str(JSValue v) {
|
|||
return JS_ToCString(js, v);
|
||||
}
|
||||
|
||||
void jsfreestr(const char *s) { JS_FreeCString(js, s); }
|
||||
QJSCLASS(gameobject)
|
||||
QJSCLASS(transform3d)
|
||||
QJSCLASS(transform2d)
|
||||
QJSCLASS(emitter)
|
||||
QJSCLASS(dsp_node)
|
||||
QJSCLASS(texture)
|
||||
|
@ -140,6 +143,7 @@ JSValue ptr2js(void *ptr) {
|
|||
}
|
||||
|
||||
int js_arrlen(JSValue v) {
|
||||
if (JS_IsUndefined(v)) return 0;
|
||||
int len;
|
||||
JS_ToInt32(js, &len, js_getpropstr( v, "length"));
|
||||
return len;
|
||||
|
@ -331,6 +335,22 @@ JSValue vec32js(HMM_Vec3 v)
|
|||
return array;
|
||||
}
|
||||
|
||||
HMM_Vec4 js2vec4(JSValue v)
|
||||
{
|
||||
HMM_Vec4 v4;
|
||||
for (int i = 0; i < 4; i++)
|
||||
v4.e[i] = js2number(js_getpropidx(v,i));
|
||||
return v4;
|
||||
}
|
||||
|
||||
JSValue vec42js(HMM_Vec4 v)
|
||||
{
|
||||
JSValue array = JS_NewArray(js);
|
||||
for (int i = 0; i < 4; i++)
|
||||
js_setprop_num(array,i,number2js(v.e[i]));
|
||||
return array;
|
||||
}
|
||||
|
||||
cpBitmask js2bitmask(JSValue v) {
|
||||
cpBitmask a;
|
||||
JS_ToUint32(js, &a, v);
|
||||
|
@ -605,7 +625,10 @@ JSC_CCALL(render_line3d,
|
|||
);
|
||||
|
||||
JSC_CCALL(render_emitters, emitters_draw(&useproj))
|
||||
JSC_CCALL(render_flush, debug_flush(&useproj); text_flush(&useproj); )
|
||||
JSC_CCALL(render_flush, debug_flush(&useproj); )
|
||||
|
||||
JSC_CCALL(render_flushtext, text_flush())
|
||||
|
||||
JSC_CCALL(render_end_pass,
|
||||
sg_end_pass();
|
||||
sg_commit();
|
||||
|
@ -623,8 +646,199 @@ JSC_CCALL(render_clear_color,
|
|||
pass_action.colors[0].clear_value = c;
|
||||
)
|
||||
|
||||
JSC_CCALL(render_set_sprite_tex, sprite_tex(js2texture(argv[0])))
|
||||
JSC_CCALL(render_sprite_flush, sprite_flush())
|
||||
sg_shader js2shader(JSValue v)
|
||||
{
|
||||
sg_shader_desc desc = {0};
|
||||
JSValue prog = v;
|
||||
JSValue vs = js_getpropstr(prog, "vs");
|
||||
JSValue fs = js_getpropstr(prog, "fs");
|
||||
char *vsf = js2str(js_getpropstr(vs, "code"));
|
||||
char *fsf = js2str(js_getpropstr(fs, "code"));
|
||||
desc.vs.source = vsf;
|
||||
desc.fs.source = fsf;
|
||||
char *vsmain = js2str(js_getpropstr(vs, "entry_point"));
|
||||
char *fsmain = js2str(js_getpropstr(fs, "entry_point"));
|
||||
desc.vs.entry = vsmain;
|
||||
desc.fs.entry = fsmain;
|
||||
JSValue vsu = js_getpropstr(vs, "uniform_blocks");
|
||||
int unin = js_arrlen(vsu);
|
||||
for (int i = 0; i < unin; i++) {
|
||||
JSValue u = js_getpropidx(vsu, i);
|
||||
int slot = js2number(js_getpropstr(u, "slot"));
|
||||
desc.vs.uniform_blocks[slot].size = js2number(js_getpropstr(u, "size"));
|
||||
desc.vs.uniform_blocks[slot].layout = SG_UNIFORMLAYOUT_STD140;
|
||||
}
|
||||
|
||||
JSValue fsu = js_getpropstr(fs, "uniform_blocks");
|
||||
unin = js_arrlen(fsu);
|
||||
for (int i = 0; i < unin; i++) {
|
||||
JSValue u = js_getpropidx(fsu, i);
|
||||
int slot = js2number(js_getpropstr(u, "slot"));
|
||||
desc.fs.uniform_blocks[slot].size = js2number(js_getpropstr(u, "size"));
|
||||
desc.fs.uniform_blocks[slot].layout = SG_UNIFORMLAYOUT_STD140;
|
||||
}
|
||||
|
||||
JSValue imgs = js_getpropstr(fs, "images");
|
||||
unin = js_arrlen(imgs);
|
||||
for (int i = 0; i < unin; i++) {
|
||||
JSValue u = js_getpropidx(imgs, i);
|
||||
int slot = js2number(js_getpropstr(u, "slot"));
|
||||
desc.fs.images[i].used = true;
|
||||
desc.fs.images[i].multisampled = js2boolean(js_getpropstr(u, "multisampled"));
|
||||
desc.fs.images[i].image_type = SG_IMAGETYPE_2D;
|
||||
desc.fs.images[i].sample_type = SG_IMAGESAMPLETYPE_FLOAT;
|
||||
}
|
||||
|
||||
JSValue samps = js_getpropstr(fs, "samplers");
|
||||
unin = js_arrlen(samps);
|
||||
for (int i = 0; i < unin; i++) {
|
||||
desc.fs.samplers[0].used = true;
|
||||
desc.fs.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING;
|
||||
}
|
||||
|
||||
JSValue pairs = js_getpropstr(fs, "image_sampler_pairs");
|
||||
unin = js_arrlen(pairs);
|
||||
for (int i = 0; i < unin; i++) {
|
||||
desc.fs.image_sampler_pairs[0].used = true;
|
||||
desc.fs.image_sampler_pairs[0].image_slot = 0;
|
||||
desc.fs.image_sampler_pairs[0].sampler_slot = 0;
|
||||
}
|
||||
|
||||
sg_shader sh = sg_make_shader(&desc);
|
||||
|
||||
jsfreestr(vsf);
|
||||
jsfreestr(fsf);
|
||||
jsfreestr(vsmain);
|
||||
jsfreestr(fsmain);
|
||||
|
||||
return sh;
|
||||
}
|
||||
|
||||
JSC_CCALL(render_pipeline3d,
|
||||
sg_shader sgshader = js2shader(argv[0]);
|
||||
sg_pipeline_desc p = {0};
|
||||
p.shader = sgshader;
|
||||
sg_vertex_layout_state st = {0};
|
||||
st.attrs[MAT_POS].format = SG_VERTEXFORMAT_FLOAT3;
|
||||
st.attrs[MAT_UV].format = SG_VERTEXFORMAT_USHORT2N;
|
||||
st.attrs[MAT_UV].buffer_index = MAT_UV;
|
||||
st.attrs[MAT_NORM].format = SG_VERTEXFORMAT_UINT10_N2;
|
||||
st.attrs[MAT_NORM].buffer_index = MAT_NORM;
|
||||
st.attrs[MAT_WEIGHT].format = SG_VERTEXFORMAT_UBYTE4N;
|
||||
st.attrs[MAT_WEIGHT].buffer_index = MAT_WEIGHT;
|
||||
st.attrs[MAT_BONE].format = SG_VERTEXFORMAT_UBYTE4;
|
||||
st.attrs[MAT_BONE].buffer_index = MAT_BONE;
|
||||
st.attrs[MAT_COLOR].format = SG_VERTEXFORMAT_UBYTE4N;
|
||||
st.attrs[MAT_COLOR].buffer_index = MAT_COLOR;
|
||||
p.layout = st;
|
||||
p.index_type = SG_INDEXTYPE_UINT16;
|
||||
p.depth.write_enabled = true;
|
||||
p.depth.compare = SG_COMPAREFUNC_LESS_EQUAL;
|
||||
p.cull_mode = SG_CULLMODE_FRONT;
|
||||
|
||||
sg_pipeline pipe = sg_make_pipeline(&p);
|
||||
return number2js(pipe.id);
|
||||
)
|
||||
|
||||
JSC_CCALL(render_pipelinetext,
|
||||
sg_shader fontshader = js2shader(argv[0]);
|
||||
sg_pipeline_desc p = {0};
|
||||
p.shader = fontshader;
|
||||
sg_vertex_layout_state st = {0};
|
||||
st.attrs[0].format = SG_VERTEXFORMAT_FLOAT2;
|
||||
st.attrs[0].buffer_index = 1;
|
||||
st.attrs[1].format = SG_VERTEXFORMAT_FLOAT2;
|
||||
st.attrs[2].format = SG_VERTEXFORMAT_FLOAT2;
|
||||
st.attrs[3].format = SG_VERTEXFORMAT_USHORT2N;
|
||||
st.attrs[4].format = SG_VERTEXFORMAT_USHORT2N;
|
||||
st.attrs[5].format = SG_VERTEXFORMAT_UBYTE4N;
|
||||
st.buffers[0].step_func = SG_VERTEXSTEP_PER_INSTANCE;
|
||||
p.layout = st;
|
||||
p.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP;
|
||||
p.colors[0].blend = blend_trans;
|
||||
|
||||
sg_pipeline pipe = sg_make_pipeline(&p);
|
||||
return number2js(pipe.id);
|
||||
)
|
||||
|
||||
JSC_CCALL(render_pipeline,
|
||||
sg_shader sgshader = js2shader(argv[0]);
|
||||
|
||||
sg_pipeline_desc pdesc = {0};
|
||||
pdesc.shader = sgshader;
|
||||
pdesc.cull_mode = SG_CULLMODE_FRONT;
|
||||
|
||||
pdesc.layout.attrs[0].format = SG_VERTEXFORMAT_FLOAT2;
|
||||
pdesc.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP;
|
||||
if (js2boolean(js_getpropstr(argv[0], "blend")))
|
||||
pdesc.colors[0].blend = blend_trans;
|
||||
|
||||
sg_pipeline pipe = sg_make_pipeline(&pdesc);
|
||||
|
||||
return number2js(pipe.id);
|
||||
)
|
||||
|
||||
JSC_CCALL(render_setuniv,
|
||||
float f = js2number(argv[2]);
|
||||
sg_apply_uniforms(js2number(argv[0]), js2number(argv[1]), SG_RANGE_REF(f));
|
||||
)
|
||||
|
||||
JSC_CCALL(render_setuniv2,
|
||||
HMM_Vec2 v = js2vec2(argv[2]);
|
||||
sg_apply_uniforms(js2number(argv[0]), js2number(argv[1]), SG_RANGE_REF(v.e));
|
||||
)
|
||||
|
||||
JSC_CCALL(render_setuniv3,
|
||||
HMM_Vec3 v = js2vec3(argv[2]);
|
||||
sg_apply_uniforms(js2number(argv[0]), js2number(argv[1]), SG_RANGE_REF(v.e));
|
||||
)
|
||||
|
||||
JSC_CCALL(render_setuniv4,
|
||||
HMM_Vec4 v = js2vec4(argv[2]);
|
||||
sg_apply_uniforms(js2number(argv[0]), js2number(argv[1]), SG_RANGE_REF(v.e));
|
||||
)
|
||||
|
||||
JSC_CCALL(render_setuniproj,
|
||||
sg_apply_uniforms(js2number(argv[0]), js2number(argv[1]), SG_RANGE_REF(useproj));
|
||||
)
|
||||
|
||||
JSC_CCALL(render_setunim4,
|
||||
HMM_Mat4 m = MAT1;
|
||||
if (JS_IsArray(js, argv[2])) {
|
||||
JSValue arr = argv[2];
|
||||
int n = js_arrlen(arr);
|
||||
if (n == 1)
|
||||
m = transform2d2mat4(js2transform2d(js_getpropidx(arr,0)));
|
||||
else {
|
||||
for (int i = 0; i < n; i++) {
|
||||
HMM_Mat4 p = transform2d2mat4(js2transform2d(js_getpropidx(arr, i)));
|
||||
m = HMM_MulM4(p,m);
|
||||
}
|
||||
}
|
||||
} else
|
||||
m = transform2d2mat4(js2transform2d(argv[2]));
|
||||
|
||||
sg_apply_uniforms(js2number(argv[0]), js2number(argv[1]), SG_RANGE_REF(m.e));
|
||||
);
|
||||
|
||||
JSC_CCALL(render_spdraw,
|
||||
sg_bindings bind = {0};
|
||||
bind.vertex_buffers[0] = sprite_quad;
|
||||
|
||||
for (int i = 0; i < js_arrlen(argv[0]); i++) {
|
||||
bind.fs.images[i] = js2texture(js_getpropidx(argv[0], i))->id;
|
||||
bind.fs.samplers[i] = std_sampler;
|
||||
}
|
||||
|
||||
sg_apply_bindings(&bind);
|
||||
sg_draw(0,4,1);
|
||||
)
|
||||
|
||||
JSC_CCALL(render_setpipeline,
|
||||
sg_pipeline p = {0};
|
||||
p.id = js2number(argv[0]);
|
||||
sg_apply_pipeline(p);
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_render_funcs[] = {
|
||||
MIST_FUNC_DEF(render, grid, 3),
|
||||
|
@ -634,14 +848,24 @@ static const JSCFunctionListEntry js_render_funcs[] = {
|
|||
MIST_FUNC_DEF(render, line, 3),
|
||||
MIST_FUNC_DEF(render, line3d, 2),
|
||||
MIST_FUNC_DEF(render, emitters, 0),
|
||||
MIST_FUNC_DEF(render, flushtext, 0),
|
||||
MIST_FUNC_DEF(render, flush, 0),
|
||||
MIST_FUNC_DEF(render, end_pass, 0),
|
||||
MIST_FUNC_DEF(render, text_size, 3),
|
||||
MIST_FUNC_DEF(render, set_camera, 0),
|
||||
MIST_FUNC_DEF(render, hud_res, 1),
|
||||
MIST_FUNC_DEF(render, clear_color, 1),
|
||||
MIST_FUNC_DEF(render, set_sprite_tex, 1),
|
||||
MIST_FUNC_DEF(render, sprite_flush, 0),
|
||||
MIST_FUNC_DEF(render, pipeline, 1),
|
||||
MIST_FUNC_DEF(render, pipeline3d, 1),
|
||||
MIST_FUNC_DEF(render, pipelinetext, 1),
|
||||
MIST_FUNC_DEF(render, setuniv3, 2),
|
||||
MIST_FUNC_DEF(render, setuniv, 2),
|
||||
MIST_FUNC_DEF(render, spdraw, 2),
|
||||
MIST_FUNC_DEF(render, setuniproj, 2),
|
||||
MIST_FUNC_DEF(render, setunim4, 3),
|
||||
MIST_FUNC_DEF(render, setuniv2, 2),
|
||||
MIST_FUNC_DEF(render, setuniv4, 2),
|
||||
MIST_FUNC_DEF(render, setpipeline, 1)
|
||||
};
|
||||
|
||||
JSC_CCALL(gui_flush, text_flush(&useproj));
|
||||
|
@ -659,21 +883,12 @@ JSC_CCALL(gui_text,
|
|||
return ret;
|
||||
)
|
||||
|
||||
JSC_CCALL(gui_img,
|
||||
transform2d t;
|
||||
t.pos = js2vec2(argv[1]);
|
||||
t.scale = js2vec2(argv[2]);
|
||||
t.angle = js2number(argv[3]);
|
||||
gui_draw_img(js2texture(argv[0]), t, js2boolean(argv[4]), js2vec2(argv[5]), 1.0, js2color(argv[6]));
|
||||
)
|
||||
|
||||
JSC_CCALL(gui_font_set, font_set(js2font(argv[0])))
|
||||
|
||||
static const JSCFunctionListEntry js_gui_funcs[] = {
|
||||
MIST_FUNC_DEF(gui, flush, 0),
|
||||
MIST_FUNC_DEF(gui, scissor, 4),
|
||||
MIST_FUNC_DEF(gui, text, 6),
|
||||
MIST_FUNC_DEF(gui, img, 7),
|
||||
MIST_FUNC_DEF(gui, font_set,1)
|
||||
};
|
||||
|
||||
|
@ -745,7 +960,7 @@ static const JSCFunctionListEntry js_input_funcs[] = {
|
|||
|
||||
JSC_CCALL(prosperon_emitters_step, emitters_step(js2number(argv[0])))
|
||||
JSC_CCALL(prosperon_phys2d_step, phys2d_update(js2number(argv[0])))
|
||||
JSC_CCALL(prosperon_window_render, openglRender(&mainwin, js2gameobject(argv[0]), js2number(argv[1])))
|
||||
JSC_CCALL(prosperon_window_render, openglRender(&mainwin, js2transform2d(argv[0]), js2number(argv[1])))
|
||||
JSC_CCALL(prosperon_guid,
|
||||
uint8_t bytes[16];
|
||||
for (int i = 0; i < 16; i++) bytes[i] = rand()%256;
|
||||
|
@ -893,6 +1108,7 @@ JSC_SCALL(io_save_qoa, save_qoa(str))
|
|||
JSC_SCALL(io_pack_start, pack_start(str))
|
||||
JSC_SCALL(io_pack_add, pack_add(str))
|
||||
JSC_CCALL(io_pack_end, pack_end())
|
||||
JSC_SCALL(io_mod, ret = number2js(file_mod_secs(str));)
|
||||
|
||||
static const JSCFunctionListEntry js_io_funcs[] = {
|
||||
MIST_FUNC_DEF(io, exists,1),
|
||||
|
@ -909,11 +1125,10 @@ static const JSCFunctionListEntry js_io_funcs[] = {
|
|||
MIST_FUNC_DEF(io, save_qoa,1),
|
||||
MIST_FUNC_DEF(io, pack_start, 1),
|
||||
MIST_FUNC_DEF(io, pack_add, 1),
|
||||
MIST_FUNC_DEF(io, pack_end, 0)
|
||||
MIST_FUNC_DEF(io, pack_end, 0),
|
||||
MIST_FUNC_DEF(io, mod,1)
|
||||
};
|
||||
|
||||
JSC_CCALL(debug_draw_gameobject, gameobject_draw_debug(js2gameobject(argv[0]));)
|
||||
|
||||
JSC_GETSET_GLOBAL(disabled_color, color)
|
||||
JSC_GETSET_GLOBAL(sleep_color, color)
|
||||
JSC_GETSET_GLOBAL(dynamic_color, color)
|
||||
|
@ -921,7 +1136,6 @@ JSC_GETSET_GLOBAL(kinematic_color, color)
|
|||
JSC_GETSET_GLOBAL(static_color, color)
|
||||
|
||||
static const JSCFunctionListEntry js_debug_funcs[] = {
|
||||
MIST_FUNC_DEF(debug, draw_gameobject, 1),
|
||||
CGETSET_ADD(global, disabled_color),
|
||||
CGETSET_ADD(global, sleep_color),
|
||||
CGETSET_ADD(global, dynamic_color),
|
||||
|
@ -1033,6 +1247,8 @@ static const JSCFunctionListEntry js_physics_funcs[] = {
|
|||
MIST_FUNC_DEF(physics, make_gravity, 0),
|
||||
};
|
||||
|
||||
|
||||
|
||||
JSC_CCALL(model_draw_go,
|
||||
model_draw_go(js2model(this), js2gameobject(argv[0]), js2gameobject(argv[1]))
|
||||
);
|
||||
|
@ -1065,6 +1281,16 @@ static const JSCFunctionListEntry js_emitter_funcs[] = {
|
|||
CGETSET_ADD(emitter, texture),
|
||||
};
|
||||
|
||||
JSC_GETSET(transform2d, pos, vec2)
|
||||
JSC_GETSET(transform2d, scale, vec2)
|
||||
JSC_GETSET(transform2d, angle, number)
|
||||
|
||||
static const JSCFunctionListEntry js_transform2d_funcs[] = {
|
||||
CGETSET_ADD(transform2d, pos),
|
||||
CGETSET_ADD(transform2d, scale),
|
||||
CGETSET_ADD(transform2d, angle)
|
||||
};
|
||||
|
||||
JSC_GETSET(dsp_node, pass, boolean)
|
||||
JSC_GETSET(dsp_node, off, boolean)
|
||||
JSC_GETSET(dsp_node, gain, number)
|
||||
|
@ -1317,22 +1543,12 @@ static const JSCFunctionListEntry js_pshape_funcs[] = {
|
|||
|
||||
JSC_GETSET(sprite, color, color)
|
||||
JSC_GETSET(sprite, emissive, color)
|
||||
JSC_GETSET(sprite, pos, vec2)
|
||||
JSC_GETSET(sprite, scale, vec2)
|
||||
JSC_GETSET(sprite, angle, number)
|
||||
JSC_GETSET(sprite, spriteoffset, vec2)
|
||||
JSC_GETSET(sprite, spritesize, vec2)
|
||||
JSC_CCALL(sprite_draw, sprite_draw(js2sprite(this), js2gameobject(argv[0])))
|
||||
|
||||
static const JSCFunctionListEntry js_sprite_funcs[] = {
|
||||
CGETSET_ADD(sprite,pos),
|
||||
CGETSET_ADD(sprite,scale),
|
||||
CGETSET_ADD(sprite,angle),
|
||||
CGETSET_ADD(sprite,color),
|
||||
CGETSET_ADD(sprite,emissive),
|
||||
CGETSET_ADD(sprite, spriteoffset),
|
||||
CGETSET_ADD(sprite, spritesize),
|
||||
MIST_FUNC_DEF(sprite, draw, 1)
|
||||
};
|
||||
|
||||
JSC_GET(texture, width, number)
|
||||
|
@ -1536,11 +1752,22 @@ JSC_SCALL(os_make_texture,
|
|||
|
||||
JSC_CCALL(os_make_font, return font2js(MakeFont(js2str(argv[0]), js2number(argv[1]))))
|
||||
|
||||
JSC_SCALL(os_system, system(str); )
|
||||
JSC_CCALL(os_make_transform2d,
|
||||
if (JS_IsUndefined(argv[0]))
|
||||
return transform2d2js(make_transform2d());
|
||||
|
||||
int n = js2number(argv[0]);
|
||||
transform2d *t = calloc(sizeof(transform2d), n);
|
||||
JSValue arr = JS_NewArray(js);
|
||||
for (int i = 0; i < n; i++)
|
||||
js_setprop_num(arr, i, transform2d2js(t+i));
|
||||
|
||||
return arr;
|
||||
)
|
||||
|
||||
JSC_SCALL(os_make_model, return model2js(model_make(str)))
|
||||
JSC_SCALL(os_system, return number2js(system(str)); )
|
||||
|
||||
JSC_CCALL(os_sprite_pipe, sprite_pipe())
|
||||
JSC_SCALL(os_make_model, ret = model2js(model_make(str)))
|
||||
|
||||
static const JSCFunctionListEntry js_os_funcs[] = {
|
||||
MIST_FUNC_DEF(os,sprite,1),
|
||||
|
@ -1561,7 +1788,7 @@ static const JSCFunctionListEntry js_os_funcs[] = {
|
|||
MIST_FUNC_DEF(os, make_texture, 1),
|
||||
MIST_FUNC_DEF(os, make_font, 2),
|
||||
MIST_FUNC_DEF(os, make_model, 1),
|
||||
MIST_FUNC_DEF(os, sprite_pipe, 0)
|
||||
MIST_FUNC_DEF(os, make_transform2d, 1),
|
||||
};
|
||||
|
||||
#include "steam.h"
|
||||
|
@ -1570,10 +1797,13 @@ void ffi_load() {
|
|||
globalThis = JS_GetGlobalObject(js);
|
||||
|
||||
QJSCLASSPREP(ptr);
|
||||
QJSCLASSPREP(transform3d);
|
||||
|
||||
|
||||
QJSGLOBALCLASS(os);
|
||||
|
||||
QJSCLASSPREP_FUNCS(gameobject);
|
||||
QJSCLASSPREP_FUNCS(transform2d);
|
||||
QJSCLASSPREP_FUNCS(dsp_node);
|
||||
QJSCLASSPREP_FUNCS(emitter);
|
||||
QJSCLASSPREP_FUNCS(warp_gravity);
|
||||
|
|
|
@ -135,4 +135,9 @@ JSValue str2js(const char *c, ...);
|
|||
|
||||
void nota_int(char *blob);
|
||||
|
||||
JSValue js_getpropidx(JSValue v, uint32_t i);
|
||||
JSValue js_getpropstr(JSValue v, const char *str);
|
||||
const char *js2str(JSValue v);
|
||||
void jsfreestr(const char *str);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,6 +33,7 @@ float camzoom = 1;
|
|||
|
||||
sg_buffer sprite_quad;
|
||||
sg_sampler std_sampler;
|
||||
sg_sampler tex_sampler;
|
||||
|
||||
static struct {
|
||||
sg_swapchain swap;
|
||||
|
@ -242,6 +243,13 @@ void render_init() {
|
|||
});
|
||||
|
||||
std_sampler = sg_make_sampler(&(sg_sampler_desc){});
|
||||
tex_sampler = sg_make_sampler(&(sg_sampler_desc){
|
||||
.min_filter = SG_FILTER_LINEAR,
|
||||
.mag_filter = SG_FILTER_LINEAR,
|
||||
.mipmap_filter = SG_FILTER_LINEAR,
|
||||
.wrap_u = SG_WRAP_REPEAT,
|
||||
.wrap_v = SG_WRAP_REPEAT
|
||||
});
|
||||
|
||||
#ifndef NDEBUG
|
||||
sg_trace_hooks hh = sg_install_trace_hooks(&hooks);
|
||||
|
@ -249,10 +257,7 @@ void render_init() {
|
|||
|
||||
font_init();
|
||||
debugdraw_init();
|
||||
sprite_initialize();
|
||||
|
||||
model_init();
|
||||
|
||||
sg_color c = (sg_color){0,0,0,1};
|
||||
pass_action = (sg_pass_action){
|
||||
.colors[0] = {.load_action = SG_LOADACTION_CLEAR, .clear_value = c},
|
||||
|
@ -289,7 +294,10 @@ void render_init() {
|
|||
1, -1, 1, 0,
|
||||
1, 1, 1, 1
|
||||
};
|
||||
|
||||
|
||||
sg_limits ll = sg_query_limits();
|
||||
printf("attribute limits %d\n", ll.max_vertex_attrs);
|
||||
|
||||
sg_gif.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = sizeof(gif_quad),
|
||||
.data = gif_quad,
|
||||
|
@ -330,7 +338,7 @@ HMM_Mat4 useproj = {0};
|
|||
#define MODE_EXPAND 4
|
||||
#define MODE_FULL 5
|
||||
|
||||
void openglRender(struct window *window, gameobject *cam, float zoom) {
|
||||
void openglRender(struct window *window, transform2d *cam, float zoom) {
|
||||
sg_swapchain sch = sglue_swapchain();
|
||||
sg_begin_pass(&(sg_pass){
|
||||
.action = pass_action,
|
||||
|
@ -365,7 +373,7 @@ void openglRender(struct window *window, gameobject *cam, float zoom) {
|
|||
}
|
||||
|
||||
// 2D projection
|
||||
campos = go_pos(cam);
|
||||
campos = cam->pos;
|
||||
camzoom = zoom;
|
||||
|
||||
projection = HMM_Orthographic_RH_NO(
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "sokol/sokol_gfx.h"
|
||||
#include "HandmadeMath.h"
|
||||
#include "gameobject.h"
|
||||
#include "transform.h"
|
||||
|
||||
#define RGBA_MAX 255
|
||||
|
||||
|
@ -34,6 +35,7 @@ extern sg_pass_action pass_action;
|
|||
|
||||
extern sg_buffer sprite_quad;
|
||||
extern sg_sampler std_sampler;
|
||||
extern sg_sampler tex_sampler;
|
||||
|
||||
struct draw_p {
|
||||
float x;
|
||||
|
@ -60,7 +62,7 @@ void render_init();
|
|||
extern HMM_Vec2 campos;
|
||||
extern float camzoom;
|
||||
|
||||
void openglRender(struct window *window, gameobject *cam, float zoom);
|
||||
void openglRender(struct window *window, transform2d *cam, float zoom);
|
||||
void opengl_rendermode(enum RenderMode r);
|
||||
|
||||
void openglInit3d(struct window *window);
|
||||
|
|
|
@ -126,6 +126,17 @@ char *dirname(const char *path)
|
|||
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, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
|
|
@ -11,7 +11,8 @@ extern int LOADED_GAME;
|
|||
|
||||
void resources_init();
|
||||
char *get_filename_from_path(char *path, int extension);
|
||||
char *get_directory_from_path(char *path);
|
||||
char *dirname(const char *path);
|
||||
char *makepath(char *dir, char *file);
|
||||
char *str_replace_ext(const char *s, const char *newext);
|
||||
FILE *res_open(char *path, const char *tag);
|
||||
char **ls(const char *path);
|
||||
|
@ -22,8 +23,6 @@ void pack_start(const char *name);
|
|||
void pack_add(const char *path);
|
||||
void pack_end();
|
||||
|
||||
char *dirname(const char *path);
|
||||
|
||||
void *slurp_file(const char *filename, size_t *size);
|
||||
char *slurp_text(const char *filename, size_t *size);
|
||||
int slurp_write(const char *txt, const char *filename, size_t len);
|
||||
|
|
|
@ -7,182 +7,13 @@
|
|||
#include "texture.h"
|
||||
#include "HandmadeMath.h"
|
||||
|
||||
#include "sprite.sglsl.h"
|
||||
#include "9slice.sglsl.h"
|
||||
|
||||
static sg_shader shader_sprite;
|
||||
static sg_pipeline pip_sprite;
|
||||
sg_bindings bind_sprite;
|
||||
|
||||
static sg_shader slice9_shader;
|
||||
static sg_pipeline slice9_pipe;
|
||||
static sg_bindings slice9_bind;
|
||||
|
||||
struct slice9_vert {
|
||||
HMM_Vec2 pos;
|
||||
struct uv_n uv;
|
||||
unsigned short border[4];
|
||||
HMM_Vec2 scale;
|
||||
struct rgba color;
|
||||
};
|
||||
|
||||
sprite *sprite_make()
|
||||
{
|
||||
sprite *sp = calloc(sizeof(*sp), 1);
|
||||
sp->pos = v2zero;
|
||||
sp->scale = v2one;
|
||||
sp->angle = 0;
|
||||
sp->color = color_white;
|
||||
sp->emissive = color_clear;
|
||||
sp->spritesize = v2one;
|
||||
sp->spriteoffset = v2zero;
|
||||
sp->rect = (HMM_Vec4){0,0,1,1};
|
||||
return sp;
|
||||
}
|
||||
|
||||
void sprite_free(sprite *sprite) { free(sprite); }
|
||||
|
||||
static texture *loadedtex;
|
||||
static int sprite_count = 0;
|
||||
|
||||
void sprite_flush() {
|
||||
return;
|
||||
if (!loadedtex) return;
|
||||
/*
|
||||
int flushed = arrlen(spverts)/4;
|
||||
sg_apply_bindings(&bind_sprite);
|
||||
sg_range data = (sg_range){
|
||||
.ptr = spverts,
|
||||
.size = sizeof(sprite_vert)*arrlen(spverts)
|
||||
};
|
||||
if (sg_query_buffer_will_overflow(bind_sprite.vertex_buffers[0], data.size))
|
||||
bind_sprite.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = data.size,
|
||||
.type = SG_BUFFERTYPE_VERTEXBUFFER,
|
||||
.usage = SG_USAGE_STREAM,
|
||||
.label = "sprite vertex buffer"
|
||||
});
|
||||
|
||||
sg_update_buffer(bind_sprite.vertex_buffers[0], &data);
|
||||
|
||||
sg_draw(sprite_count * 4, 4, flushed);
|
||||
sprite_count += flushed;
|
||||
*/
|
||||
}
|
||||
|
||||
void sprite_initialize() {
|
||||
shader_sprite = sg_make_shader(sprite_shader_desc(sg_query_backend()));
|
||||
|
||||
pip_sprite = sg_make_pipeline(&(sg_pipeline_desc){
|
||||
.shader = shader_sprite,
|
||||
.layout = {
|
||||
.attrs = {
|
||||
[0].format = SG_VERTEXFORMAT_FLOAT2
|
||||
},
|
||||
},
|
||||
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
|
||||
.label = "sprite pipeline",
|
||||
.colors[0].blend = blend_trans,
|
||||
});
|
||||
|
||||
bind_sprite.vertex_buffers[0] = sprite_quad;
|
||||
bind_sprite.fs.samplers[0] = std_sampler;
|
||||
|
||||
slice9_shader = sg_make_shader(slice9_shader_desc(sg_query_backend()));
|
||||
|
||||
slice9_pipe = sg_make_pipeline(&(sg_pipeline_desc){
|
||||
.shader = slice9_shader,
|
||||
.layout = {
|
||||
.attrs = {
|
||||
[0].format = SG_VERTEXFORMAT_FLOAT2,
|
||||
[1].format = SG_VERTEXFORMAT_FLOAT2,
|
||||
[2].format = SG_VERTEXFORMAT_USHORT4N,
|
||||
[3].format = SG_VERTEXFORMAT_FLOAT2,
|
||||
[4].format = SG_VERTEXFORMAT_UBYTE4N
|
||||
}},
|
||||
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
|
||||
});
|
||||
|
||||
slice9_bind.vertex_buffers[0] = sprite_quad;
|
||||
}
|
||||
|
||||
void sprite_pipe()
|
||||
{
|
||||
sg_apply_pipeline(pip_sprite);
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, SLOT_vp, SG_RANGE_REF(useproj));
|
||||
sg_apply_bindings(&bind_sprite);
|
||||
}
|
||||
|
||||
void tex_draw(HMM_Mat3 m, struct rect r, struct rgba color, int wrap, HMM_Vec2 wrapoffset, HMM_Vec2 wrapscale, struct rgba emissive) {
|
||||
/*
|
||||
struct sprite_vert verts[4];
|
||||
float w = loadedtex->width*r.w;
|
||||
float h = loadedtex->height*r.h;
|
||||
|
||||
HMM_Vec2 sposes[4] = {
|
||||
{0,0},
|
||||
{w,0},
|
||||
{0,h},
|
||||
{w,h}
|
||||
};
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
verts[i].pos = mat_t_pos(m, sposes[i]);
|
||||
|
||||
if (wrap) {
|
||||
r.w *= wrapscale.x;
|
||||
r.h *= wrapscale.y;
|
||||
}
|
||||
|
||||
verts[0].uv.X = r.x;
|
||||
verts[0].uv.Y = r.y+r.h;
|
||||
verts[1].uv.X = r.x+r.w;
|
||||
verts[1].uv.Y = r.y+r.h;
|
||||
verts[2].uv.X = r.x;
|
||||
verts[2].uv.Y = r.y;
|
||||
verts[3].uv.X = r.x+r.w;
|
||||
verts[3].uv.Y = r.y;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
arrput(spverts, verts[i]);
|
||||
*/
|
||||
}
|
||||
|
||||
transform2d sprite2t(sprite *s)
|
||||
{
|
||||
return (transform2d){
|
||||
.pos = s->pos,
|
||||
.scale = HMM_MulV2(s->scale, (HMM_Vec2){loadedtex->width, loadedtex->height}),
|
||||
.angle = HMM_TurnToRad*s->angle
|
||||
};
|
||||
}
|
||||
|
||||
void sprite_tex(texture *t)
|
||||
{
|
||||
loadedtex = t;
|
||||
bind_sprite.fs.images[0] = t->id;
|
||||
}
|
||||
|
||||
void sprite_draw(struct sprite *sprite, gameobject *go) {
|
||||
HMM_Mat4 m = transform2d2mat4(go2t(go));
|
||||
HMM_Mat4 sm = transform2d2mat4(sprite2t(sprite));
|
||||
struct spriteuni spv;
|
||||
rgba2floats(&spv.color.e, sprite->color);
|
||||
rgba2floats(spv.emissive.e, sprite->emissive);
|
||||
spv.size = sprite->spritesize;
|
||||
spv.offset = sprite->spriteoffset;
|
||||
spv.model = HMM_MulM4(m,sm);
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, SLOT_sprite, SG_RANGE_REF(spv));
|
||||
sg_draw(0,4,1);
|
||||
}
|
||||
|
||||
void gui_draw_img(texture *tex, transform2d t, int wrap, HMM_Vec2 wrapoffset, float wrapscale, struct rgba color) {
|
||||
sg_apply_pipeline(pip_sprite);
|
||||
sg_apply_uniforms(SG_SHADERSTAGE_VS, SLOT_vp, SG_RANGE_REF(useproj));
|
||||
sprite_tex(tex);
|
||||
tex_draw(transform2d2mat(t), ST_UNIT, color, wrap, wrapoffset, (HMM_Vec2){wrapscale,wrapscale}, (struct rgba){0,0,0,0});
|
||||
}
|
||||
|
||||
void slice9_draw(texture *tex, transform2d *t, HMM_Vec4 border, struct rgba color)
|
||||
{
|
||||
|
||||
}
|
||||
void sprite_free(sprite *sprite) { free(sprite); }
|
|
@ -7,37 +7,14 @@
|
|||
#include "transform.h"
|
||||
#include "gameobject.h"
|
||||
|
||||
struct sprite {
|
||||
HMM_Vec2 pos;
|
||||
HMM_Vec2 scale;
|
||||
float angle;
|
||||
typedef struct sprite {
|
||||
struct rgba color;
|
||||
struct rgba emissive;
|
||||
HMM_Vec2 spritesize;
|
||||
HMM_Vec4 rect;
|
||||
HMM_Vec2 spriteoffset;
|
||||
};
|
||||
|
||||
struct spriteuni {
|
||||
HMM_Vec4 color;
|
||||
HMM_Vec4 emissive;
|
||||
HMM_Vec2 size;
|
||||
HMM_Vec2 offset;
|
||||
HMM_Mat4 model;
|
||||
};
|
||||
|
||||
typedef struct sprite sprite;
|
||||
|
||||
extern sg_bindings bind_sprite;
|
||||
} sprite;
|
||||
|
||||
sprite *sprite_make();
|
||||
void sprite_free(sprite *sprite);
|
||||
void sprite_tex(texture *t);
|
||||
void sprite_initialize();
|
||||
void sprite_draw(struct sprite *sprite, gameobject *go);
|
||||
void sprite_pipe();
|
||||
void sprite_draw_all();
|
||||
void sprite_flush();
|
||||
|
||||
void gui_draw_img(texture *tex, transform2d t, int wrap, HMM_Vec2 wrapoffset, float wrapscale, struct rgba color);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -122,11 +122,9 @@ struct texture *texture_from_file(const char *path) {
|
|||
unsigned int nw = next_pow2(tex->width);
|
||||
unsigned int nh = next_pow2(tex->height);
|
||||
|
||||
int filter = SG_FILTER_NEAREST;
|
||||
|
||||
sg_image_data sg_img_data;
|
||||
sg_img_data.subimage[0][0] = (sg_range){.ptr = data, .size=tex->width*tex->height*4};
|
||||
/*
|
||||
|
||||
int mips = mip_levels(tex->width, tex->height)+1;
|
||||
|
||||
YughInfo("Has %d mip levels, from wxh %dx%d, pow2 is %ux%u.", mips, tex->width, tex->height,nw,nh);
|
||||
|
@ -151,18 +149,18 @@ struct texture *texture_from_file(const char *path) {
|
|||
mipw = w;
|
||||
miph = h;
|
||||
}
|
||||
*/
|
||||
|
||||
tex->id = sg_make_image(&(sg_image_desc){
|
||||
.type = SG_IMAGETYPE_2D,
|
||||
.width = tex->width,
|
||||
.height = tex->height,
|
||||
.usage = SG_USAGE_IMMUTABLE,
|
||||
//.num_mipmaps = mips,
|
||||
.num_mipmaps = mips,
|
||||
.data = sg_img_data
|
||||
});
|
||||
|
||||
/*for (int i = 1; i < mips; i++)
|
||||
free(mipdata[i]);*/
|
||||
|
||||
for (int i = 1; i < mips; i++)
|
||||
free(mipdata[i]);
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
@ -191,8 +189,6 @@ struct texture *texture_fromdata(void *raw, long size)
|
|||
|
||||
tex->data = data;
|
||||
|
||||
int filter = SG_FILTER_NEAREST;
|
||||
|
||||
sg_image_data sg_img_data;
|
||||
|
||||
int mips = mip_levels(tex->width, tex->height)+1;
|
||||
|
|
|
@ -18,7 +18,8 @@ extern struct rect ST_UNIT;
|
|||
|
||||
/* Represents an actual texture on the GPU */
|
||||
struct texture {
|
||||
sg_image id; /* ID reference for the GPU memory location of the texture */
|
||||
sg_image id; /* ID reference for the GPU memory location of the
|
||||
texture */
|
||||
int width;
|
||||
int height;
|
||||
unsigned char *data;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "transform.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
const transform2d t2d_unit = {
|
||||
.pos = {0,0},
|
||||
|
@ -7,6 +8,23 @@ const transform2d t2d_unit = {
|
|||
.angle = 0
|
||||
};
|
||||
|
||||
transform3d *make_transform3d()
|
||||
{
|
||||
transform3d *t = calloc(sizeof(transform3d),1);
|
||||
return t;
|
||||
}
|
||||
|
||||
void transform3d_free(transform3d *t) { free(t); }
|
||||
|
||||
transform2d *make_transform2d()
|
||||
{
|
||||
transform2d *t = calloc(sizeof(transform2d),1);
|
||||
t->scale = (HMM_Vec2){1,1};
|
||||
return t;
|
||||
}
|
||||
|
||||
void transform2d_free(transform2d *t) { free(t); }
|
||||
|
||||
HMM_Vec3 trans_forward(const transform3d *const trans) { return HMM_QVRot(vFWD, trans->rotation); }
|
||||
HMM_Vec3 trans_back(const transform3d *trans) { return HMM_QVRot(vBKWD, trans->rotation); }
|
||||
HMM_Vec3 trans_up(const transform3d *trans) { return HMM_QVRot(vUP, trans->rotation); }
|
||||
|
@ -40,13 +58,19 @@ HMM_Mat3 transform2d2mat(transform2d trn) {
|
|||
return HMM_MulM3(HMM_Translate2D(trn.pos), HMM_MulM3(HMM_RotateM3(trn.angle), HMM_ScaleM3(trn.scale)));
|
||||
}
|
||||
|
||||
HMM_Mat4 transform2d2mat4(transform2d trn)
|
||||
HMM_Mat4 transform2d2mat4(transform2d *t)
|
||||
{
|
||||
transform3d t3d;
|
||||
t3d.pos.xy = trn.pos;
|
||||
t3d.scale.xy = trn.scale;
|
||||
t3d.rotation = HMM_QFromAxisAngle_RH((HMM_Vec3){0,0,-1}, trn.angle);
|
||||
return transform3d2mat(t3d);
|
||||
HMM_Mat4 T = {0};
|
||||
float c = cosf(t->angle);
|
||||
float s = sinf(t->angle);
|
||||
T.col[0].x = c*t->scale.x;
|
||||
T.col[0].y = s*t->scale.y;
|
||||
T.col[1].x = -s*t->scale.x;
|
||||
T.col[1].y = c*t->scale.y;
|
||||
T.col[3].xy = t->pos;
|
||||
T.col[2].z = 1;
|
||||
T.col[3].w = 1;
|
||||
return T;
|
||||
}
|
||||
|
||||
transform2d mat2transform2d(HMM_Mat3 m)
|
||||
|
|
|
@ -9,12 +9,18 @@ typedef struct transform3d {
|
|||
HMM_Quat rotation;
|
||||
} transform3d;
|
||||
|
||||
transform3d *make_transform3d();
|
||||
void transform3d_free(transform3d *t);
|
||||
|
||||
typedef struct {
|
||||
HMM_Vec2 pos;
|
||||
HMM_Vec2 scale;
|
||||
float angle;
|
||||
} transform2d;
|
||||
|
||||
transform2d *make_transform2d();
|
||||
void transform2d_free(transform2d *t);
|
||||
|
||||
extern const transform2d t2d_unit;
|
||||
|
||||
#define VEC2_FMT "[%g,%g]"
|
||||
|
@ -27,7 +33,7 @@ HMM_Vec3 trans_down(const transform3d *trans);
|
|||
HMM_Vec3 trans_right(const transform3d *trans);
|
||||
HMM_Vec3 trans_left(const transform3d *trans);
|
||||
|
||||
HMM_Mat4 transform2d2mat4(transform2d trn);
|
||||
HMM_Mat4 transform2d2mat4(transform2d *t);
|
||||
|
||||
/* Transform a position via the matrix */
|
||||
HMM_Vec2 mat_t_pos(HMM_Mat3 m, HMM_Vec2 pos);
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
@vs vs9
|
||||
in vec2 vert;
|
||||
in vec2 vuv;
|
||||
in vec4 vborder;
|
||||
in vec2 vscale;
|
||||
in vec4 vcolor;
|
||||
|
||||
out vec2 uv;
|
||||
out vec4 border;
|
||||
out vec2 scale;
|
||||
out vec4 fcolor;
|
||||
|
||||
uniform vs9_params { mat4 projection; };
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = projection * vec4(vert, 0.0, 1.0);
|
||||
|
||||
uv = vuv;
|
||||
border = vborder;
|
||||
scale = vscale;
|
||||
fcolor = vcolor;
|
||||
}
|
||||
@end
|
||||
|
||||
@fs fs9
|
||||
in vec2 uv; /* image uv */
|
||||
in vec4 border; /* uv length of border, normalized to image dimensions; left, bottom, right, top */
|
||||
in vec2 scale; /* polygon dimensions ~ texture dimensions */
|
||||
in vec4 fcolor;
|
||||
|
||||
out vec4 color;
|
||||
|
||||
uniform texture2D image;
|
||||
uniform sampler smp;
|
||||
|
||||
float map(float value, float min1, float max1, float min2, float max2)
|
||||
{
|
||||
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
|
||||
}
|
||||
|
||||
float processAxis(float coord, float texBorder, float winBorder)
|
||||
{
|
||||
if (coord < winBorder)
|
||||
return map(coord, 0, winBorder, 0, texBorder);
|
||||
if (coord < 1 - winBorder)
|
||||
return map(coord, winBorder, 1 - winBorder, texBorder, 1 - texBorder);
|
||||
|
||||
return map(coord, 1 - winBorder, 1, 1 - texBorder, 1);
|
||||
}
|
||||
|
||||
vec2 uv9slice(vec2 uv, vec2 s, vec4 b)
|
||||
{
|
||||
vec2 t = clamp((s * uv - b.xy) / (s - b.xy - b.zw), 0.0, 1.0);
|
||||
return mix(uv * s, 1.0 - s * (1.0 - uv), t);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 nuv = uv9slice(uv, scale, border);
|
||||
color = fcolor * texture(sampler2D(image,smp), nuv);
|
||||
}
|
||||
@end
|
||||
|
||||
@program slice9 vs9 fs9
|
|
@ -1,14 +0,0 @@
|
|||
#version 330
|
||||
in vec2 TexCoords;
|
||||
out vec4 color;
|
||||
|
||||
uniform sampler2DArray image;
|
||||
uniform float frame;
|
||||
uniform vec3 spriteColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
color = vec4(spriteColor, 1.f) * texture(image, vec3(TexCoords,frame));
|
||||
if (color.a < 0.1)
|
||||
discard;
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
#version 330 core
|
||||
layout (location = 0) in vec2 vertex; // <vec2 position, vec2 texCoords>
|
||||
|
||||
out vec2 TexCoords;
|
||||
|
||||
layout (std140) uniform Projection
|
||||
{
|
||||
mat4 projection;
|
||||
};
|
||||
|
||||
uniform mat4 model;
|
||||
|
||||
void main()
|
||||
{
|
||||
TexCoords = vertex.xy;
|
||||
gl_Position = projection * model * vec4(vertex.xy, 0.0, 1.0);
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
@vs vs
|
||||
in vec2 vertex;
|
||||
|
||||
out vec2 texcoords;
|
||||
out vec4 fcolor;
|
||||
out vec4 femissive;
|
||||
|
||||
uniform app {
|
||||
float time;
|
||||
vec2 window;
|
||||
};
|
||||
|
||||
uniform vp {
|
||||
mat4 proj;
|
||||
};
|
||||
|
||||
uniform sprite {
|
||||
vec4 vcolor;
|
||||
vec4 vemissive;
|
||||
vec2 spritesize;
|
||||
vec2 spriteoff;
|
||||
mat4 model;
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
texcoords = vertex;
|
||||
texcoords.y = 1 - texcoords.y;
|
||||
gl_Position = proj * model * vec4(vertex, 0, 1.0);
|
||||
fcolor = vcolor;
|
||||
femissive = vemissive;
|
||||
}
|
||||
@end
|
||||
|
||||
@fs fs
|
||||
in vec2 texcoords;
|
||||
in vec4 fcolor;
|
||||
in vec4 femissive;
|
||||
|
||||
out vec4 color;
|
||||
|
||||
uniform texture2D image;
|
||||
uniform sampler smp;
|
||||
|
||||
void main()
|
||||
{
|
||||
color = texture(sampler2D(image,smp), texcoords);
|
||||
color *= fcolor;
|
||||
color.xyz = mix(color.xyz, femissive.xyz, femissive.a);
|
||||
}
|
||||
@end
|
||||
|
||||
@program sprite vs fs
|
|
@ -1,12 +0,0 @@
|
|||
#version 330 core
|
||||
in vec2 texcoords;
|
||||
out vec4 color;
|
||||
|
||||
uniform sampler2D image;
|
||||
uniform vec3 spriteColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
color = vec4(spriteColor, 1.f) * texture(image, texcoords);
|
||||
color.a = 1.f;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
@vs vs
|
||||
in vec2 vert;
|
||||
|
||||
in vec2 pos;
|
||||
in vec2 wh;
|
||||
in vec2 uv;
|
||||
in vec2 st;
|
||||
in vec4 vColor;
|
||||
|
||||
out vec2 TexCoords;
|
||||
out vec4 fColor;
|
||||
|
||||
uniform vs_params { mat4 projection; };
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = projection * vec4(pos + (vert * wh), 0.0, 1.0);
|
||||
|
||||
TexCoords = uv + vec2(vert.x*st.x, st.y - vert.y*st.y);
|
||||
|
||||
fColor = vColor;
|
||||
}
|
||||
@end
|
||||
|
||||
@fs fs
|
||||
in vec2 TexCoords;
|
||||
in vec4 fColor;
|
||||
|
||||
out vec4 color;
|
||||
|
||||
uniform texture2D text;
|
||||
uniform sampler smp;
|
||||
|
||||
void main()
|
||||
{
|
||||
float lettera = texture(sampler2D(text,smp),TexCoords).r;
|
||||
if (lettera < 0.1f) discard;
|
||||
color = fColor;
|
||||
}
|
||||
@end
|
||||
|
||||
@program text vs fs
|
|
@ -1,30 +1,45 @@
|
|||
@vs vs
|
||||
@block vptr
|
||||
in vec3 a_pos;
|
||||
in vec2 a_tex_coords;
|
||||
in vec2 a_uv;
|
||||
in vec4 a_norm;
|
||||
in vec4 a_weight;
|
||||
in vec4 a_joint;
|
||||
|
||||
out vec2 tex_coords;
|
||||
out vec3 normal;
|
||||
|
||||
uniform vs_p { uniform mat4 vp; };
|
||||
uniform vmodel { uniform mat4 model; };
|
||||
@end
|
||||
|
||||
@vs vs
|
||||
@include_block vptr
|
||||
|
||||
in vec4 a_bone;
|
||||
in vec4 a_weight;
|
||||
|
||||
uniform skinv { uniform mat4 bones[50]; };
|
||||
|
||||
void main() {
|
||||
mat4 skin = bones[int(a_joint.x)] * a_weight.x;
|
||||
skin += bones[int(a_joint.y)] * a_weight.y;
|
||||
skin += bones[int(a_joint.z)] * a_weight.z;
|
||||
skin += bones[int(a_joint.w)] * a_weight.w;
|
||||
mat4 skinm = model * skin;
|
||||
gl_Position = vp * skinm * vec4(a_pos,1.0);
|
||||
tex_coords = a_tex_coords;
|
||||
mat4 tt = vp;
|
||||
mat4 mm = model;
|
||||
mat4 skin = bones[int(a_bone.x)] * a_weight.x;
|
||||
skin += bones[int(a_bone.y)] * a_weight.y;
|
||||
skin += bones[int(a_bone.z)] * a_weight.z;
|
||||
skin += bones[int(a_bone.w)] * a_weight.w;
|
||||
mat4 skinm = mm * skin;
|
||||
gl_Position = tt * skinm * vec4(a_pos,1.0);
|
||||
tex_coords = a_uv;
|
||||
normal = (skinm * vec4(a_norm.xyz*2-1,0)).xyz;
|
||||
}
|
||||
@end
|
||||
|
||||
@vs vs_st
|
||||
@include_block vptr
|
||||
|
||||
void main() {
|
||||
gl_Position = vp * model * vec4(a_pos,1.0);
|
||||
tex_coords = a_uv;
|
||||
normal = (model * vec4(a_norm.xyz*2-1,0)).xyz;
|
||||
}
|
||||
@end
|
||||
|
||||
@fs fs
|
||||
in vec2 tex_coords;
|
||||
in vec3 normal;
|
||||
|
@ -45,3 +60,4 @@ void main() {
|
|||
@end
|
||||
|
||||
@program unlit vs fs
|
||||
@program unlit_st vs_st fs
|
||||
|
|
Loading…
Reference in a new issue