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 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 = {
|
||||
loop: true,
|
||||
rect: fullrect,
|
||||
|
@ -61,7 +79,10 @@ var sprite = {
|
|||
return;
|
||||
}
|
||||
if (p === this.path) return;
|
||||
this._p = p;
|
||||
sprite_rmbucket(this);
|
||||
this._p = p;
|
||||
sprite_addbucket(this);
|
||||
|
||||
this.del_anim?.();
|
||||
this.texture = game.texture(p);
|
||||
|
||||
|
@ -74,12 +95,12 @@ var sprite = {
|
|||
this.play();
|
||||
|
||||
this.pos = this.dimensions().scale(this.anchor);
|
||||
|
||||
},
|
||||
get path() {
|
||||
return this._p;
|
||||
},
|
||||
kill() {
|
||||
sprite_rmbucket(this);
|
||||
this.del_anim?.();
|
||||
this.anim = undefined;
|
||||
this.gameobject = undefined;
|
||||
|
@ -111,6 +132,7 @@ var sprite = {
|
|||
height() { return this.dimensions().y; },
|
||||
};
|
||||
globalThis.allsprites = {};
|
||||
globalThis.sprite_buckets = [];
|
||||
|
||||
sprite.doc = {
|
||||
path: "Path to the texture.",
|
||||
|
@ -152,8 +174,11 @@ component.sprite = function(obj) {
|
|||
sp.transform = obj.transform;
|
||||
sp.guid = prosperon.guid();
|
||||
allsprites[sp.guid] = sp;
|
||||
sprite_addbucket(sp);
|
||||
if (component.sprite.make_hook) component.sprite.make_hook(sp);
|
||||
return sp;
|
||||
}
|
||||
|
||||
sprite.shade = [1,1,1,1];
|
||||
|
||||
Object.mixin(os.make_seg2d(), {
|
||||
|
|
|
@ -324,6 +324,25 @@ game.engine_start = function (s) {
|
|||
};
|
||||
|
||||
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,
|
||||
window.size.x,
|
||||
|
@ -342,6 +361,141 @@ prosperon.release_mode = function()
|
|||
}
|
||||
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() {
|
||||
var startframe = profile.now();
|
||||
var dt = profile.secs(profile.now()) - frame_t;
|
||||
|
|
|
@ -354,6 +354,7 @@ dup(diff) {
|
|||
this.components[key].enabled = false;
|
||||
delete this.components[key];
|
||||
}
|
||||
|
||||
delete this.components;
|
||||
|
||||
this.clear();
|
||||
|
@ -367,7 +368,6 @@ dup(diff) {
|
|||
}
|
||||
},
|
||||
|
||||
|
||||
make_objs(objs) {
|
||||
for (var prop in objs) {
|
||||
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("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);
|
||||
e.ssbo = render.make_textssbo();
|
||||
e.shape = shape.quad;
|
||||
e.shape = shape.centered_quad;
|
||||
e.shader = render.make_shader("shaders/baseparticle.cg");
|
||||
e.dead = [];
|
||||
return e;
|
||||
|
|
|
@ -444,6 +444,8 @@ var parshader;
|
|||
var spritessboshader;
|
||||
var polyssboshader;
|
||||
|
||||
var sprite_ssbo;
|
||||
|
||||
render.init = function() {
|
||||
textshader = render.make_shader("shaders/text_base.cg");
|
||||
render.spriteshader = render.make_shader("shaders/sprite.cg");
|
||||
|
@ -456,6 +458,7 @@ render.init = function() {
|
|||
polyssboshader = render.make_shader("shaders/poly_ssbo.cg");
|
||||
textssbo = render.make_textssbo();
|
||||
poly_ssbo = render.make_textssbo();
|
||||
sprite_ssbo = render.make_textssbo();
|
||||
|
||||
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) {
|
||||
check_flush();
|
||||
var mat = {
|
||||
|
|
|
@ -19,15 +19,13 @@ readonly buffer ssbo {
|
|||
out vec2 uv;
|
||||
out vec4 color0;
|
||||
|
||||
vec2 pos;
|
||||
uniform mat4 vp;
|
||||
|
||||
void main()
|
||||
{
|
||||
particle p = par[gl_InstanceIndex];
|
||||
pos = a_pos - 0.5;
|
||||
gl_Position = vp * p.model * vec4(pos, 0.0, 1.0);
|
||||
uv = a_pos;
|
||||
gl_Position = vp * p.model * vec4(a_pos, 0.0, 1.0);
|
||||
uv = a_uv;
|
||||
color0 = p.color;
|
||||
}
|
||||
@end
|
||||
|
|
|
@ -1533,9 +1533,9 @@ static const JSCFunctionListEntry js_physics_funcs[] = {
|
|||
CGETSET_ADD(physics, collision_persistence),
|
||||
};
|
||||
|
||||
JSC_GETSET_APPLY(transform, pos, vec3)
|
||||
JSC_GETSET_APPLY(transform, scale, vec3)
|
||||
JSC_GETSET_APPLY(transform, rotation, quat)
|
||||
JSC_GETSET(transform, pos, vec3)
|
||||
JSC_GETSET(transform, scale, vec3)
|
||||
JSC_GETSET(transform, rotation, quat)
|
||||
JSC_CCALL(transform_move, transform_move(js2transform(self), js2vec3(argv[0])); )
|
||||
|
||||
JSC_CCALL(transform_lookat,
|
||||
|
|
|
@ -56,6 +56,8 @@ HMM_Vec3 mat3_t_dir(HMM_Mat4 m, HMM_Vec3 dir)
|
|||
}
|
||||
|
||||
HMM_Mat4 transform2mat(transform *t) {
|
||||
return HMM_M4TRS(t->pos, t->rotation, t->scale);
|
||||
|
||||
if (t->dirty) {
|
||||
t->cache = HMM_M4TRS(t->pos, t->rotation, t->scale);
|
||||
t->dirty = 0;
|
||||
|
|
Loading…
Reference in a new issue