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 =