diff --git a/include/QF/GL/qf_draw.h b/include/QF/GL/qf_draw.h index 30315e7b0..7a7283c5c 100644 --- a/include/QF/GL/qf_draw.h +++ b/include/QF/GL/qf_draw.h @@ -30,9 +30,11 @@ struct qpic_s; struct rfont_s; +struct draw_charbuffer_s; void gl_Draw_Init (void); void gl_Draw_Shutdown (void); +void gl_Draw_CharBuffer (int x, int y, struct draw_charbuffer_s *buffer); void gl_Draw_Character (int x, int y, unsigned ch); void gl_Draw_String (int x, int y, const char *str); void gl_Draw_nString (int x, int y, const char *str, int count); diff --git a/include/QF/GLSL/qf_draw.h b/include/QF/GLSL/qf_draw.h index ea9b3e5dc..59ecb1668 100644 --- a/include/QF/GLSL/qf_draw.h +++ b/include/QF/GLSL/qf_draw.h @@ -30,9 +30,11 @@ struct qpic_s; struct rfont_s; +struct draw_charbuffer_s; void glsl_Draw_Init (void); void glsl_Draw_Shutdown (void); +void glsl_Draw_CharBuffer (int x, int y, struct draw_charbuffer_s *buffer); void glsl_Draw_Character (int x, int y, unsigned ch); void glsl_Draw_String (int x, int y, const char *str); void glsl_Draw_nString (int x, int y, const char *str, int count); diff --git a/include/QF/Vulkan/qf_draw.h b/include/QF/Vulkan/qf_draw.h index 8006d1007..1da531fb1 100644 --- a/include/QF/Vulkan/qf_draw.h +++ b/include/QF/Vulkan/qf_draw.h @@ -32,7 +32,10 @@ struct vulkan_ctx_s; struct qfv_renderframe_s; struct qpic_s; struct rfont_s; +struct draw_charbuffer_s; +void Vulkan_Draw_CharBuffer (int x, int y, struct draw_charbuffer_s *buffer, + struct vulkan_ctx_s *ctx); void Vulkan_Draw_Init (struct vulkan_ctx_s *ctx); void Vulkan_Draw_Shutdown (struct vulkan_ctx_s *ctx); void Vulkan_Draw_Character (int x, int y, unsigned ch, diff --git a/include/QF/draw.h b/include/QF/draw.h index 532ea7a54..6646ad90a 100644 --- a/include/QF/draw.h +++ b/include/QF/draw.h @@ -41,6 +41,23 @@ #include "QF/wad.h" +/** Buffer for drawing text using quake conchars or the default 8x8 font. + + Characters are stored with the first character in the upper left, scanning + horizontally to the right. +*/ +typedef struct draw_charbuffer_s { + int width; ///< width in character cells + int height; ///< height in character cells + char *chars; ///< width * height characters +} draw_charbuffer_t; + +draw_charbuffer_t *Draw_CreateBuffer (int width, int height); +void Draw_DestroyBuffer (draw_charbuffer_t *buffer); +void Draw_ClearBuffer (draw_charbuffer_t *buffer); +void Draw_ScrollBuffer (draw_charbuffer_t *buffer, int lines); +void Draw_CharBuffer (int x, int y, draw_charbuffer_t *buffer); + extern byte *draw_chars; /** Initialize the draw stuff. diff --git a/include/QF/plugin/vid_render.h b/include/QF/plugin/vid_render.h index 81365fbcd..b8b0bbda0 100644 --- a/include/QF/plugin/vid_render.h +++ b/include/QF/plugin/vid_render.h @@ -79,10 +79,13 @@ typedef struct vid_model_funcs_s { struct tex_s; struct rfont_s; +struct draw_charbuffer_s; + typedef void (*capfunc_t) (struct tex_s *screencap, void *data); typedef struct vid_render_funcs_s { void (*init) (void); + void (*Draw_CharBuffer) (int x, int y, struct draw_charbuffer_s *buffer); void (*Draw_Character) (int x, int y, unsigned ch); void (*Draw_String) (int x, int y, const char *str); void (*Draw_nString) (int x, int y, const char *str, int count); diff --git a/include/d_iface.h b/include/d_iface.h index b687e8df1..7f05c38bf 100644 --- a/include/d_iface.h +++ b/include/d_iface.h @@ -226,4 +226,7 @@ extern float r_skytime; extern int c_surf; +struct draw_charbuffer_s; +void sw_Draw_CharBuffer (int x, int y, struct draw_charbuffer_s *buffer); + #endif // _D_IFACE_H diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index ca603d9e1..6d3db7023 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -50,6 +50,7 @@ libs_video_renderer_libQFrenderer_la_DEPENDENCIES= $(renderer_libs) libs_video_renderer_libQFrenderer_la_SOURCES=\ libs/video/renderer/r_bsp.c \ libs/video/renderer/r_cvar.c \ + libs/video/renderer/r_draw.c \ libs/video/renderer/r_efrag.c \ libs/video/renderer/r_fog.c \ libs/video/renderer/r_font.c \ diff --git a/libs/video/renderer/gl/gl_draw.c b/libs/video/renderer/gl/gl_draw.c index a12cdf86c..9ee389775 100644 --- a/libs/video/renderer/gl/gl_draw.c +++ b/libs/video/renderer/gl/gl_draw.c @@ -486,6 +486,21 @@ tVA_increment (void) flush_text (); } +void +gl_Draw_CharBuffer (int x, int y, draw_charbuffer_t *buffer) +{ + const byte *line = (byte *) buffer->chars; + int width = buffer->width; + int height = buffer->height; + while (height-- > 0) { + for (int i = 0; i < width; i++) { + gl_Draw_Character (x + i * 8, y, line[i]); + } + line += width; + y += 8; + } +} + /* Draw_Character diff --git a/libs/video/renderer/glsl/glsl_draw.c b/libs/video/renderer/glsl/glsl_draw.c index dcd9b0fb7..6258d3048 100644 --- a/libs/video/renderer/glsl/glsl_draw.c +++ b/libs/video/renderer/glsl/glsl_draw.c @@ -485,6 +485,21 @@ flush_2d (void) line_queue->size = 0; } +void +glsl_Draw_CharBuffer (int x, int y, draw_charbuffer_t *buffer) +{ + const byte *line = (byte *) buffer->chars; + int width = buffer->width; + int height = buffer->height; + while (height-- > 0) { + for (int i = 0; i < width; i++) { + glsl_Draw_Character (x + i * 8, y, line[i]); + } + line += width; + y += 8; + } +} + void glsl_Draw_Character (int x, int y, unsigned int chr) { diff --git a/libs/video/renderer/r_draw.c b/libs/video/renderer/r_draw.c new file mode 100644 index 000000000..207980f88 --- /dev/null +++ b/libs/video/renderer/r_draw.c @@ -0,0 +1,88 @@ +/* + r_draw.c + + Renderer general draw support + + Copyright (C) 2022 Bill Currie + + 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 +#include + +#include "QF/draw.h" +#include "QF/render.h" + +#include "QF/plugin/vid_render.h" + +VISIBLE draw_charbuffer_t * +Draw_CreateBuffer (int width, int height) +{ + size_t size = width * height; + draw_charbuffer_t *buffer = malloc (sizeof (draw_charbuffer_t) + size); + buffer->width = width; + buffer->height = height; + buffer->chars = (char *) (buffer + 1); + return buffer; +} + +VISIBLE void +Draw_DestroyBuffer (draw_charbuffer_t *buffer) +{ + free (buffer); +} + +VISIBLE void +Draw_ClearBuffer (draw_charbuffer_t *buffer) +{ + memset (buffer->chars, ' ', buffer->height * buffer->width); +} + +VISIBLE void +Draw_ScrollBuffer (draw_charbuffer_t *buffer, int lines) +{ + int down = 0; + if (lines < 0) { + lines = -lines; + down = 1; + } + if (lines > buffer->height) { + lines = buffer->height; + } + if (down) { + memmove (buffer->chars + lines * buffer->width, buffer->chars, + (buffer->height - lines) * buffer->width); + memset (buffer->chars, ' ', lines * buffer->width); + } else { + memmove (buffer->chars, buffer->chars + lines * buffer->width, + (buffer->height - lines) * buffer->width); + memset (buffer->chars + (buffer->height - lines) * buffer->width, ' ', + lines * buffer->width); + } +} + +VISIBLE void +Draw_CharBuffer (int x, int y, draw_charbuffer_t *buffer) +{ + r_funcs->Draw_CharBuffer (x, y, buffer); +} diff --git a/libs/video/renderer/r_progs.c b/libs/video/renderer/r_progs.c index 95f199242..7f20c0663 100644 --- a/libs/video/renderer/r_progs.c +++ b/libs/video/renderer/r_progs.c @@ -63,10 +63,17 @@ typedef struct qpic_res_s { char *name; } qpic_res_t; +typedef struct bi_charbuff_s { + struct bi_charbuff_s *next; + draw_charbuffer_t *buffer; +} bi_charbuff_t; + typedef struct { PR_RESMAP (qpic_res_t) qpic_map; + PR_RESMAP (bi_charbuff_t) charbuff_map; qpic_res_t *qpics; hashtab_t *pic_hash; + bi_charbuff_t *charbuffs; } draw_resources_t; static qpic_res_t * @@ -121,6 +128,47 @@ get_qpic (progs_t *pr, draw_resources_t *res, const char *name, int qpic_handle) return qp; } +static bi_charbuff_t * +charbuff_new (draw_resources_t *res) +{ + return PR_RESNEW (res->charbuff_map); +} + +static void +charbuff_free (draw_resources_t *res, bi_charbuff_t *cbuff) +{ + Draw_DestroyBuffer (cbuff->buffer); + PR_RESFREE (res->charbuff_map, cbuff); +} + +static void +charbuff_reset (draw_resources_t *res) +{ + PR_RESRESET (res->charbuff_map); +} + +static inline bi_charbuff_t * +charbuff_get (draw_resources_t *res, int index) +{ + return PR_RESGET (res->charbuff_map, index); +} + +static inline int __attribute__((pure)) +charbuff_index (draw_resources_t *res, bi_charbuff_t *qp) +{ + return PR_RESINDEX (res->charbuff_map, qp); +} + +static bi_charbuff_t * __attribute__((pure)) +get_charbuff (progs_t *pr, draw_resources_t *res, const char *name, int charbuff_handle) +{ + bi_charbuff_t *cbuff = charbuff_get (res, charbuff_handle); + + if (!cbuff) + PR_RunError (pr, "invalid charbuff handle passed to %s", name + 3); + return cbuff; +} + static void bi_Draw_FreePic (progs_t *pr, void *_res) { @@ -354,6 +402,66 @@ bi_Font_String (progs_t *pr, void *_res) r_funcs->Draw_FontString (x, y, str); } +static void +bi_Draw_CreateBuffer (progs_t *pr, void *_res) +{ + draw_resources_t *res = _res; + int width = P_INT (pr, 0); + int height = P_INT (pr, 1); + draw_charbuffer_t *buffer; + bi_charbuff_t *cbuff; + + buffer = Draw_CreateBuffer (width, height); + cbuff = charbuff_new (res); + cbuff->next = res->charbuffs; + res->charbuffs = cbuff; + cbuff->buffer = buffer; + R_INT (pr) = charbuff_index (res, cbuff); +} + +static void +bi_Draw_DestroyBuffer (progs_t *pr, void *_res) +{ + draw_resources_t *res = _res; + pr_ptr_t cbuff_handle = P_POINTER (pr, 0); + bi_charbuff_t *cbuff = get_charbuff (pr, res, __FUNCTION__, cbuff_handle); + + charbuff_free (res, cbuff); +} + +static void +bi_Draw_ClearBuffer (progs_t *pr, void *_res) +{ + draw_resources_t *res = _res; + pr_ptr_t cbuff_handle = P_POINTER (pr, 0); + bi_charbuff_t *cbuff = get_charbuff (pr, res, __FUNCTION__, cbuff_handle); + + Draw_ClearBuffer (cbuff->buffer); +} + +static void +bi_Draw_ScrollBuffer (progs_t *pr, void *_res) +{ + draw_resources_t *res = _res; + pr_ptr_t cbuff_handle = P_POINTER (pr, 0); + bi_charbuff_t *cbuff = get_charbuff (pr, res, __FUNCTION__, cbuff_handle); + int lines = P_INT (pr, 1); + + Draw_ScrollBuffer (cbuff->buffer, lines); +} + +static void +bi_Draw_CharBuffer (progs_t *pr, void *_res) +{ + draw_resources_t *res = _res; + int x = P_INT (pr, 0); + int y = P_INT (pr, 1); + pr_ptr_t cbuff_handle = P_POINTER (pr, 2); + bi_charbuff_t *cbuff = get_charbuff (pr, res, __FUNCTION__, cbuff_handle); + + Draw_CharBuffer (x, y, cbuff->buffer); +} + static const char * bi_draw_get_key (const void *p, void *unused) { @@ -365,13 +473,20 @@ bi_draw_clear (progs_t *pr, void *_res) { draw_resources_t *res = (draw_resources_t *) _res; qpic_res_t *qp; + bi_charbuff_t *cbuff; for (qp = res->qpics; qp; qp = qp->next) { bi_draw_free_qpic (qp); } res->qpics = 0; + for (cbuff = res->charbuffs; cbuff; cbuff = cbuff->next) { + Draw_DestroyBuffer (cbuff->buffer); + } + res->charbuffs = 0; + qpic_reset (res); + charbuff_reset (res); Hash_FlushTable (res->pic_hash); } @@ -406,6 +521,12 @@ static builtin_t builtins[] = { bi(Font_Load, 2, p(string), p(int)), bi(Font_String, 3, p(int), p(int), p(string)), + + bi(Draw_CreateBuffer, 2, p(int), p(int)), + bi(Draw_DestroyBuffer, 1, p(ptr)), + bi(Draw_ClearBuffer, 1, p(ptr)), + bi(Draw_ScrollBuffer, 2, p(ptr), p(int)), + bi(Draw_CharBuffer, 3, p(int), p(int), p(ptr)), {0} }; diff --git a/libs/video/renderer/sw/draw.c b/libs/video/renderer/sw/draw.c index 671244755..06db109af 100644 --- a/libs/video/renderer/sw/draw.c +++ b/libs/video/renderer/sw/draw.c @@ -245,7 +245,6 @@ Draw_Init (void) } } - /* Draw_Character @@ -306,6 +305,21 @@ Draw_Character (int x, int y, unsigned int chr) } } +void +sw_Draw_CharBuffer (int x, int y, draw_charbuffer_t *buffer) +{ + const byte *line = (byte *) buffer->chars; + int width = buffer->width; + int height = buffer->height; + while (height-- > 0) { + for (int i = 0; i < width; i++) { + Draw_Character (x + i * 8, y, line[i]); + } + line += width; + y += 8; + } +} + void Draw_String (int x, int y, const char *str) diff --git a/libs/video/renderer/vid_render_gl.c b/libs/video/renderer/vid_render_gl.c index ea8a10049..dac319acf 100644 --- a/libs/video/renderer/vid_render_gl.c +++ b/libs/video/renderer/vid_render_gl.c @@ -486,6 +486,7 @@ gl_capture_screen (capfunc_t callback, void *data) vid_render_funcs_t gl_vid_render_funcs = { gl_vid_render_init, + gl_Draw_CharBuffer, gl_Draw_Character, gl_Draw_String, gl_Draw_nString, diff --git a/libs/video/renderer/vid_render_glsl.c b/libs/video/renderer/vid_render_glsl.c index 2ffb0cf22..02242755c 100644 --- a/libs/video/renderer/vid_render_glsl.c +++ b/libs/video/renderer/vid_render_glsl.c @@ -430,6 +430,7 @@ glsl_capture_screen (capfunc_t callback, void *data) vid_render_funcs_t glsl_vid_render_funcs = { glsl_vid_render_init, + glsl_Draw_CharBuffer, glsl_Draw_Character, glsl_Draw_String, glsl_Draw_nString, diff --git a/libs/video/renderer/vid_render_sw.c b/libs/video/renderer/vid_render_sw.c index 2dc9b8a42..060c9ac0a 100644 --- a/libs/video/renderer/vid_render_sw.c +++ b/libs/video/renderer/vid_render_sw.c @@ -450,6 +450,7 @@ sw_capture_screen (capfunc_t callback, void *data) vid_render_funcs_t sw_vid_render_funcs = { sw_vid_render_init, + sw_Draw_CharBuffer, Draw_Character, Draw_String, Draw_nString, diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 6519f1740..acb38d4d6 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -135,6 +135,12 @@ vulkan_R_LineGraph (int x, int y, int *h_vals, int count, int height) { } +static void +vulkan_Draw_CharBuffer (int x, int y, draw_charbuffer_t *buffer) +{ + Vulkan_Draw_CharBuffer (x, y, buffer, vulkan_ctx); +} + static void vulkan_Draw_Character (int x, int y, unsigned ch) { @@ -740,6 +746,7 @@ vulkan_vid_render_shutdown (void) vid_render_funcs_t vulkan_vid_render_funcs = { vulkan_vid_render_init, + vulkan_Draw_CharBuffer, vulkan_Draw_Character, vulkan_Draw_String, vulkan_Draw_nString, diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index a3693426a..7a604860a 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -571,6 +571,22 @@ queue_character (int x, int y, byte chr, vulkan_ctx_t *ctx) &frame->quad_verts); } +void +Vulkan_Draw_CharBuffer (int x, int y, draw_charbuffer_t *buffer, + vulkan_ctx_t *ctx) +{ + const byte *line = (byte *) buffer->chars; + int width = buffer->width; + int height = buffer->height; + while (height-- > 0) { + for (int i = 0; i < width; i++) { + Vulkan_Draw_Character (x + i * 8, y, line[i], ctx); + } + line += width; + y += 8; + } +} + void Vulkan_Draw_Character (int x, int y, unsigned int chr, vulkan_ctx_t *ctx) {