From 125821fcdd7788ee4b261c9de65759aa9b62047e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 28 May 2022 18:14:26 +0900 Subject: [PATCH] [render] Add basic 2d line drawing The software renderer uses Bresenham's line slice algorithm as presented by Michael Abrash in his Graphics Programming Black Book Special Edition with the serial numbers filed off (as such, more just so *I* can read the code easily), along with the Chen-Sutherland line clipping algorithm. The other renderers were more or less trivial in comparison. --- include/QF/GL/qf_draw.h | 1 + include/QF/GLSL/qf_draw.h | 1 + include/QF/Vulkan/qf_draw.h | 2 + include/QF/draw.h | 11 ++ include/QF/plugin/vid_render.h | 1 + libs/video/renderer/gl/gl_draw.c | 16 ++ libs/video/renderer/glsl/glsl_draw.c | 55 ++++++- libs/video/renderer/r_progs.c | 29 ++++ libs/video/renderer/sw/draw.c | 159 ++++++++++++++++++++ libs/video/renderer/vid_render_gl.c | 1 + libs/video/renderer/vid_render_glsl.c | 1 + libs/video/renderer/vid_render_sw.c | 1 + libs/video/renderer/vid_render_vulkan.c | 7 + libs/video/renderer/vulkan/qfpipeline.plist | 8 + libs/video/renderer/vulkan/vulkan_bsp.c | 6 +- libs/video/renderer/vulkan/vulkan_draw.c | 96 +++++++++--- ruamoko/include/draw.h | 4 + ruamoko/lib/draw.r | 4 + 18 files changed, 375 insertions(+), 28 deletions(-) diff --git a/include/QF/GL/qf_draw.h b/include/QF/GL/qf_draw.h index 65f1a03da..d348e2534 100644 --- a/include/QF/GL/qf_draw.h +++ b/include/QF/GL/qf_draw.h @@ -41,6 +41,7 @@ void gl_Draw_Crosshair (void); void gl_Draw_CrosshairAt (int ch, int x, int y); void gl_Draw_TileClear (int x, int y, int w, int h); void gl_Draw_Fill (int x, int y, int w, int h, int c); +void gl_Draw_Line (int x0, int y0, int x1, int y1, int c); void gl_Draw_TextBox (int x, int y, int width, int lines, byte alpha); void gl_Draw_FadeScreen (void); void gl_Draw_BlendScreen (quat_t color); diff --git a/include/QF/GLSL/qf_draw.h b/include/QF/GLSL/qf_draw.h index 653e2bc5f..5c93713fc 100644 --- a/include/QF/GLSL/qf_draw.h +++ b/include/QF/GLSL/qf_draw.h @@ -41,6 +41,7 @@ void glsl_Draw_Crosshair (void); void glsl_Draw_CrosshairAt (int ch, int x, int y); void glsl_Draw_TileClear (int x, int y, int w, int h); void glsl_Draw_Fill (int x, int y, int w, int h, int c); +void glsl_Draw_Line (int x0, int y0, int x1, int y1, int c); void glsl_Draw_TextBox (int x, int y, int width, int lines, byte alpha); void glsl_Draw_FadeScreen (void); void glsl_Draw_BlendScreen (quat_t color); diff --git a/include/QF/Vulkan/qf_draw.h b/include/QF/Vulkan/qf_draw.h index 26f9d2a28..216f4b3a0 100644 --- a/include/QF/Vulkan/qf_draw.h +++ b/include/QF/Vulkan/qf_draw.h @@ -50,6 +50,8 @@ void Vulkan_Draw_TileClear (int x, int y, int w, int h, struct vulkan_ctx_s *ctx); void Vulkan_Draw_Fill (int x, int y, int w, int h, int c, struct vulkan_ctx_s *ctx); +void Vulkan_Draw_Line (int x0, int y0, int x1, int y1, int c, + struct vulkan_ctx_s *ctx); void Vulkan_Draw_TextBox (int x, int y, int width, int lines, byte alpha, struct vulkan_ctx_s *ctx); void Vulkan_Draw_FadeScreen (struct vulkan_ctx_s *ctx); diff --git a/include/QF/draw.h b/include/QF/draw.h index 8f6b78889..5f6037e15 100644 --- a/include/QF/draw.h +++ b/include/QF/draw.h @@ -144,6 +144,17 @@ void Draw_TileClear (int x, int y, int w, int h); */ void Draw_Fill (int x, int y, int w, int h, int c); +/** Clear a line with a solid color. + \param x0 horizontal position of the line start point + \param y0 horizontal position of the line start point + \param x1 horizontal position of the line end point + \param y1 horizontal position of the line end point + \param c 8 bit color index. + + The color comes from the quake palette. +*/ +void Draw_Line (int x0, int y0, int x1, int y1, int c); + /** Draw a text box on the screen \param x horizontal location of the upper left corner of the box \param y vertical location of the upper left corner of the box diff --git a/include/QF/plugin/vid_render.h b/include/QF/plugin/vid_render.h index 1f19a5278..3d6774d08 100644 --- a/include/QF/plugin/vid_render.h +++ b/include/QF/plugin/vid_render.h @@ -91,6 +91,7 @@ typedef struct vid_render_funcs_s { void (*Draw_CrosshairAt) (int ch, int x, int y); void (*Draw_TileClear) (int x, int y, int w, int h); void (*Draw_Fill) (int x, int y, int w, int h, int c); + void (*Draw_Line) (int x0, int y0, int x1, int y1, int c); void (*Draw_TextBox) (int x, int y, int width, int lines, byte alpha); void (*Draw_FadeScreen) (void); void (*Draw_BlendScreen) (quat_t color); diff --git a/libs/video/renderer/gl/gl_draw.c b/libs/video/renderer/gl/gl_draw.c index 820c83d8e..c4abb9753 100644 --- a/libs/video/renderer/gl/gl_draw.c +++ b/libs/video/renderer/gl/gl_draw.c @@ -910,6 +910,22 @@ gl_Draw_Fill (int x, int y, int w, int h, int c) qfglEnable (GL_TEXTURE_2D); } +void +gl_Draw_Line (int x0, int y0, int x1, int y1, int c) +{ + qfglDisable (GL_TEXTURE_2D); + qfglColor3ubv (vid.palette + c * 3); + + qfglBegin (GL_LINES); + + qfglVertex2f (x0, y0); + qfglVertex2f (x1, y1); + + qfglEnd (); + qfglColor3ubv (color_white); + qfglEnable (GL_TEXTURE_2D); +} + void gl_Draw_FadeScreen (void) { diff --git a/libs/video/renderer/glsl/glsl_draw.c b/libs/video/renderer/glsl/glsl_draw.c index d24d57f97..a150fe20f 100644 --- a/libs/video/renderer/glsl/glsl_draw.c +++ b/libs/video/renderer/glsl/glsl_draw.c @@ -104,6 +104,7 @@ static struct { static scrap_t *draw_scrap; // hold all 2d images static byte white_block[8 * 8]; static dstring_t *draw_queue; +static dstring_t *line_queue; static qpic_t *conchars; static int conback_texture; static qpic_t *crosshair_pic; @@ -388,6 +389,7 @@ glsl_Draw_Init (void) //crosshaircolor->callback (crosshaircolor); draw_queue = dstring_new (); + line_queue = dstring_new (); vert_shader = GLSL_BuildShader (twod_vert_effects); frag_shader = GLSL_BuildShader (twod_frag_effects); @@ -461,14 +463,26 @@ static void flush_2d (void) { GLSL_ScrapFlush (draw_scrap); - qfeglBindTexture (GL_TEXTURE_2D, GLSL_ScrapTexture (draw_scrap)); - qfeglVertexAttribPointer (quake_2d.vertex.location, 4, GL_FLOAT, - 0, 32, draw_queue->str); - qfeglVertexAttribPointer (quake_2d.color.location, 4, GL_FLOAT, - 0, 32, draw_queue->str + 16); - qfeglDrawArrays (GL_TRIANGLES, 0, draw_queue->size / 32); + qfeglBindTexture (GL_TEXTURE_2D, GLSL_ScrapTexture (draw_scrap)); + if (draw_queue->size) { + qfeglVertexAttribPointer (quake_2d.vertex.location, 4, GL_FLOAT, + 0, 32, draw_queue->str); + qfeglVertexAttribPointer (quake_2d.color.location, 4, GL_FLOAT, + 0, 32, draw_queue->str + 16); + + qfeglDrawArrays (GL_TRIANGLES, 0, draw_queue->size / 32); + } + if (line_queue->size) { + qfeglVertexAttribPointer (quake_2d.vertex.location, 4, GL_FLOAT, + 0, 32, line_queue->str); + qfeglVertexAttribPointer (quake_2d.color.location, 4, GL_FLOAT, + 0, 32, line_queue->str + 16); + + qfeglDrawArrays (GL_LINES, 0, line_queue->size / 32); + } draw_queue->size = 0; + line_queue->size = 0; } void @@ -693,6 +707,32 @@ glsl_Draw_Fill (int x, int y, int w, int h, int c) draw_pic (x, y, w, h, white_pic, 0, 0, 8, 8, color); } +void +glsl_Draw_Line (int x0, int y0, int x1, int y1, int c) +{ + glpic_t *gl = (glpic_t *) white_pic->data; + subpic_t *sp = gl->subpic; + float sl = sp->rect->x * sp->size; + float sh = sp->rect->x * sp->size; + float tl = sp->rect->y * sp->size; + float th = sp->rect->y * sp->size; + + quat_t color = { VectorExpand (vid.palette + c * 3), 255 }; + QuatScale (color, 1/255.0, color); + drawvert_t verts[2] = { + { .xyst = { x0, y0, sl, tl }, .color = { QuatExpand (color) }, }, + { .xyst = { x1, y1, sh, th }, .color = { QuatExpand (color) }, }, + }; + + void *v; + int size = sizeof (verts); + + line_queue->size += size; + dstring_adjust (line_queue); + v = line_queue->str + line_queue->size - size; + memcpy (v, verts, size); +} + static inline void draw_blendscreen (quat_t color) { @@ -784,12 +824,13 @@ void GLSL_DrawReset (void) { draw_queue->size = 0; + line_queue->size = 0; } void GLSL_FlushText (void) { - if (draw_queue->size) + if (draw_queue->size || line_queue->size) flush_2d (); } diff --git a/libs/video/renderer/r_progs.c b/libs/video/renderer/r_progs.c index 319634505..db9760e37 100644 --- a/libs/video/renderer/r_progs.c +++ b/libs/video/renderer/r_progs.c @@ -42,6 +42,8 @@ #include "QF/render.h" #include "QF/sys.h" +#include "QF/ui/view.h" + #include "r_internal.h" typedef struct { @@ -296,6 +298,18 @@ bi_Draw_Fill (progs_t *pr, void *_res) r_funcs->Draw_Fill (x, y, w, h, color); } +static void +bi_Draw_Line (progs_t *pr, void *_res) +{ + int x0 = P_INT (pr, 0); + int y0 = P_INT (pr, 1); + int x1 = P_INT (pr, 2); + int y1 = P_INT (pr, 3); + int color = P_INT (pr, 4); + + r_funcs->Draw_Line (x0, y0, x1, y1, color); +} + static void bi_Draw_Crosshair (progs_t *pr, void *_res) { @@ -306,6 +320,18 @@ bi_Draw_Crosshair (progs_t *pr, void *_res) r_funcs->Draw_CrosshairAt (ch, x, y); } +static void +bi_Draw_Width (progs_t *pr, void *_res) +{ + R_INT (pr) = r_data->vid->conview->xlen; +} + +static void +bi_Draw_Height (progs_t *pr, void *_res) +{ + R_INT (pr) = r_data->vid->conview->ylen; +} + static const char * bi_draw_get_key (const void *p, void *unused) { @@ -338,6 +364,8 @@ bi_draw_destroy (progs_t *pr, void *_res) #define p(type) PR_PARAM(type) #define P(a, s) { .size = (s), .alignment = BITOP_LOG2 (a), } static builtin_t builtins[] = { + bi(Draw_Width, 0), + bi(Draw_Height, 0), bi(Draw_FreePic, 1, p(ptr)), bi(Draw_MakePic, 3, p(int), p(int), p(string)), bi(Draw_CachePic, 2, p(string), p(int)), @@ -351,6 +379,7 @@ static builtin_t builtins[] = { bi(Draw_nString, 4, p(int), p(int), p(string), p(int)), bi(Draw_AltString, 3, p(int), p(int), p(string)), bi(Draw_Fill, 5, p(int), p(int), p(int), p(int), p(int)), + bi(Draw_Line, 5, p(int), p(int), p(int), p(int), p(int)), bi(Draw_Crosshair, 5, p(int), p(int), p(int), p(int)), {0} }; diff --git a/libs/video/renderer/sw/draw.c b/libs/video/renderer/sw/draw.c index 27568d82c..c861da9b4 100644 --- a/libs/video/renderer/sw/draw.c +++ b/libs/video/renderer/sw/draw.c @@ -766,6 +766,165 @@ Draw_Fill (int x, int y, int w, int h, int c) dest[u] = c; } +static inline byte * +draw_horizontal (byte *dest, int xs, int len, int c) +{ + while (len-- > 0) { + *dest = c; + dest += xs; + } + return dest; +} + +static inline byte * +draw_vertical (byte *dest, int len, int c) +{ + while (len-- > 0) { + *dest = c; + dest += d_rowbytes; + } + return dest; +} + +static void +draw_line (int x0, int y0, int x1, int y1, int c) +{ + // Bresenham's line slice algorith (ala Michael Abrash) + int dx, dy, sx; + // always go top to bottom + if (y1 < y0) { + int t; + t = y1; y1 = y0; y0 = t; + t = x1; x1 = x0; x0 = t; + } + dy = y1 - y0; + + if ((dx = x1 - x0) < 0) { + sx = -1; + dx = -dx; + } else { + sx = 1; + } + + byte *dest = d_viewbuffer + y0 * d_rowbytes + x0; + + if (!dx) { + draw_vertical (dest, dy, c); + return; + } + if (!dy) { + draw_horizontal (dest, sx, dx, c); + return; + } + if (dx == dy) { + while (dy-- > 0) { + *dest = c; + dest += d_rowbytes + sx; + } + return; + } + if (dx > dy) { + int step = dx / dy; + int adj_up = (dx % dy) * 2; + int adj_down = dy * 2; + int error = (dx % dy) - adj_down; + int initial = step / 2 + 1; + int final = initial; + + if (!adj_up && !(step & 1)) { + initial--; + } + if (step & 1) { + error += dy; + } + dest = draw_horizontal (dest, sx, initial, c); + dest += d_rowbytes; + while (dy-- > 1) { + int run = step; + if ((error += adj_up) > 0) { + run++; + error -= adj_down; + } + dest = draw_horizontal (dest, sx, run, c); + dest += d_rowbytes; + } + dest = draw_horizontal (dest, sx, final, c); + } else { + int step = dy / dx; + int adj_up = (dy % dx) * 2; + int adj_down = dx * 2; + int error = (dy % dx) - adj_down; + int initial = step / 2 + 1; + int final = initial; + + if (!adj_up && !(step & 1)) { + initial--; + } + if (step & 1) { + error += dx; + } + dest = draw_vertical (dest, initial, c); + dest += sx; + while (dx-- > 1) { + int run = step; + if ((error += adj_up) > 0) { + run++; + error -= adj_down; + } + dest = draw_vertical (dest, run, c); + dest += sx; + } + dest = draw_vertical (dest, final, c); + } +} + +static inline byte +test_point (int x, int y) +{ + byte c = 0; + + if (x < 0) { + c |= 1; + } else if (x >= vid.conview->xlen) { + c |= 2; + } + if (y < 0) { + c |= 4; + } else if (y >= vid.conview->ylen) { + c |= 8; + } + return c; +} + +void +Draw_Line (int x0, int y0, int x1, int y1, int c) +{ + byte c0 = test_point (x0, y0); + byte c1 = test_point (x1, y1); + int xmax = vid.conview->xlen - 1; + int ymax = vid.conview->ylen - 1; + + while (c0 | c1) { + // Cohen-Sutherland line clipping + if (c0 & c1) { + return; + } + int dx = x1 - x0; + int dy = y1 - y0; + if (c0 & 1) { y0 = (( 0 - x0) * dy + dx * y0) / dx; x0 = 0; } + if (c0 & 2) { y0 = ((xmax - x0) * dy + dx * y0) / dx; x0 = xmax; } + if (c1 & 1) { y1 = (( 0 - x1) * dy + dx * y1) / dx; x1 = 0; } + if (c1 & 2) { y1 = ((xmax - x1) * dy + dx * y1) / dx; x1 = xmax; } + + if (c0 & 4) { x0 = (( 0 - y0) * dx + dy * x0) / dy; y0 = 0; } + if (c0 & 8) { x0 = ((ymax - y0) * dx + dy * x0) / dy; y0 = ymax; } + if (c1 & 4) { x1 = (( 0 - y1) * dx + dy * x1) / dy; y1 = 0; } + if (c1 & 8) { x1 = ((ymax - y1) * dx + dy * x1) / dy; y1 = ymax; } + c0 = test_point (x0, y0); + c1 = test_point (x1, y1); + } + draw_line (x0, y0, x1, y1, c); +} void Draw_FadeScreen (void) diff --git a/libs/video/renderer/vid_render_gl.c b/libs/video/renderer/vid_render_gl.c index 7944e3ada..3fe390bf9 100644 --- a/libs/video/renderer/vid_render_gl.c +++ b/libs/video/renderer/vid_render_gl.c @@ -495,6 +495,7 @@ vid_render_funcs_t gl_vid_render_funcs = { gl_Draw_CrosshairAt, gl_Draw_TileClear, gl_Draw_Fill, + gl_Draw_Line, gl_Draw_TextBox, gl_Draw_FadeScreen, gl_Draw_BlendScreen, diff --git a/libs/video/renderer/vid_render_glsl.c b/libs/video/renderer/vid_render_glsl.c index 9be89b23a..958cfbfdc 100644 --- a/libs/video/renderer/vid_render_glsl.c +++ b/libs/video/renderer/vid_render_glsl.c @@ -439,6 +439,7 @@ vid_render_funcs_t glsl_vid_render_funcs = { glsl_Draw_CrosshairAt, glsl_Draw_TileClear, glsl_Draw_Fill, + glsl_Draw_Line, glsl_Draw_TextBox, glsl_Draw_FadeScreen, glsl_Draw_BlendScreen, diff --git a/libs/video/renderer/vid_render_sw.c b/libs/video/renderer/vid_render_sw.c index a4a532557..e1398bc72 100644 --- a/libs/video/renderer/vid_render_sw.c +++ b/libs/video/renderer/vid_render_sw.c @@ -459,6 +459,7 @@ vid_render_funcs_t sw_vid_render_funcs = { Draw_CrosshairAt, Draw_TileClear, Draw_Fill, + Draw_Line, Draw_TextBox, Draw_FadeScreen, Draw_BlendScreen, diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 6e66fdc54..cce63d511 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -189,6 +189,12 @@ vulkan_Draw_Fill (int x, int y, int w, int h, int c) Vulkan_Draw_Fill (x, y, w, h, c, vulkan_ctx); } +static void +vulkan_Draw_Line (int x0, int y0, int x1, int y1, int c) +{ + Vulkan_Draw_Line (x0, y0, x1, y1, c, vulkan_ctx); +} + static void vulkan_Draw_TextBox (int x, int y, int width, int lines, byte alpha) { @@ -731,6 +737,7 @@ vid_render_funcs_t vulkan_vid_render_funcs = { vulkan_Draw_CrosshairAt, vulkan_Draw_TileClear, vulkan_Draw_Fill, + vulkan_Draw_Line, vulkan_Draw_TextBox, vulkan_Draw_FadeScreen, vulkan_Draw_BlendScreen, diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 4e4f59e9e..accc4e366 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -482,6 +482,10 @@ topology = triangle_list; primitiveRestartEnable = false; }; + lines = { + topology = line_list; + primitiveRestartEnable = false; + }; twod = { topology = triangle_strip; primitiveRestartEnable = true; @@ -1045,6 +1049,10 @@ }; layout = twod_layout; }; + lines = { + @inherit = $properties.pipelines.twod; + inputAssembly = $properties.inputAssembly.lines; + }; lighting = { @inherit = $properties.pipelines.comp_base; subpass = 3; diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index a5beec50a..43dbd4a67 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -1072,8 +1072,10 @@ Vulkan_DrawWorld (qfv_renderframe_t *rFrame) int world_id = worldent.renderer.model->render_id; bctx->main_pass.ent_frame = 0; // world is always frame 0 bctx->main_pass.inst_id = world_id; - DARRAY_APPEND (&bctx->main_pass.instances[world_id].entities, - worldent.renderer.render_id); + if (bctx->main_pass.instances) { + DARRAY_APPEND (&bctx->main_pass.instances[world_id].entities, + worldent.renderer.render_id); + } R_VisitWorldNodes (brush, ctx); if (!bctx->vertex_buffer) { return; diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 46604ae24..c042d814f 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -82,8 +82,11 @@ typedef struct cachepic_s { typedef struct drawframe_s { size_t vert_offset; - drawvert_t *verts; + size_t line_offset; + drawvert_t *quad_verts; + drawvert_t *line_verts; uint32_t num_quads; + uint32_t num_lines; VkCommandBuffer cmd; VkDescriptorSet descriptors; } drawframe_t; @@ -109,7 +112,8 @@ typedef struct drawctx_s { VkDeviceMemory vert_memory; VkBuffer ind_buffer; VkDeviceMemory ind_memory; - VkPipeline pipeline; + VkPipeline quad_pipeline; + VkPipeline line_pipeline; VkPipelineLayout layout; drawframeset_t frames; } drawctx_t; @@ -119,6 +123,11 @@ typedef struct drawctx_s { #define VERTS_PER_QUAD (4) #define INDS_PER_QUAD (5) // one per vert plus primitive reset +#define MAX_LINES (32768) +#define VERTS_PER_LINE (2) + +#define VERTS_PER_FRAME (MAX_LINES*VERTS_PER_LINE + MAX_QUADS*VERTS_PER_QUAD) + static void create_quad_buffers (vulkan_ctx_t *ctx) { @@ -133,7 +142,7 @@ create_quad_buffers (vulkan_ctx_t *ctx) VkBuffer vbuf, ibuf; VkDeviceMemory vmem, imem; - vert_size = frames * MAX_QUADS * VERTS_PER_QUAD * sizeof (drawvert_t); + vert_size = frames * VERTS_PER_FRAME * sizeof (drawvert_t); ind_size = MAX_QUADS * INDS_PER_QUAD * sizeof (uint32_t); vbuf = QFV_CreateBuffer (device, vert_size, @@ -161,10 +170,14 @@ create_quad_buffers (vulkan_ctx_t *ctx) for (size_t f = 0; f < frames; f++) { drawframe_t *frame = &dctx->frames.a[f]; - size_t ind = f * MAX_QUADS * VERTS_PER_QUAD; + size_t ind = f * VERTS_PER_FRAME; + size_t lind = ind + MAX_QUADS * VERTS_PER_QUAD; frame->vert_offset = ind * sizeof (drawvert_t); - frame->verts = vert_data + ind; + frame->line_offset = lind; + frame->quad_verts = vert_data + ind; + frame->line_verts = frame->quad_verts + MAX_QUADS * VERTS_PER_QUAD; frame->num_quads = 0; + frame->num_lines = 0; } // The indices will never change so pre-generate and stash them @@ -347,7 +360,8 @@ Vulkan_Draw_Shutdown (vulkan_ctx_t *ctx) destroy_quad_buffers (ctx); - dfunc->vkDestroyPipeline (device->dev, dctx->pipeline, 0); + dfunc->vkDestroyPipeline (device->dev, dctx->quad_pipeline, 0); + dfunc->vkDestroyPipeline (device->dev, dctx->line_pipeline, 0); Hash_DelTable (dctx->pic_cache); delete_memsuper (dctx->pic_memsuper); delete_memsuper (dctx->string_memsuper); @@ -409,7 +423,8 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) flush_draw_scrap (ctx); - dctx->pipeline = Vulkan_CreateGraphicsPipeline (ctx, "twod"); + dctx->quad_pipeline = Vulkan_CreateGraphicsPipeline (ctx, "twod"); + dctx->line_pipeline = Vulkan_CreateGraphicsPipeline (ctx, "lines"); dctx->layout = Vulkan_CreatePipelineLayout (ctx, "twod_layout"); @@ -457,7 +472,7 @@ draw_pic (float x, float y, int w, int h, qpic_t *pic, return; } - drawvert_t *verts = frame->verts + frame->num_quads * VERTS_PER_QUAD; + drawvert_t *verts = frame->quad_verts + frame->num_quads * VERTS_PER_QUAD; frame->num_quads++; subpic_t *subpic = *(subpic_t **) pic->data; @@ -767,6 +782,32 @@ Vulkan_Draw_Fill (int x, int y, int w, int h, int c, vulkan_ctx_t *ctx) draw_pic (x, y, w, h, dctx->white_pic, 0, 0, 1, 1, color, frame); } +void +Vulkan_Draw_Line (int x0, int y0, int x1, int y1, int c, vulkan_ctx_t *ctx) +{ + drawctx_t *dctx = ctx->draw_context; + drawframe_t *frame = &dctx->frames.a[ctx->curFrame]; + + if (frame->num_quads >= MAX_QUADS) { + return; + } + + quat_t color = { VectorExpand (vid.palette + c * 3), 255 }; + QuatScale (color, 1/255.0, color); + drawvert_t *verts = frame->line_verts + frame->num_lines * VERTS_PER_LINE; + + verts[0] = (drawvert_t) { + .xy = { x0, y0 }, + .color = { QuatExpand (color) }, + }; + verts[1] = (drawvert_t) { + .xy = { x1, y1 }, + .color = { QuatExpand (color) }, + }; + + frame->num_lines++; +} + static inline void draw_blendscreen (quat_t color, vulkan_ctx_t *ctx) { @@ -816,16 +857,23 @@ Vulkan_FlushText (qfv_renderframe_t *rFrame) drawctx_t *dctx = ctx->draw_context; drawframe_t *dframe = &dctx->frames.a[ctx->curFrame]; + if (!dframe->num_quads && !dframe->num_lines) { + return; + } + VkCommandBuffer cmd = dframe->cmd; //FIXME which pass? DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passTranslucent], cmd); - VkMappedMemoryRange range = { - VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, - dctx->vert_memory, dframe->vert_offset, - dframe->num_quads * VERTS_PER_QUAD * sizeof (drawvert_t), + VkMappedMemoryRange ranges[] = { + { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, + dctx->vert_memory, dframe->vert_offset, + dframe->num_quads * VERTS_PER_QUAD * sizeof (drawvert_t) }, + { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, + dctx->vert_memory, dframe->line_offset, + dframe->num_lines * VERTS_PER_LINE * sizeof (drawvert_t) }, }; - dfunc->vkFlushMappedMemoryRanges (device->dev, 1, &range); + dfunc->vkFlushMappedMemoryRanges (device->dev, 2, ranges); dfunc->vkResetCommandBuffer (cmd, 0); VkCommandBufferInheritanceInfo inherit = { @@ -843,10 +891,6 @@ Vulkan_FlushText (qfv_renderframe_t *rFrame) QFV_duCmdBeginLabel (device, cmd, "twod", { 0.6, 0.2, 0, 1}); - dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - dctx->pipeline); - dfunc->vkCmdSetViewport (cmd, 0, 1, &rFrame->renderpass->viewport); - dfunc->vkCmdSetScissor (cmd, 0, 1, &rFrame->renderpass->scissor); VkDeviceSize offsets[] = {dframe->vert_offset}; dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, &dctx->vert_buffer, offsets); dfunc->vkCmdBindIndexBuffer (cmd, dctx->ind_buffer, 0, @@ -858,13 +902,27 @@ Vulkan_FlushText (qfv_renderframe_t *rFrame) VkPipelineLayout layout = dctx->layout; dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, 2, set, 0, 0); - dfunc->vkCmdDrawIndexed (cmd, dframe->num_quads * INDS_PER_QUAD, - 1, 0, 0, 0); + if (dframe->num_quads) { + dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + dctx->quad_pipeline); + dfunc->vkCmdSetViewport (cmd, 0, 1, &rFrame->renderpass->viewport); + dfunc->vkCmdSetScissor (cmd, 0, 1, &rFrame->renderpass->scissor); + dfunc->vkCmdDrawIndexed (cmd, dframe->num_quads * INDS_PER_QUAD, + 1, 0, 0, 0); + } + + if (dframe->num_lines) { + dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + dctx->line_pipeline); + dfunc->vkCmdDraw (cmd, dframe->num_lines * VERTS_PER_LINE, + 1, MAX_QUADS * VERTS_PER_QUAD, 0); + } QFV_duCmdEndLabel (device, cmd); dfunc->vkEndCommandBuffer (cmd); dframe->num_quads = 0; + dframe->num_lines = 0; } void diff --git a/ruamoko/include/draw.h b/ruamoko/include/draw.h index ae868ff36..a5369375e 100644 --- a/ruamoko/include/draw.h +++ b/ruamoko/include/draw.h @@ -10,6 +10,9 @@ struct _qpic_t { }; typedef struct _qpic_t *qpic_t; +@extern int Draw_Width (void); +@extern int Draw_Height (void); + @extern void Draw_FreePic (qpic_t pic); @extern qpic_t Draw_MakePic (int width, int heiight, string data); @extern qpic_t Draw_CachePic (string name, int alpha); @@ -24,6 +27,7 @@ typedef struct _qpic_t *qpic_t; @extern void Draw_nString (int x, int y, string text, int n); @extern void Draw_AltString (int x, int y, string text); @extern void Draw_Fill (int x, int y, int w, int h, int c); +@extern void Draw_Line (int x0, int y0, int x1, int y1, int c); @extern void Draw_Crosshair (int ch, int x, int y); @extern void text_box (int x, int y, int width, int lines); diff --git a/ruamoko/lib/draw.r b/ruamoko/lib/draw.r index 5aef3ab75..65311595f 100644 --- a/ruamoko/lib/draw.r +++ b/ruamoko/lib/draw.r @@ -1,5 +1,8 @@ #include +int Draw_Width (void) = #0; +int Draw_Height (void) = #0; + void Draw_FreePic (qpic_t pic) = #0; qpic_t Draw_MakePic (int width, int heiight, string data) = #0; qpic_t (string name, int alpha) Draw_CachePic = #0; @@ -14,6 +17,7 @@ void (int x, int y, string text) Draw_String = #0; void (int x, int y, string text, int n) Draw_nString = #0; void (int x, int y, string text) Draw_AltString = #0; void (int x, int y, int w, int h, int c) Draw_Fill = #0; +void (int x0, int y0, int x1, int y1, int c) Draw_Line = #0; void (int ch, int x, int y) Draw_Crosshair = #0; void (int x, int y, int width, int lines) text_box =