mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-29 15:41:59 +00:00
79e4a5f6a8
Canvas draw order is sorted by group then order within the group. As a fallback, the canvas entity id is used to keep the sort stable, but that's only as stable as the ids themselves (if the canvases are destroyed and recreated, the ids may switch around).
605 lines
18 KiB
C
605 lines
18 KiB
C
/*
|
|
canvas.c
|
|
|
|
Integration of 2d and 3d objects
|
|
|
|
Copyright (C) 2022 Bill Currie
|
|
|
|
Author: Bill Currie <bill@taniwha.org>
|
|
Date: 2022/12/12
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to:
|
|
|
|
Free Software Foundation, Inc.
|
|
59 Temple Place - Suite 330
|
|
Boston, MA 02111-1307, USA
|
|
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#define IMPLEMENT_CANVAS_Funcs
|
|
#include "QF/ui/canvas.h"
|
|
#include "QF/ui/imui.h"
|
|
#include "QF/ui/text.h"
|
|
#include "QF/ui/view.h"
|
|
|
|
#include "QF/plugin/vid_render.h"
|
|
|
|
static uint32_t
|
|
_canvas_rangeid (ecs_registry_t *reg, uint32_t ent, uint32_t comp, uint32_t c)
|
|
{
|
|
comp += canvas_canvas - c;
|
|
// view components come immediately after canvas components
|
|
uint32_t vcomp = view_href + comp + canvas_comp_count - canvas_canvas;
|
|
hierref_t *href = Ent_GetComponent (ent, vcomp, reg);
|
|
// the root entity of the hierarchy has the canvas component
|
|
uint32_t cent = href->hierarchy->ent[0];
|
|
canvas_t *canvas = Ent_GetComponent (cent, comp, reg);
|
|
return canvas->range[c];
|
|
}
|
|
|
|
#define canvas_rangeid(c) \
|
|
static uint32_t \
|
|
canvas_##c##_rangeid (ecs_registry_t *reg, uint32_t ent, uint32_t comp) \
|
|
{ \
|
|
return _canvas_rangeid (reg, ent, comp, canvas_##c); \
|
|
}
|
|
canvas_rangeid(update)
|
|
canvas_rangeid(updateonce)
|
|
canvas_rangeid(tile)
|
|
canvas_rangeid(pic)
|
|
canvas_rangeid(fitpic)
|
|
canvas_rangeid(subpic)
|
|
canvas_rangeid(cachepic)
|
|
canvas_rangeid(fill)
|
|
canvas_rangeid(charbuff)
|
|
canvas_rangeid(passage_glyphs)
|
|
canvas_rangeid(glyphs)
|
|
canvas_rangeid(func)
|
|
canvas_rangeid(lateupdate)
|
|
canvas_rangeid(outline)
|
|
#undef canvas_rangeid
|
|
|
|
static void
|
|
canvas_canvas_destroy (void *_canvas)
|
|
{
|
|
canvas_t *canvas = _canvas;
|
|
auto reg = canvas->reg;
|
|
for (uint32_t i = 0; i < canvas_canvas; i++) {
|
|
ECS_DelSubpoolRange (reg, canvas->base + i, canvas->range[i]);
|
|
}
|
|
}
|
|
|
|
const component_t canvas_components[canvas_comp_count] = {
|
|
[canvas_update] = {
|
|
.size = sizeof (canvas_update_f),
|
|
.name = "update",
|
|
.rangeid = canvas_update_rangeid,
|
|
},
|
|
[canvas_updateonce] = {
|
|
.size = sizeof (canvas_update_f),
|
|
.name = "updateonce",
|
|
.rangeid = canvas_updateonce_rangeid,
|
|
},
|
|
[canvas_tile] = {
|
|
.size = sizeof (byte),
|
|
.name = "tile",
|
|
.rangeid = canvas_tile_rangeid,
|
|
},
|
|
[canvas_pic] = {
|
|
.size = sizeof (qpic_t *),
|
|
.name = "pic",
|
|
.rangeid = canvas_pic_rangeid,
|
|
},
|
|
[canvas_fitpic] = {
|
|
.size = sizeof (qpic_t *),
|
|
.name = "fitpic",
|
|
.rangeid = canvas_fitpic_rangeid,
|
|
},
|
|
[canvas_subpic] = {
|
|
.size = sizeof (canvas_subpic_t),
|
|
.name = "subpic",
|
|
.rangeid = canvas_subpic_rangeid,
|
|
},
|
|
[canvas_cachepic] = {
|
|
.size = sizeof (const char *),
|
|
.name = "cachepic",
|
|
.rangeid = canvas_cachepic_rangeid,
|
|
},
|
|
[canvas_fill] = {
|
|
.size = sizeof (byte),
|
|
.name = "fill",
|
|
.rangeid = canvas_fill_rangeid,
|
|
},
|
|
[canvas_charbuff] = {
|
|
.size = sizeof (draw_charbuffer_t *),
|
|
.name = "charbuffer",
|
|
.rangeid = canvas_charbuff_rangeid,
|
|
},
|
|
[canvas_passage_glyphs] = {
|
|
.size = sizeof (glyphset_t),
|
|
.name = "passage glyphs (copy)",
|
|
.rangeid = canvas_passage_glyphs_rangeid,
|
|
},
|
|
[canvas_glyphs] = {
|
|
.size = sizeof (glyphset_t),
|
|
.name = "glyphs (copy)",
|
|
.rangeid = canvas_glyphs_rangeid,
|
|
},
|
|
[canvas_func] = {
|
|
.size = sizeof (canvas_func_f),
|
|
.name = "func",
|
|
.rangeid = canvas_func_rangeid,
|
|
},
|
|
[canvas_lateupdate] = {
|
|
.size = sizeof (canvas_update_f),
|
|
.name = "lateupdate",
|
|
.rangeid = canvas_lateupdate_rangeid,
|
|
},
|
|
[canvas_outline] = {
|
|
.size = sizeof (byte),
|
|
.name = "outline",
|
|
.rangeid = canvas_outline_rangeid,
|
|
},
|
|
[canvas_canvas] = {
|
|
.size = sizeof (canvas_t),
|
|
.name = "canvas",
|
|
.destroy = canvas_canvas_destroy,
|
|
},
|
|
};
|
|
|
|
typedef void (*canvas_sysfunc_f) (canvas_system_t *canvas_sys,
|
|
ecs_pool_t *pool, ecs_range_t range);
|
|
static void
|
|
draw_update (canvas_system_t *canvas_sys, ecs_pool_t *pool, ecs_range_t range)
|
|
{
|
|
ecs_system_t viewsys = { canvas_sys->reg, canvas_sys->view_base };
|
|
uint32_t count = range.end - range.start;
|
|
uint32_t *ent = pool->dense + range.start;
|
|
__auto_type func = (canvas_update_f *) pool->data + range.start;
|
|
while (count-- > 0) {
|
|
(*func++) (View_FromEntity (viewsys, *ent++));
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_tile_views (canvas_system_t *canvas_sys, ecs_pool_t *pool,
|
|
ecs_range_t range)
|
|
{
|
|
ecs_system_t viewsys = { canvas_sys->reg, canvas_sys->view_base };
|
|
uint32_t count = range.end - range.start;
|
|
uint32_t *ent = pool->dense + range.start;
|
|
while (count-- > 0) {
|
|
view_t view = View_FromEntity (viewsys, *ent++);
|
|
if (View_GetVisible (view)) {
|
|
view_pos_t pos = View_GetAbs (view);
|
|
view_pos_t len = View_GetLen (view);
|
|
r_funcs->Draw_TileClear (pos.x, pos.y, len.x, len.y);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_pic_views (canvas_system_t *canvas_sys, ecs_pool_t *pool,
|
|
ecs_range_t range)
|
|
{
|
|
ecs_system_t viewsys = { canvas_sys->reg, canvas_sys->view_base };
|
|
uint32_t count = range.end - range.start;
|
|
uint32_t *ent = pool->dense + range.start;
|
|
__auto_type pic = (qpic_t **) pool->data + range.start;
|
|
while (count-- > 0) {
|
|
view_t view = View_FromEntity (viewsys, *ent++);
|
|
if (View_GetVisible (view)) {
|
|
view_pos_t pos = View_GetAbs (view);
|
|
r_funcs->Draw_Pic (pos.x, pos.y, *pic);
|
|
}
|
|
pic++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_fitpic_views (canvas_system_t *canvas_sys, ecs_pool_t *pool,
|
|
ecs_range_t range)
|
|
{
|
|
ecs_system_t viewsys = { canvas_sys->reg, canvas_sys->view_base };
|
|
uint32_t count = range.end - range.start;
|
|
uint32_t *ent = pool->dense + range.start;
|
|
__auto_type pic = (qpic_t **) pool->data + range.start;
|
|
while (count-- > 0) {
|
|
view_t view = View_FromEntity (viewsys, *ent++);
|
|
if (View_GetVisible (view)) {
|
|
view_pos_t pos = View_GetAbs (view);
|
|
view_pos_t len = View_GetLen (view);
|
|
r_funcs->Draw_FitPic (pos.x, pos.y, len.x, len.y, *pic);
|
|
}
|
|
pic++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_subpic_views (canvas_system_t *canvas_sys, ecs_pool_t *pool,
|
|
ecs_range_t range)
|
|
{
|
|
ecs_system_t viewsys = { canvas_sys->reg, canvas_sys->view_base };
|
|
uint32_t count = range.end - range.start;
|
|
uint32_t *ent = pool->dense + range.start;
|
|
__auto_type subpic = (canvas_subpic_t *) pool->data + range.start;
|
|
while (count-- > 0) {
|
|
view_t view = View_FromEntity (viewsys, *ent++);
|
|
if (View_GetVisible (view)) {
|
|
view_pos_t pos = View_GetAbs (view);
|
|
r_funcs->Draw_SubPic (pos.x, pos.y, subpic->pic,
|
|
subpic->x, subpic->y, subpic->w, subpic->h);
|
|
}
|
|
subpic++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_cachepic_views (canvas_system_t *canvas_sys, ecs_pool_t *pool,
|
|
ecs_range_t range)
|
|
{
|
|
ecs_system_t viewsys = { canvas_sys->reg, canvas_sys->view_base };
|
|
uint32_t count = range.end - range.start;
|
|
uint32_t *ent = pool->dense + range.start;
|
|
__auto_type name = (const char **) pool->data + range.start;
|
|
while (count-- > 0) {
|
|
view_t view = View_FromEntity (viewsys, *ent++);
|
|
if (View_GetVisible (view)) {
|
|
view_pos_t pos = View_GetAbs (view);
|
|
qpic_t *pic = r_funcs->Draw_CachePic (*name, 1);
|
|
r_funcs->Draw_Pic (pos.x, pos.y, pic);
|
|
}
|
|
name++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_fill_views (canvas_system_t *canvas_sys, ecs_pool_t *pool,
|
|
ecs_range_t range)
|
|
{
|
|
ecs_system_t viewsys = { canvas_sys->reg, canvas_sys->view_base };
|
|
uint32_t count = range.end - range.start;
|
|
uint32_t *ent = pool->dense + range.start;
|
|
__auto_type fill = (byte *) pool->data + range.start;
|
|
while (count-- > 0) {
|
|
view_t view = View_FromEntity (viewsys, *ent++);
|
|
if (View_GetVisible (view)) {
|
|
view_pos_t pos = View_GetAbs (view);
|
|
view_pos_t len = View_GetLen (view);
|
|
r_funcs->Draw_Fill (pos.x, pos.y, len.x, len.y, *fill);
|
|
}
|
|
fill++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_charbuff_views (canvas_system_t *canvas_sys, ecs_pool_t *pool,
|
|
ecs_range_t range)
|
|
{
|
|
ecs_system_t viewsys = { canvas_sys->reg, canvas_sys->view_base };
|
|
uint32_t count = range.end - range.start;
|
|
uint32_t *ent = pool->dense + range.start;
|
|
__auto_type charbuff = (draw_charbuffer_t **) pool->data + range.start;
|
|
while (count-- > 0) {
|
|
view_t view = View_FromEntity (viewsys, *ent++);
|
|
if (View_GetVisible (view)) {
|
|
view_pos_t pos = View_GetAbs (view);
|
|
r_funcs->Draw_CharBuffer (pos.x, pos.y, *charbuff);
|
|
}
|
|
charbuff++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_func_views (canvas_system_t *canvas_sys, ecs_pool_t *pool,
|
|
ecs_range_t range)
|
|
{
|
|
ecs_system_t viewsys = { canvas_sys->reg, canvas_sys->view_base };
|
|
uint32_t count = range.end - range.start;
|
|
uint32_t *ent = pool->dense + range.start;
|
|
__auto_type func = (canvas_func_f *) pool->data + range.start;
|
|
while (count-- > 0) {
|
|
view_t view = View_FromEntity (viewsys, *ent++);
|
|
if (View_GetVisible (view)) {
|
|
view_pos_t pos = View_GetAbs (view);
|
|
view_pos_t len = View_GetLen (view);
|
|
(*func) (pos, len);
|
|
}
|
|
func++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_outline_views (canvas_system_t *canvas_sys, ecs_pool_t *pool,
|
|
ecs_range_t range)
|
|
{
|
|
ecs_system_t viewsys = { canvas_sys->reg, canvas_sys->view_base };
|
|
uint32_t count = range.end - range.start;
|
|
uint32_t *ent = pool->dense + range.start;
|
|
__auto_type col = (byte *) pool->data + range.start;
|
|
__auto_type line = r_funcs->Draw_Line;
|
|
while (count-- > 0) {
|
|
view_t view = View_FromEntity (viewsys, *ent++);
|
|
byte c = *col++;
|
|
if (View_GetVisible (view)) {
|
|
view_pos_t p = View_GetAbs (view);
|
|
view_pos_t l = View_GetLen (view);
|
|
view_pos_t q = { p.x + l.x - 1, p.y + l.y - 1 };
|
|
line (p.x, p.y, q.x, p.y, c);
|
|
line (p.x, q.y, q.x, q.y, c);
|
|
line (p.x, p.y, p.x, q.y, c);
|
|
line (q.x, p.y, q.x, q.y, c);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_glyph_refs (view_pos_t *abs, glyphset_t *glyphset, glyphref_t *gref,
|
|
uint32_t color)
|
|
{
|
|
uint32_t count = gref->count;
|
|
glyphobj_t *glyph = glyphset->glyphs + gref->start;
|
|
|
|
while (count-- > 0) {
|
|
glyphobj_t *g = glyph++;
|
|
r_funcs->Draw_Glyph (abs->x + g->x, abs->y + g->y,
|
|
g->fontid, g->glyphid, color);
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_box (view_pos_t *abs, view_pos_t *len, uint32_t ind, int c)
|
|
{
|
|
int x = abs[ind].x;
|
|
int y = abs[ind].y;
|
|
int w = len[ind].x;
|
|
int h = len[ind].y;
|
|
r_funcs->Draw_Line (x, y, x + w, y, c);
|
|
r_funcs->Draw_Line (x, y + h, x + w, y + h, c);
|
|
r_funcs->Draw_Line (x, y, x, y + h, c);
|
|
r_funcs->Draw_Line (x + w, y, x + w, y + h, c);
|
|
}
|
|
|
|
static void
|
|
draw_glyphs (canvas_system_t *canvas_sys, ecs_pool_t *pool, ecs_range_t range)
|
|
{
|
|
auto reg = canvas_sys->reg;
|
|
uint32_t glyphs = canvas_sys->text_base + text_glyphs;
|
|
uint32_t color = canvas_sys->text_base + text_color;
|
|
uint32_t vhref = canvas_sys->view_base + view_href;
|
|
uint32_t count = range.end - range.start;
|
|
uint32_t *ent = pool->dense + range.start;
|
|
auto glyphset = (glyphset_t *) pool->data + range.start;
|
|
|
|
while (count-- > 0) {
|
|
view_t view = { .id = *ent++, .reg = reg, .comp = vhref};
|
|
glyphset_t *gs = glyphset++;
|
|
if (View_GetVisible (view)) {
|
|
view_pos_t abs = View_GetAbs (view);
|
|
glyphref_t *gref = Ent_GetComponent (view.id, glyphs, reg);
|
|
uint32_t *c = Ent_SafeGetComponent (view.id, color, reg);
|
|
draw_glyph_refs (&abs, gs, gref, c ? *c : 254);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_passage_glyphs (canvas_system_t *canvas_sys, ecs_pool_t *pool,
|
|
ecs_range_t range)
|
|
{
|
|
auto reg = canvas_sys->reg;
|
|
uint32_t glyphs = canvas_sys->text_base + text_glyphs;
|
|
uint32_t color = canvas_sys->text_base + text_color;
|
|
uint32_t vhref = canvas_sys->view_base + view_href;
|
|
uint32_t count = range.end - range.start;
|
|
uint32_t *ent = pool->dense + range.start;
|
|
auto glyphset = (glyphset_t *) pool->data + range.start;
|
|
|
|
while (count-- > 0) {
|
|
view_t psg_view = { .id = *ent++, .reg = reg, .comp = vhref};
|
|
// first child is always a paragraph view, and all views after the
|
|
// first paragraph's first child are all text views
|
|
view_t para_view = View_GetChild (psg_view, 0);
|
|
view_t text_view = View_GetChild (para_view, 0);
|
|
hierref_t *href = View_GetRef (text_view);
|
|
glyphset_t *gs = glyphset++;
|
|
hierarchy_t *h = href->hierarchy;
|
|
view_pos_t *abs = h->components[view_abs];
|
|
view_pos_t *len = h->components[view_len];
|
|
|
|
for (uint32_t i = href->index; i < h->num_objects; i++) {
|
|
glyphref_t *gref = Ent_GetComponent (h->ent[i], glyphs, reg);
|
|
uint32_t *c = Ent_SafeGetComponent (h->ent[i], color, reg);
|
|
draw_glyph_refs (&abs[i], gs, gref, c ? *c : 254);
|
|
|
|
if (0) draw_box (abs, len, i, 253);
|
|
}
|
|
if (0) {
|
|
for (uint32_t i = 1; i < href->index; i++) {
|
|
draw_box (abs, len, i, 251);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
Canvas_Draw (canvas_system_t canvas_sys)
|
|
{
|
|
static canvas_sysfunc_f draw_func[canvas_comp_count] = {
|
|
[canvas_update] = draw_update,
|
|
[canvas_updateonce] = draw_update,
|
|
[canvas_tile] = draw_tile_views,
|
|
[canvas_pic] = draw_pic_views,
|
|
[canvas_fitpic] = draw_fitpic_views,
|
|
[canvas_subpic] = draw_subpic_views,
|
|
[canvas_cachepic] = draw_cachepic_views,
|
|
[canvas_fill] = draw_fill_views,
|
|
[canvas_charbuff] = draw_charbuff_views,
|
|
[canvas_passage_glyphs] = draw_passage_glyphs,
|
|
[canvas_glyphs] = draw_glyphs,
|
|
[canvas_func] = draw_func_views,
|
|
[canvas_lateupdate] = draw_update,
|
|
[canvas_outline] = draw_outline_views,
|
|
};
|
|
|
|
auto reg = canvas_sys.reg;
|
|
uint32_t comp = canvas_sys.base + canvas_canvas;
|
|
ecs_pool_t *canvas_pool = ®->comp_pools[comp];
|
|
uint32_t count = canvas_pool->count;
|
|
//uint32_t *entities = canvas_pool->dense;
|
|
__auto_type canvases = (canvas_t *) canvas_pool->data;
|
|
|
|
while (count-- > 0) {
|
|
canvas_t *canvas = canvases++;
|
|
//uint32_t ent = *entities++;
|
|
|
|
if (!canvas->visible) {
|
|
continue;
|
|
}
|
|
|
|
for (int i = 0; i < canvas_comp_count; i++) {
|
|
if (draw_func[i]) {
|
|
uint32_t c = canvas_sys.base + i;
|
|
uint32_t rid = canvas->range[i];
|
|
ecs_range_t range = ECS_GetSubpoolRange (reg, c, rid);
|
|
if (range.end - range.start) {
|
|
ecs_pool_t *pool = ®->comp_pools[c];
|
|
draw_func[i] (&canvas_sys, pool, range);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
{
|
|
ecs_pool_t *pool = ®->comp_pools[canvas_updateonce];
|
|
ecs_subpool_t *subpool = ®->subpools[canvas_updateonce];
|
|
pool->count = 0;
|
|
uint32_t rcount = subpool->num_ranges - subpool->available;
|
|
memset (subpool->ranges, 0, rcount * sizeof (*subpool->ranges));
|
|
}
|
|
}
|
|
|
|
void
|
|
Canvas_InitSys (canvas_system_t *canvas_sys, ecs_registry_t *reg)
|
|
{
|
|
*canvas_sys = (canvas_system_t) {
|
|
.reg = reg,
|
|
.base = ECS_RegisterComponents (reg, canvas_components,
|
|
canvas_comp_count),
|
|
.view_base = ECS_RegisterComponents (reg, view_components,
|
|
view_comp_count),
|
|
.text_base = ECS_RegisterComponents (reg, text_components,
|
|
text_comp_count),
|
|
.imui_base = ECS_RegisterComponents (reg, imui_components,
|
|
imui_comp_count),
|
|
};
|
|
}
|
|
|
|
void
|
|
Canvas_AddToEntity (canvas_system_t canvas_sys, uint32_t ent)
|
|
{
|
|
canvas_t canvas = {
|
|
.reg = canvas_sys.reg,
|
|
.base = canvas_sys.base,
|
|
.visible = true
|
|
};
|
|
for (uint32_t i = 0; i < canvas_canvas; i++) {
|
|
canvas.range[i] = ECS_NewSubpoolRange (canvas_sys.reg,
|
|
canvas_sys.base + i);
|
|
}
|
|
Ent_SetComponent (ent, canvas_sys.base + canvas_canvas, canvas_sys.reg,
|
|
&canvas);
|
|
View_AddToEntity (ent,
|
|
(ecs_system_t) { canvas_sys.reg, canvas_sys.view_base },
|
|
nullview);
|
|
}
|
|
|
|
uint32_t
|
|
Canvas_New (canvas_system_t canvas_sys)
|
|
{
|
|
uint32_t ent = ECS_NewEntity (canvas_sys.reg);
|
|
Canvas_AddToEntity (canvas_sys, ent);
|
|
return ent;
|
|
}
|
|
|
|
static int
|
|
canvas_href_cmp (const void *_a, const void *_b, void *arg)
|
|
{
|
|
uint32_t enta = *(const uint32_t *)_a;
|
|
uint32_t entb = *(const uint32_t *)_b;
|
|
canvas_system_t *canvas_sys = arg;
|
|
ecs_registry_t *reg = canvas_sys->reg;
|
|
uint32_t href = canvas_sys->view_base + view_href;
|
|
hierref_t *ref_a = Ent_GetComponent (enta, href, reg);
|
|
hierref_t *ref_b = Ent_GetComponent (entb, href, reg);
|
|
if (ref_a->hierarchy == ref_b->hierarchy) {
|
|
return ref_a->index - ref_b->index;
|
|
}
|
|
ptrdiff_t diff = ref_a->hierarchy - ref_b->hierarchy;
|
|
return diff > 0 ? 1 : diff < 0 ? -1 : 0;
|
|
}
|
|
|
|
void
|
|
Canvas_SortComponentPool (canvas_system_t canvas_sys, uint32_t ent,
|
|
uint32_t component)
|
|
{
|
|
canvas_t *canvas = Ent_GetComponent (ent, canvas_sys.base + canvas_canvas,
|
|
canvas_sys.reg);
|
|
uint32_t rid = canvas->range[component];
|
|
uint32_t c = component + canvas_sys.base;
|
|
ecs_range_t range = ECS_GetSubpoolRange (canvas_sys.reg, c, rid);
|
|
ECS_SortComponentPoolRange (canvas_sys.reg, c, range,
|
|
canvas_href_cmp, &canvas_sys);
|
|
}
|
|
|
|
void
|
|
Canvas_SetLen (canvas_system_t canvas_sys, uint32_t ent, view_pos_t len)
|
|
{
|
|
view_t view = Canvas_GetRootView (canvas_sys, ent);
|
|
View_SetLen (view, len.x, len.y);
|
|
View_UpdateHierarchy (view);
|
|
}
|
|
|
|
static int
|
|
canvas_draw_cmp (const void *_a, const void *_b, void *arg)
|
|
{
|
|
uint32_t enta = *(const uint32_t *)_a;
|
|
uint32_t entb = *(const uint32_t *)_b;
|
|
canvas_system_t *canvas_sys = arg;
|
|
auto reg = canvas_sys->reg;
|
|
uint32_t c_canvas = canvas_sys->base + canvas_canvas;
|
|
auto canvasa = (canvas_t *) Ent_GetComponent (enta, c_canvas, reg);
|
|
auto canvasb = (canvas_t *) Ent_GetComponent (entb, c_canvas, reg);
|
|
int diff = canvasa->draw_group - canvasb->draw_group;
|
|
if (!diff) {
|
|
diff = canvasa->draw_order - canvasb->draw_order;
|
|
}
|
|
if (!diff) {
|
|
// order possibly undefined, but at least stable so long as the entity
|
|
// ids are stable
|
|
diff = enta - entb;
|
|
}
|
|
return diff;
|
|
}
|
|
|
|
void
|
|
Canvas_DrawSort (canvas_system_t canvas_sys)
|
|
{
|
|
auto reg = canvas_sys.reg;
|
|
uint32_t c_canvas = canvas_sys.base + canvas_canvas;
|
|
ECS_SortComponentPool (reg, c_canvas, canvas_draw_cmp, &canvas_sys);
|
|
}
|