mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 07:11:41 +00:00
[ui] Add a canvas system
This is the beginning of supporting 2d rendering in 3d space. The idea is that a canvas can be in 2d orthographic space (not attached to any entity with a 3d transform), or in 3d perspective space (attached to an entity with a 3d transform, either as a child of the camera, or of some object in 3d space). It will replace the current HUD code when it's working.
This commit is contained in:
parent
3a2877dd9a
commit
6decbd18c4
4 changed files with 444 additions and 0 deletions
|
@ -170,8 +170,11 @@ include_qf_simd = \
|
|||
include/QF/simd/vec4i.h
|
||||
|
||||
include_qf_ui = \
|
||||
include/QF/ui/canvas.h \
|
||||
include/QF/ui/font.h \
|
||||
include/QF/ui/inputline.h \
|
||||
include/QF/ui/passage.h \
|
||||
include/QF/ui/text.h \
|
||||
include/QF/ui/txtbuffer.h \
|
||||
include/QF/ui/view.h \
|
||||
include/QF/ui/vrect.h
|
||||
|
|
87
include/QF/ui/canvas.h
Normal file
87
include/QF/ui/canvas.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
canvas.h
|
||||
|
||||
Integration of 2d and 3d objects
|
||||
|
||||
Copyright (C) 2022 Bill Currie <bill@taniwha.org>
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __QF_scene_canvas_h
|
||||
#define __QF_scene_canvas_h
|
||||
|
||||
#include "QF/ecs.h"
|
||||
|
||||
enum {
|
||||
canvas_update,
|
||||
canvas_updateonce,
|
||||
canvas_tile,
|
||||
canvas_pic,
|
||||
canvas_subpic,
|
||||
canvas_cachepic,
|
||||
canvas_fill,
|
||||
canvas_charbuff,
|
||||
canvas_func,
|
||||
canvas_outline,
|
||||
|
||||
// last so deleting an entity removes the grouped components first
|
||||
canvas_canvas,
|
||||
|
||||
canvas_comp_count
|
||||
};
|
||||
|
||||
typedef struct canvas_s {
|
||||
ecs_registry_t *reg;
|
||||
uint32_t ent;
|
||||
uint32_t base;
|
||||
uint32_t text_base;
|
||||
uint32_t view_base;
|
||||
uint32_t range[canvas_comp_count];
|
||||
} canvas_t;
|
||||
|
||||
extern const struct component_s canvas_components[canvas_comp_count];
|
||||
|
||||
typedef struct canvas_system_s {
|
||||
ecs_registry_t *reg;
|
||||
uint32_t text_base;
|
||||
uint32_t view_base;
|
||||
} canvas_system_t;
|
||||
|
||||
struct view_s;
|
||||
struct view_pos_s;
|
||||
|
||||
typedef void (*canvas_update_f) (struct view_s);
|
||||
typedef void (*canvas_func_f) (struct view_pos_s, struct view_pos_s);
|
||||
|
||||
typedef struct canvas_subpic_s {
|
||||
struct qpic_s *pic;
|
||||
uint32_t x, y;
|
||||
uint32_t w, h;
|
||||
} canvas_subpic_t;
|
||||
|
||||
void Canvas_AddToEntity (ecs_system_t canvas_sys, uint32_t text_base,
|
||||
uint32_t view_base, uint32_t ent);
|
||||
void Canvas_Draw (uint32_t canvas_base, canvas_system_t canvas_sys);
|
||||
|
||||
#endif//__QF_scene_canvas_h
|
|
@ -15,6 +15,7 @@ libs_ui_libQFgui_la_LDFLAGS= $(lib_ldflags)
|
|||
libs_ui_libQFgui_la_LIBADD= $(gui_deps) $(ui_deps)
|
||||
libs_ui_libQFgui_la_DEPENDENCIES= $(gui_deps) $(ui_deps)
|
||||
libs_ui_libQFgui_la_SOURCES= \
|
||||
libs/ui/canvas.c \
|
||||
libs/ui/font.c \
|
||||
libs/ui/text.c
|
||||
|
||||
|
|
353
libs/ui/canvas.c
Normal file
353
libs/ui/canvas.c
Normal file
|
@ -0,0 +1,353 @@
|
|||
/*
|
||||
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
|
||||
|
||||
#include "QF/ui/canvas.h"
|
||||
#include "QF/ui/text.h"
|
||||
#include "QF/ui/view.h"
|
||||
|
||||
#include "QF/plugin/vid_render.h"
|
||||
|
||||
#define canvas_rangeid(c) \
|
||||
static uint32_t \
|
||||
canvas_##c##_rangeid (ecs_registry_t *reg, uint32_t ent, uint32_t comp) \
|
||||
{ \
|
||||
comp += canvas_canvas - canvas_##c; \
|
||||
canvas_t *canvas = Ent_GetComponent (ent, comp, reg); \
|
||||
return canvas->range[canvas_##c]; \
|
||||
}
|
||||
canvas_rangeid(update)
|
||||
canvas_rangeid(updateonce)
|
||||
canvas_rangeid(tile)
|
||||
canvas_rangeid(pic)
|
||||
canvas_rangeid(subpic)
|
||||
canvas_rangeid(cachepic)
|
||||
canvas_rangeid(fill)
|
||||
canvas_rangeid(charbuff)
|
||||
canvas_rangeid(func)
|
||||
canvas_rangeid(outline)
|
||||
#undef canvas_rangeid
|
||||
|
||||
static void
|
||||
canvas_canvas_destroy (void *_canvas)
|
||||
{
|
||||
}
|
||||
|
||||
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 = "pic",
|
||||
.rangeid = canvas_tile_rangeid,
|
||||
},
|
||||
[canvas_pic] = {
|
||||
.size = sizeof (qpic_t *),
|
||||
.name = "pic",
|
||||
.rangeid = canvas_pic_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_func] = {
|
||||
.size = sizeof (canvas_func_f),
|
||||
.name = "func",
|
||||
.rangeid = canvas_func_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;
|
||||
__auto_type func = (canvas_update_f *) pool->data + range.start;
|
||||
while (count-- > 0) {
|
||||
(*func++) (View_FromEntity (viewsys, *ent++));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
draw_updateonce (canvas_system_t *canvas_sys, ecs_pool_t *pool,
|
||||
ecs_range_t range)
|
||||
{
|
||||
draw_update (canvas_sys, pool, range);
|
||||
pool->count = 0;//XXX FIXME hmm, what to do with ranges
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
__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_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;
|
||||
__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;
|
||||
__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;
|
||||
__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;
|
||||
__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;
|
||||
__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;
|
||||
__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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Canvas_Draw (uint32_t canvas_base, canvas_system_t canvas_sys)
|
||||
{
|
||||
static canvas_sysfunc_f draw_func[canvas_comp_count] = {
|
||||
[canvas_update] = draw_update,
|
||||
[canvas_updateonce] = draw_updateonce,
|
||||
[canvas_tile] = draw_tile_views,
|
||||
[canvas_pic] = draw_pic_views,
|
||||
[canvas_subpic] = draw_subpic_views,
|
||||
[canvas_cachepic] = draw_cachepic_views,
|
||||
[canvas_fill] = draw_fill_views,
|
||||
[canvas_charbuff] = draw_charbuff_views,
|
||||
[canvas_func] = draw_func_views,
|
||||
[canvas_outline] = draw_outline_views,
|
||||
};
|
||||
|
||||
uint32_t comp = canvas_base + canvas_canvas;
|
||||
ecs_pool_t *pool = &canvas_sys.reg->comp_pools[comp];
|
||||
uint32_t count = pool->count;
|
||||
//uint32_t *entities = pool->dense;
|
||||
__auto_type canvases = (canvas_t *) pool->data;
|
||||
|
||||
while (count-- > 0) {
|
||||
canvas_t *canvas = canvases++;
|
||||
//uint32_t ent = *entities++;
|
||||
|
||||
for (int i = 0; i < canvas_comp_count; i++) {
|
||||
uint32_t c = canvas_base + i;
|
||||
uint32_t rid = canvas->range[i];
|
||||
ecs_range_t range = ECS_GetSubpoolRange (canvas_sys.reg, c, rid);
|
||||
if (draw_func[i]) {
|
||||
ecs_pool_t *pool = &canvas_sys.reg->comp_pools[c];
|
||||
draw_func[i] (&canvas_sys, pool, range);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < canvas_comp_count; i++) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Canvas_AddToEntity (ecs_system_t canvas_sys, uint32_t text_base,
|
||||
uint32_t view_base, uint32_t ent)
|
||||
{
|
||||
canvas_t canvas = {
|
||||
.reg = canvas_sys.reg,
|
||||
.ent = ent,
|
||||
.text_base = text_base,
|
||||
.view_base = view_base,
|
||||
};
|
||||
for (uint32_t i = 0; i < canvas_comp_count; i++) {
|
||||
canvas.range[i] = ECS_NewSubpoolRange (canvas.reg, canvas.base + i);
|
||||
}
|
||||
Ent_SetComponent (ent, canvas.base + canvas_canvas, canvas.reg, &canvas);
|
||||
View_AddToEntity (ent, (ecs_system_t) { canvas.reg, view_base }, nullview);
|
||||
}
|
Loading…
Reference in a new issue