add sprite and rendering to engine js
This commit is contained in:
parent
08725d474d
commit
ef802bb6f2
|
@ -15,6 +15,24 @@ var make_point_obj = function(o, p)
|
||||||
|
|
||||||
var fullrect = [0,0,1,1];
|
var fullrect = [0,0,1,1];
|
||||||
|
|
||||||
|
var sprite_addbucket = function(sprite)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
var pp = sprite.gameobject.drawlayer.toString();
|
||||||
|
sprite_buckets[pp] ??= {};
|
||||||
|
sprite_buckets[pp][sprite.path] ??= {};
|
||||||
|
sprite_buckets[pp][sprite.path][sprite.guid] = sprite;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sprite_rmbucket = function(sprite)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
var pp = sprite.gameobject.drawlayer.toString();
|
||||||
|
if (!sprite_buckets[pp]) return;
|
||||||
|
if (!sprite_buckets[pp][sprite.path]) return;
|
||||||
|
delete sprite_buckets[pp][sprite.path][sprite.guid];
|
||||||
|
}
|
||||||
|
|
||||||
var sprite = {
|
var sprite = {
|
||||||
loop: true,
|
loop: true,
|
||||||
rect: fullrect,
|
rect: fullrect,
|
||||||
|
@ -61,7 +79,10 @@ var sprite = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (p === this.path) return;
|
if (p === this.path) return;
|
||||||
|
sprite_rmbucket(this);
|
||||||
this._p = p;
|
this._p = p;
|
||||||
|
sprite_addbucket(this);
|
||||||
|
|
||||||
this.del_anim?.();
|
this.del_anim?.();
|
||||||
this.texture = game.texture(p);
|
this.texture = game.texture(p);
|
||||||
|
|
||||||
|
@ -74,12 +95,12 @@ var sprite = {
|
||||||
this.play();
|
this.play();
|
||||||
|
|
||||||
this.pos = this.dimensions().scale(this.anchor);
|
this.pos = this.dimensions().scale(this.anchor);
|
||||||
|
|
||||||
},
|
},
|
||||||
get path() {
|
get path() {
|
||||||
return this._p;
|
return this._p;
|
||||||
},
|
},
|
||||||
kill() {
|
kill() {
|
||||||
|
sprite_rmbucket(this);
|
||||||
this.del_anim?.();
|
this.del_anim?.();
|
||||||
this.anim = undefined;
|
this.anim = undefined;
|
||||||
this.gameobject = undefined;
|
this.gameobject = undefined;
|
||||||
|
@ -111,6 +132,7 @@ var sprite = {
|
||||||
height() { return this.dimensions().y; },
|
height() { return this.dimensions().y; },
|
||||||
};
|
};
|
||||||
globalThis.allsprites = {};
|
globalThis.allsprites = {};
|
||||||
|
globalThis.sprite_buckets = [];
|
||||||
|
|
||||||
sprite.doc = {
|
sprite.doc = {
|
||||||
path: "Path to the texture.",
|
path: "Path to the texture.",
|
||||||
|
@ -152,8 +174,11 @@ component.sprite = function(obj) {
|
||||||
sp.transform = obj.transform;
|
sp.transform = obj.transform;
|
||||||
sp.guid = prosperon.guid();
|
sp.guid = prosperon.guid();
|
||||||
allsprites[sp.guid] = sp;
|
allsprites[sp.guid] = sp;
|
||||||
|
sprite_addbucket(sp);
|
||||||
|
if (component.sprite.make_hook) component.sprite.make_hook(sp);
|
||||||
return sp;
|
return sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprite.shade = [1,1,1,1];
|
sprite.shade = [1,1,1,1];
|
||||||
|
|
||||||
Object.mixin(os.make_seg2d(), {
|
Object.mixin(os.make_seg2d(), {
|
||||||
|
|
|
@ -324,6 +324,25 @@ game.engine_start = function (s) {
|
||||||
};
|
};
|
||||||
|
|
||||||
render.init();
|
render.init();
|
||||||
|
|
||||||
|
camera = make_camera();
|
||||||
|
camera.transform.pos = [0,0,-100];
|
||||||
|
camera.mode = "keep";
|
||||||
|
camera.break = "fit";
|
||||||
|
camera.size = game.size;
|
||||||
|
gamestate.camera = camera;
|
||||||
|
|
||||||
|
hudcam = make_camera();
|
||||||
|
hudcam.near = 0;
|
||||||
|
hudcam.size = camera.size;
|
||||||
|
hudcam.mode = "keep";
|
||||||
|
hudcam.break = "fit";
|
||||||
|
|
||||||
|
appcam = make_camera();
|
||||||
|
appcam.near = 0;
|
||||||
|
appcam.size = window.size;
|
||||||
|
appcam.transform.pos = [window.size.x,window.size.y,-100];
|
||||||
|
screencolor = render.screencolor();
|
||||||
},
|
},
|
||||||
process,
|
process,
|
||||||
window.size.x,
|
window.size.x,
|
||||||
|
@ -342,6 +361,141 @@ prosperon.release_mode = function()
|
||||||
}
|
}
|
||||||
prosperon.debug = true;
|
prosperon.debug = true;
|
||||||
|
|
||||||
|
// Returns an array in the form of [left, bottom, right, top] in pixels of the camera to render to
|
||||||
|
// Camera viewport is [left,bottom,right,top] in relative values
|
||||||
|
function camviewport()
|
||||||
|
{
|
||||||
|
var aspect = (this.viewport[2]-this.viewport[0])/(this.viewport[3]-this.viewport[1])*window.size.x/window.size.y;
|
||||||
|
var raspect = this.size.x/this.size.y;
|
||||||
|
|
||||||
|
var left = this.viewport[0]*window.size.x;
|
||||||
|
var bottom = this.viewport[1]*window.size.y;
|
||||||
|
|
||||||
|
var usemode = this.mode;
|
||||||
|
|
||||||
|
if (this.break && this.size.x > window.size.x && this.size.y > window.size.y)
|
||||||
|
usemode = this.break;
|
||||||
|
|
||||||
|
if (usemode === "fit")
|
||||||
|
if (raspect < aspect) usemode = "height";
|
||||||
|
else usemode = "width";
|
||||||
|
|
||||||
|
switch(usemode) {
|
||||||
|
case "stretch":
|
||||||
|
case "expand":
|
||||||
|
return [0, 0, window.size.x, window.size.y];
|
||||||
|
case "keep":
|
||||||
|
return [left, bottom, left+this.size.x, bottom+this.size.y];
|
||||||
|
case "height":
|
||||||
|
var ret = [left, 0, this.size.x*(window.size.y/this.size.y), window.size.y];
|
||||||
|
ret[0] = (window.size.x-(ret[2]-ret[0]))/2;
|
||||||
|
return ret;
|
||||||
|
case "width":
|
||||||
|
var ret = [0, bottom, window.size.x, this.size.y*(window.size.x/this.size.x)];
|
||||||
|
ret[1] = (window.size.y-(ret[3]-ret[1]))/2;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [0, 0, window.size.x, window.size.y];
|
||||||
|
}
|
||||||
|
|
||||||
|
// pos is pixels on the screen, lower left[0,0]
|
||||||
|
function camscreen2world(pos)
|
||||||
|
{
|
||||||
|
var view = this.screen2cam(pos);
|
||||||
|
view.x *= this.size.x;
|
||||||
|
view.y *= this.size.y;
|
||||||
|
view = view.sub([this.size.x/2, this.size.y/2]);
|
||||||
|
view = view.add(this.pos.xy);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
camscreen2world.doc = "Convert a view position for a camera to world."
|
||||||
|
|
||||||
|
|
||||||
|
function screen2cam(pos)
|
||||||
|
{
|
||||||
|
var viewport = this.view();
|
||||||
|
var width = viewport[2]-viewport[0];
|
||||||
|
var height = viewport[3]-viewport[1];
|
||||||
|
var left = pos.x-viewport[0];
|
||||||
|
var bottom = pos.y-viewport[1];
|
||||||
|
var p = [left/width, bottom/height];
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
screen2cam.doc = "Convert a screen space position in pixels to a normalized viewport position in a camera."
|
||||||
|
|
||||||
|
function make_camera()
|
||||||
|
{
|
||||||
|
var cam = world.spawn();
|
||||||
|
cam.near = 0.1;
|
||||||
|
cam.far = 1000;
|
||||||
|
cam.ortho = true;
|
||||||
|
cam.viewport = [0,0,1,1];
|
||||||
|
cam.size = window.size.slice(); // The render size of this camera in pixels
|
||||||
|
// In ortho mode, this determines how many pixels it will see
|
||||||
|
cam.mode = "stretch";
|
||||||
|
cam.screen2world = camscreen2world;
|
||||||
|
cam.screen2cam = screen2cam;
|
||||||
|
|
||||||
|
cam.mousepos = function() { return this.screen2world(input.mouse.screenpos()); }
|
||||||
|
cam.view = camviewport;
|
||||||
|
cam.offscreen = false;
|
||||||
|
return cam;
|
||||||
|
}
|
||||||
|
|
||||||
|
var camera;
|
||||||
|
var hudcam;
|
||||||
|
var appcam;
|
||||||
|
var screencolor;
|
||||||
|
|
||||||
|
prosperon.render = function()
|
||||||
|
{
|
||||||
|
render.set_camera(camera);
|
||||||
|
render.sprites();
|
||||||
|
prosperon.draw();
|
||||||
|
hudcam.size = camera.size;
|
||||||
|
hudcam.transform.pos = [hudcam.size.x/2, hudcam.size.y/2, -100];
|
||||||
|
render.set_camera(hudcam);
|
||||||
|
|
||||||
|
prosperon.hud();
|
||||||
|
render.flush_text();
|
||||||
|
|
||||||
|
render.end_pass();
|
||||||
|
|
||||||
|
/* draw the image of the game world first */
|
||||||
|
render.glue_pass();
|
||||||
|
render.viewport(...camera.view());
|
||||||
|
render.use_shader(render.postshader);
|
||||||
|
render.use_mat({diffuse:screencolor});
|
||||||
|
render.draw(shape.quad);
|
||||||
|
|
||||||
|
// Flush & render
|
||||||
|
appcam.transform.pos = [window.size.x/2, window.size.y/2, -100];
|
||||||
|
appcam.size = window.size.slice();
|
||||||
|
if (os.sys() !== 'macos')
|
||||||
|
appcam.size.y *= -1;
|
||||||
|
|
||||||
|
render.set_camera(appcam);
|
||||||
|
render.viewport(...appcam.view());
|
||||||
|
|
||||||
|
// Call gui functions
|
||||||
|
mum.style = mum.dbg_style;
|
||||||
|
prosperon.gui();
|
||||||
|
if (mum.drawinput) mum.drawinput();
|
||||||
|
prosperon.gui_dbg();
|
||||||
|
render.flush_text();
|
||||||
|
mum.style = mum.base;
|
||||||
|
|
||||||
|
render.imgui_new(window.size.x, window.size.y, 0.01);
|
||||||
|
// if (gfx_gui) render.gfx_gui();
|
||||||
|
render.imgui_end();
|
||||||
|
|
||||||
|
render.end_pass();
|
||||||
|
render.commit();
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
|
@ -354,6 +354,7 @@ dup(diff) {
|
||||||
this.components[key].enabled = false;
|
this.components[key].enabled = false;
|
||||||
delete this.components[key];
|
delete this.components[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
delete this.components;
|
delete this.components;
|
||||||
|
|
||||||
this.clear();
|
this.clear();
|
||||||
|
@ -367,7 +368,6 @@ dup(diff) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
make_objs(objs) {
|
make_objs(objs) {
|
||||||
for (var prop in objs) {
|
for (var prop in objs) {
|
||||||
say(`spawning ${json.encode(objs[prop])}`);
|
say(`spawning ${json.encode(objs[prop])}`);
|
||||||
|
|
|
@ -274,3 +274,41 @@ mum.ex_hud = function()
|
||||||
mum.label("TOP RIGHT", {pos:game.size, anchor:[1,1]});
|
mum.label("TOP RIGHT", {pos:game.size, anchor:[1,1]});
|
||||||
mum.label("BOTTOM RIGHT", {pos:[game.size.x, 0], anchor:[1,0]});
|
mum.label("BOTTOM RIGHT", {pos:[game.size.x, 0], anchor:[1,0]});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mum.drawinput = undefined;
|
||||||
|
var ptext = "";
|
||||||
|
var panpan = {
|
||||||
|
draw() {
|
||||||
|
mum.rectangle({pos:[0,0], anchor:[0,0], height:20, width: window.size.x, padding:[10,16], color:Color.black});
|
||||||
|
mum.label("input level: ");
|
||||||
|
mum.label(ptext, {offset:[50,0], color:Color.red});
|
||||||
|
},
|
||||||
|
inputs: {
|
||||||
|
block: true,
|
||||||
|
char(c) {
|
||||||
|
ptext += c
|
||||||
|
},
|
||||||
|
enter() {
|
||||||
|
delete mum.drawinput;
|
||||||
|
player[0].uncontrol(panpan);
|
||||||
|
},
|
||||||
|
escape() {
|
||||||
|
delete mum.drawinput;
|
||||||
|
player[0].uncontrol(panpan);
|
||||||
|
},
|
||||||
|
backspace() {
|
||||||
|
ptext = ptext.slice(0,ptext.length-1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
mum.textinput = function (fn, str = "") {
|
||||||
|
mum.drawinput = panpan.draw;
|
||||||
|
ptext = str;
|
||||||
|
player[0].control(panpan);
|
||||||
|
panpan.inputs.enter = function() {
|
||||||
|
fn(ptext);
|
||||||
|
delete mum.drawinput;
|
||||||
|
player[0].uncontrol(panpan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ var make_emitter = function()
|
||||||
{
|
{
|
||||||
var e = Object.create(emitter);
|
var e = Object.create(emitter);
|
||||||
e.ssbo = render.make_textssbo();
|
e.ssbo = render.make_textssbo();
|
||||||
e.shape = shape.quad;
|
e.shape = shape.centered_quad;
|
||||||
e.shader = render.make_shader("shaders/baseparticle.cg");
|
e.shader = render.make_shader("shaders/baseparticle.cg");
|
||||||
e.dead = [];
|
e.dead = [];
|
||||||
return e;
|
return e;
|
||||||
|
|
|
@ -444,6 +444,8 @@ var parshader;
|
||||||
var spritessboshader;
|
var spritessboshader;
|
||||||
var polyssboshader;
|
var polyssboshader;
|
||||||
|
|
||||||
|
var sprite_ssbo;
|
||||||
|
|
||||||
render.init = function() {
|
render.init = function() {
|
||||||
textshader = render.make_shader("shaders/text_base.cg");
|
textshader = render.make_shader("shaders/text_base.cg");
|
||||||
render.spriteshader = render.make_shader("shaders/sprite.cg");
|
render.spriteshader = render.make_shader("shaders/sprite.cg");
|
||||||
|
@ -456,6 +458,7 @@ render.init = function() {
|
||||||
polyssboshader = render.make_shader("shaders/poly_ssbo.cg");
|
polyssboshader = render.make_shader("shaders/poly_ssbo.cg");
|
||||||
textssbo = render.make_textssbo();
|
textssbo = render.make_textssbo();
|
||||||
poly_ssbo = render.make_textssbo();
|
poly_ssbo = render.make_textssbo();
|
||||||
|
sprite_ssbo = render.make_textssbo();
|
||||||
|
|
||||||
render.textshader = textshader;
|
render.textshader = textshader;
|
||||||
|
|
||||||
|
@ -489,6 +492,30 @@ render.init = function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
render.sprites = function(gridsize = 1)
|
||||||
|
{
|
||||||
|
var sps = Object.values(allsprites);
|
||||||
|
var sprite_buckets = {};
|
||||||
|
for (var sprite of sps) {
|
||||||
|
var pp = sprite.gameobject.drawlayer.toString();
|
||||||
|
sprite_buckets[pp] ??= {};
|
||||||
|
sprite_buckets[pp][sprite.path] ??= {};
|
||||||
|
sprite_buckets[pp][sprite.path][sprite.guid] = sprite;
|
||||||
|
}
|
||||||
|
|
||||||
|
render.use_shader(spritessboshader);
|
||||||
|
for (var bucket of Object.values(sprite_buckets)){
|
||||||
|
for (var img of Object.values(bucket)) {
|
||||||
|
var sparray = Object.values(img);
|
||||||
|
if (sparray.length === 0) continue;
|
||||||
|
var ss = sparray[0];
|
||||||
|
render.use_mat(ss);
|
||||||
|
render.make_sprite_ssbo(Object.values(sparray), sprite_ssbo);
|
||||||
|
render.draw(shape.quad, sprite_ssbo, sparray.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render.circle = function(pos, radius, color) {
|
render.circle = function(pos, radius, color) {
|
||||||
check_flush();
|
check_flush();
|
||||||
var mat = {
|
var mat = {
|
||||||
|
|
|
@ -19,15 +19,13 @@ readonly buffer ssbo {
|
||||||
out vec2 uv;
|
out vec2 uv;
|
||||||
out vec4 color0;
|
out vec4 color0;
|
||||||
|
|
||||||
vec2 pos;
|
|
||||||
uniform mat4 vp;
|
uniform mat4 vp;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
particle p = par[gl_InstanceIndex];
|
particle p = par[gl_InstanceIndex];
|
||||||
pos = a_pos - 0.5;
|
gl_Position = vp * p.model * vec4(a_pos, 0.0, 1.0);
|
||||||
gl_Position = vp * p.model * vec4(pos, 0.0, 1.0);
|
uv = a_uv;
|
||||||
uv = a_pos;
|
|
||||||
color0 = p.color;
|
color0 = p.color;
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -1533,9 +1533,9 @@ static const JSCFunctionListEntry js_physics_funcs[] = {
|
||||||
CGETSET_ADD(physics, collision_persistence),
|
CGETSET_ADD(physics, collision_persistence),
|
||||||
};
|
};
|
||||||
|
|
||||||
JSC_GETSET_APPLY(transform, pos, vec3)
|
JSC_GETSET(transform, pos, vec3)
|
||||||
JSC_GETSET_APPLY(transform, scale, vec3)
|
JSC_GETSET(transform, scale, vec3)
|
||||||
JSC_GETSET_APPLY(transform, rotation, quat)
|
JSC_GETSET(transform, rotation, quat)
|
||||||
JSC_CCALL(transform_move, transform_move(js2transform(self), js2vec3(argv[0])); )
|
JSC_CCALL(transform_move, transform_move(js2transform(self), js2vec3(argv[0])); )
|
||||||
|
|
||||||
JSC_CCALL(transform_lookat,
|
JSC_CCALL(transform_lookat,
|
||||||
|
|
|
@ -56,6 +56,8 @@ HMM_Vec3 mat3_t_dir(HMM_Mat4 m, HMM_Vec3 dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
HMM_Mat4 transform2mat(transform *t) {
|
HMM_Mat4 transform2mat(transform *t) {
|
||||||
|
return HMM_M4TRS(t->pos, t->rotation, t->scale);
|
||||||
|
|
||||||
if (t->dirty) {
|
if (t->dirty) {
|
||||||
t->cache = HMM_M4TRS(t->pos, t->rotation, t->scale);
|
t->cache = HMM_M4TRS(t->pos, t->rotation, t->scale);
|
||||||
t->dirty = 0;
|
t->dirty = 0;
|
||||||
|
|
Loading…
Reference in a new issue