fast sprite render
This commit is contained in:
@@ -758,6 +758,7 @@ function insertion_sort(arr, cmp)
|
||||
|
||||
function sprites_to_queue(sprites, ysort = false)
|
||||
{
|
||||
return render._main.make_sprite_queue(allsprites, prosperon.camera, sprite_pipeline)
|
||||
var sprites = allsprites;
|
||||
for (var i = 0; i < sprites.length; i++)
|
||||
sprites[i].transform.clean();
|
||||
@@ -769,7 +770,6 @@ function sprites_to_queue(sprites, ysort = false)
|
||||
var mesh = render._main.make_sprite_mesh(sprites);
|
||||
|
||||
var queue = [];
|
||||
var idx = 0;
|
||||
var image;
|
||||
var first_index = 0;
|
||||
var count = 0;
|
||||
|
||||
232
source/jsffi.c
232
source/jsffi.c
@@ -1149,7 +1149,6 @@ int js_arrlen(JSContext *js,JSValue v) {
|
||||
len = js_getnum_str(js,v,"length");
|
||||
return len;
|
||||
}
|
||||
|
||||
static inline int js_transform_dirty_chain(JSContext *js, JSValue v)
|
||||
{
|
||||
transform *t = js2transform(js, v);
|
||||
@@ -1753,6 +1752,64 @@ static const JSCFunctionListEntry js_spline_funcs[] = {
|
||||
MIST_FUNC_DEF(spline, bezier, 2)
|
||||
};
|
||||
|
||||
|
||||
shader_globals camera_globals(JSContext *js, JSValue camera)
|
||||
{
|
||||
shader_globals data = {0};
|
||||
HMM_Vec2 size;
|
||||
transform *transform;
|
||||
double fov;
|
||||
double aspect;
|
||||
int ortho;
|
||||
double near;
|
||||
double far;
|
||||
|
||||
JS_GETPROP(js, size, camera, size, vec2)
|
||||
JS_GETPROP(js, transform, camera, transform, transform)
|
||||
JS_GETPROP(js, fov, camera, fov, number)
|
||||
JS_GETPROP(js, aspect, camera, aspect, number)
|
||||
JS_GETPROP(js, ortho, camera,ortho,bool)
|
||||
JS_GETPROP(js,near,camera,near,number)
|
||||
JS_GETPROP(js,far,camera,far,number)
|
||||
|
||||
HMM_Mat4 proj;
|
||||
HMM_Mat4 view;
|
||||
|
||||
if (ortho) {
|
||||
proj = HMM_Orthographic_RH_NO(
|
||||
-size.x*0.5, 0.5*size.x,
|
||||
-size.y*0.5, 0.5*size.y,
|
||||
-1.0f, 1.0f
|
||||
);
|
||||
view = HMM_Translate((HMM_Vec3){ -transform->pos.x, -transform->pos.y, 0.0f });
|
||||
}
|
||||
else {
|
||||
proj = HMM_Perspective_RH_NO(fov, aspect,near,far);
|
||||
|
||||
HMM_Mat4 camera_transform = HMM_Translate(transform->pos);
|
||||
camera_transform = HMM_MulM4(camera_transform, HMM_QToM4(transform->rotation));
|
||||
// camera_transform = HMM_MulM4(camera_transform, HMM_Scale(transform->scale)); // don't bother w/ scale
|
||||
view = HMM_InvGeneralM4(camera_transform);
|
||||
}
|
||||
|
||||
// Update your shader globals
|
||||
data.world_to_projection = HMM_MulM4(proj, view);
|
||||
data.projection_to_world = HMM_InvGeneralM4(data.world_to_projection);
|
||||
data.camera_pos_world = transform->pos;
|
||||
data.viewport_min_z = near;
|
||||
data.viewport_max_z = far;
|
||||
data.render_size = size;
|
||||
data.world_to_view = view;
|
||||
data.view_to_projection = proj;
|
||||
data.camera_dir_world = HMM_NormV3(HMM_QVRot((HMM_Vec3){0,0,-1},transform->rotation));
|
||||
data.viewport_size = (HMM_Vec2){0.5,0.5};
|
||||
data.viewport_offset = (HMM_Vec2){0,0};
|
||||
data.time = SDL_GetTicksNS() / 1000000000.0f;
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
JSValue js_vector_dot(JSContext *js, JSValue self, int argc, JSValue *argv) {
|
||||
size_t alen, blen;
|
||||
float *a = js2floats(js,argv[0], &alen);
|
||||
@@ -3986,7 +4043,7 @@ int sort_sprite(const sprite *a, const sprite *b)
|
||||
|
||||
if (a->quad.vert[0].pos.y != b->quad.vert[0].pos.y) return b->quad.vert[0].pos.y - a->quad.vert[0].pos.y;
|
||||
|
||||
// if (!JS_SameValue(a->js, a->image, b->image)) return JS_VALUE_GET_PTR(a->image) < JS_VALUE_GET_PTR(b->image) ? -1 : 1;
|
||||
if (!JS_SameValue(a->js, a->image, b->image)) return JS_VALUE_GET_PTR(a->image) < JS_VALUE_GET_PTR(b->image) ? -1 : 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -4014,33 +4071,58 @@ JSC_CCALL(gpu_sort_sprite,
|
||||
return number2js(js,0);
|
||||
)
|
||||
|
||||
inline int sprite_in_view(HMM_Mat3 sprite, HMM_Mat4 camera)
|
||||
{
|
||||
int outside = 0;
|
||||
for (int j = 0; j < 4; j++) {
|
||||
HMM_Vec3 corner = HMM_MulM3V3(sprite, (HMM_Vec3){base_quad[j].x, base_quad[j].y, 1.0});
|
||||
HMM_Vec4 clip = HMM_MulM4V4(camera, (HMM_Vec4){corner.x,corner.y,corner.z,1.0});
|
||||
if (clip.w <= 0.0) {
|
||||
outside++;
|
||||
continue;
|
||||
}
|
||||
|
||||
float nx = clip.x/clip.w;
|
||||
float ny = clip.y/clip.w;
|
||||
float nz = clip.z/clip.w;
|
||||
|
||||
if (nx < -1 || nx > 1) outside++;
|
||||
else if (ny < -1 || ny > 1) outside++;
|
||||
else if (nz < -1 || nz > 1) outside++;
|
||||
}
|
||||
|
||||
return outside != 4;
|
||||
}
|
||||
|
||||
JSC_CCALL(gpu_make_sprite_queue,
|
||||
size_t quads = js_arrlen(js, argv[0]);
|
||||
|
||||
// Reserve an array of 'sprites' if needed, but watch for out-of-bounds
|
||||
shader_globals info = camera_globals(js,argv[1]);
|
||||
|
||||
sprite *sprites = NULL;
|
||||
arrsetlen(sprites, quads);
|
||||
arrsetcap(sprites, quads);
|
||||
|
||||
for (int i = 0; i < quads; i++) {
|
||||
JSValue sub = JS_GetPropertyUint32(js, argv[0], i);
|
||||
JSValue jstransform = JS_GetPropertyStr(js, sub, "transform");
|
||||
HMM_Mat3 trmat = js2transform_mat3(js,jstransform);
|
||||
if (!sprite_in_view(trmat,info.world_to_projection)) {
|
||||
JS_FreeValue(js,jstransform);
|
||||
JS_FreeValue(js,sub);
|
||||
continue;
|
||||
}
|
||||
|
||||
rect src;
|
||||
HMM_Vec4 color;
|
||||
|
||||
JS_GETATOM(js, src, sub, src_atom, rect)
|
||||
JS_GETATOM(js, color, sub, color_atom, color)
|
||||
|
||||
JSValue jstransform = JS_GetPropertyStr(js, sub, "transform");
|
||||
|
||||
quad sprite_quad;
|
||||
transform *t;
|
||||
JS_GETATOM(js,t,sub,transform_atom,transform)
|
||||
HMM_Mat3 trmat = t->gcache3;
|
||||
|
||||
// Transform the base_quad's 4 points into sprite_quad
|
||||
for (int j = 0; j < 4; j++)
|
||||
sprite_quad.vert[j].pos = HMM_MulM3V3(trmat, base_quad[j]).xy;
|
||||
|
||||
// Use [0..3] for uv and color
|
||||
sprite_quad.vert[0].uv = (HMM_Vec2){ src.x, src.y + src.h };
|
||||
sprite_quad.vert[1].uv = (HMM_Vec2){ src.x+src.w, src.y + src.h };
|
||||
sprite_quad.vert[2].uv = (HMM_Vec2){ src.x, src.y };
|
||||
@@ -4051,31 +4133,55 @@ JSC_CCALL(gpu_make_sprite_queue,
|
||||
sprite_quad.vert[2].color = color;
|
||||
sprite_quad.vert[3].color = color;
|
||||
|
||||
// If you need to store into a bigger array:
|
||||
// sprites[i].quad = sprite_quad;
|
||||
// etc.
|
||||
sprite sp;
|
||||
sp.quad = sprite_quad;
|
||||
sp.image = JS_GetPropertyStr(js,sub,"image");
|
||||
sp.js = js;
|
||||
JS_GETPROP(js,sp.layer,sub,layer,number)
|
||||
sprites[i] = sp;
|
||||
sprites[i].sprite = JS_DupValue(js,sub);
|
||||
arrput(sprites,sp);
|
||||
|
||||
JS_FreeValue(js, sub);
|
||||
JS_FreeValue(js, jstransform);
|
||||
JS_FreeValue(js, sp.image);
|
||||
}
|
||||
|
||||
qsort(sprites, arrlen(sprites),sizeof(sprite),sort_sprite);
|
||||
|
||||
text_vert *buffer = NULL;
|
||||
for (int i = 0; i < quads; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
arrpush(buffer, sprites[i].quad.vert[j]);
|
||||
|
||||
JSValue mesh = quads_to_mesh(js, buffer);
|
||||
|
||||
arrfree(buffer);
|
||||
|
||||
ret = JS_NewArray(js);
|
||||
|
||||
for (int i = 0; i < quads; i++)
|
||||
JS_SetPropertyUint32(js,ret,i,sprites[i].sprite);
|
||||
int first_index = 0;
|
||||
int count = 0;
|
||||
int n = 0;
|
||||
JSValue img = JS_UNDEFINED;
|
||||
for (int i = 0; i < quads; i++) {
|
||||
if (!JS_SameValue(js,sprites[i].image, img)) {
|
||||
if (count > 0) {
|
||||
JSValue q = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js,q,"type", JS_NewString(js,"geometry"));
|
||||
JS_SetPropertyStr(js,q,"mesh", JS_DupValue(js,mesh));
|
||||
JS_SetPropertyStr(js,q,"pipeline", JS_DupValue(js,argv[2]));
|
||||
JS_SetPropertyStr(js,q,"image", JS_DupValue(js,img));
|
||||
JS_SetPropertyStr(js,q,"first_index", number2js(js,first_index));
|
||||
JS_SetPropertyStr(js,q,"num_indices",number2js(js,count*6));
|
||||
JS_SetPropertyUint32(js,ret,n++,q);
|
||||
}
|
||||
first_index = i*6;
|
||||
count = 1;
|
||||
JS_FreeValue(js,img);
|
||||
img = JS_DupValue(js,sprites[i].image);
|
||||
} else count++;
|
||||
JS_FreeValue(js,sprites[i].image);
|
||||
}
|
||||
|
||||
arrfree(sprites);
|
||||
JS_FreeValue(js,mesh);
|
||||
)
|
||||
|
||||
JSC_CCALL(gpu_make_sprite_mesh,
|
||||
@@ -4789,7 +4895,7 @@ static const JSCFunctionListEntry js_SDL_GPUDevice_funcs[] = {
|
||||
MIST_FUNC_DEF(gpu, load_texture, 2),
|
||||
MIST_FUNC_DEF(gpu, texture, 1),
|
||||
MIST_FUNC_DEF(gpu, make_sprite_mesh, 2),
|
||||
MIST_FUNC_DEF(gpu, make_sprite_queue, 1),
|
||||
MIST_FUNC_DEF(gpu, make_sprite_queue, 3),
|
||||
MIST_FUNC_DEF(gpu, make_quad, 0),
|
||||
MIST_FUNC_DEF(gpu, driver, 0),
|
||||
MIST_FUNC_DEF(gpu, make_shader, 1),
|
||||
@@ -5057,61 +5163,6 @@ JSC_CCALL(cmd_hud,
|
||||
SDL_PushGPUVertexUniformData(cmds, js2number(js,argv[1]), &data, sizeof(data));
|
||||
)
|
||||
|
||||
shader_globals camera_globals(JSContext *js, JSValue camera)
|
||||
{
|
||||
shader_globals data = {0};
|
||||
HMM_Vec2 size;
|
||||
transform *transform;
|
||||
double fov;
|
||||
double aspect;
|
||||
int ortho;
|
||||
double near;
|
||||
double far;
|
||||
|
||||
JS_GETPROP(js, size, camera, size, vec2)
|
||||
JS_GETPROP(js, transform, camera, transform, transform)
|
||||
JS_GETPROP(js, fov, camera, fov, number)
|
||||
JS_GETPROP(js, aspect, camera, aspect, number)
|
||||
JS_GETPROP(js, ortho, camera,ortho,bool)
|
||||
JS_GETPROP(js,near,camera,near,number)
|
||||
JS_GETPROP(js,far,camera,far,number)
|
||||
|
||||
HMM_Mat4 proj;
|
||||
HMM_Mat4 view;
|
||||
|
||||
if (ortho) {
|
||||
proj = HMM_Orthographic_RH_NO(
|
||||
-size.x*0.5, 0.5*size.x,
|
||||
-size.y*0.5, 0.5*size.y,
|
||||
-1.0f, 1.0f
|
||||
);
|
||||
view = HMM_Translate((HMM_Vec3){ -transform->pos.x, -transform->pos.y, 0.0f });
|
||||
}
|
||||
else {
|
||||
proj = HMM_Perspective_RH_NO(fov, aspect,near,far);
|
||||
|
||||
HMM_Mat4 camera_transform = HMM_Translate(transform->pos);
|
||||
camera_transform = HMM_MulM4(camera_transform, HMM_QToM4(transform->rotation));
|
||||
// camera_transform = HMM_MulM4(camera_transform, HMM_Scale(transform->scale)); // don't bother w/ scale
|
||||
view = HMM_InvGeneralM4(camera_transform);
|
||||
}
|
||||
|
||||
// Update your shader globals
|
||||
data.world_to_projection = HMM_MulM4(proj, view);
|
||||
data.projection_to_world = HMM_InvGeneralM4(data.world_to_projection);
|
||||
data.camera_pos_world = transform->pos;
|
||||
data.viewport_min_z = near;
|
||||
data.viewport_max_z = far;
|
||||
data.render_size = size;
|
||||
data.world_to_view = view;
|
||||
data.view_to_projection = proj;
|
||||
data.camera_dir_world = HMM_NormV3(HMM_QVRot((HMM_Vec3){0,0,-1},transform->rotation));
|
||||
data.viewport_size = (HMM_Vec2){0.5,0.5};
|
||||
data.viewport_offset = (HMM_Vec2){0,0};
|
||||
data.time = SDL_GetTicksNS() / 1000000000.0f;
|
||||
return data;
|
||||
}
|
||||
|
||||
JSC_CCALL(cmd_camera,
|
||||
SDL_GPUCommandBuffer *cmds = js2SDL_GPUCommandBuffer(js, self);
|
||||
shader_globals data = camera_globals(js, argv[0]);
|
||||
@@ -6963,39 +7014,12 @@ JSC_CCALL(os_cull_sprites,
|
||||
|
||||
int len = js_arrlen(js,sprites);
|
||||
|
||||
HMM_Vec2 corners[4] = {
|
||||
(HMM_Vec2){0,0},
|
||||
(HMM_Vec2){1,0},
|
||||
(HMM_Vec2){0,1},
|
||||
(HMM_Vec2){1,1},
|
||||
};
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
JSValue sub = JS_GetPropertyUint32(js,sprites, i);
|
||||
transform *t;
|
||||
JS_GETATOM(js,t,sub,transform_atom,transform)
|
||||
HMM_Mat3 trmat = t->gcache3;
|
||||
int outside = 0;
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
Uint64 start = SDL_GetTicksNS();
|
||||
HMM_Vec3 corner = HMM_MulM3V3(trmat, (HMM_Vec3){corners[j].x, corners[j].y, 1.0});
|
||||
HMM_Vec4 clip = HMM_MulM4V4(info.world_to_projection, (HMM_Vec4){corner.x,corner.y,corner.z,1.0});
|
||||
if (clip.w <= 0.0) {
|
||||
outside++;
|
||||
continue;
|
||||
}
|
||||
|
||||
float nx = clip.x/clip.w;
|
||||
float ny = clip.y/clip.w;
|
||||
float nz = clip.z/clip.w;
|
||||
|
||||
if (nx < -1 || nx > 1) outside++;
|
||||
else if (ny < -1 || ny > 1) outside++;
|
||||
else if (nz < -1 || nz > 1) outside++;
|
||||
}
|
||||
|
||||
if (outside != 4) {
|
||||
if (sprite_in_view(trmat, info.world_to_projection)) {
|
||||
JS_SetPropertyUint32(js,ret,n,JS_DupValue(js,sub));
|
||||
n++;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user