mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-26 06:10:56 +00:00
[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.
This commit is contained in:
parent
ea781c9dcc
commit
125821fcdd
18 changed files with 375 additions and 28 deletions
|
@ -41,6 +41,7 @@ void gl_Draw_Crosshair (void);
|
||||||
void gl_Draw_CrosshairAt (int ch, int x, int y);
|
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_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_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_TextBox (int x, int y, int width, int lines, byte alpha);
|
||||||
void gl_Draw_FadeScreen (void);
|
void gl_Draw_FadeScreen (void);
|
||||||
void gl_Draw_BlendScreen (quat_t color);
|
void gl_Draw_BlendScreen (quat_t color);
|
||||||
|
|
|
@ -41,6 +41,7 @@ void glsl_Draw_Crosshair (void);
|
||||||
void glsl_Draw_CrosshairAt (int ch, int x, int y);
|
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_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_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_TextBox (int x, int y, int width, int lines, byte alpha);
|
||||||
void glsl_Draw_FadeScreen (void);
|
void glsl_Draw_FadeScreen (void);
|
||||||
void glsl_Draw_BlendScreen (quat_t color);
|
void glsl_Draw_BlendScreen (quat_t color);
|
||||||
|
|
|
@ -50,6 +50,8 @@ void Vulkan_Draw_TileClear (int x, int y, int w, int h,
|
||||||
struct vulkan_ctx_s *ctx);
|
struct vulkan_ctx_s *ctx);
|
||||||
void Vulkan_Draw_Fill (int x, int y, int w, int h, int c,
|
void Vulkan_Draw_Fill (int x, int y, int w, int h, int c,
|
||||||
struct vulkan_ctx_s *ctx);
|
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,
|
void Vulkan_Draw_TextBox (int x, int y, int width, int lines, byte alpha,
|
||||||
struct vulkan_ctx_s *ctx);
|
struct vulkan_ctx_s *ctx);
|
||||||
void Vulkan_Draw_FadeScreen (struct vulkan_ctx_s *ctx);
|
void Vulkan_Draw_FadeScreen (struct vulkan_ctx_s *ctx);
|
||||||
|
|
|
@ -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);
|
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
|
/** Draw a text box on the screen
|
||||||
\param x horizontal location of the upper left corner of the box
|
\param x horizontal location of the upper left corner of the box
|
||||||
\param y vertical location of the upper left corner of the box
|
\param y vertical location of the upper left corner of the box
|
||||||
|
|
|
@ -91,6 +91,7 @@ typedef struct vid_render_funcs_s {
|
||||||
void (*Draw_CrosshairAt) (int ch, int x, int y);
|
void (*Draw_CrosshairAt) (int ch, int x, int y);
|
||||||
void (*Draw_TileClear) (int x, int y, int w, int h);
|
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_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_TextBox) (int x, int y, int width, int lines, byte alpha);
|
||||||
void (*Draw_FadeScreen) (void);
|
void (*Draw_FadeScreen) (void);
|
||||||
void (*Draw_BlendScreen) (quat_t color);
|
void (*Draw_BlendScreen) (quat_t color);
|
||||||
|
|
|
@ -910,6 +910,22 @@ gl_Draw_Fill (int x, int y, int w, int h, int c)
|
||||||
qfglEnable (GL_TEXTURE_2D);
|
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
|
void
|
||||||
gl_Draw_FadeScreen (void)
|
gl_Draw_FadeScreen (void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -104,6 +104,7 @@ static struct {
|
||||||
static scrap_t *draw_scrap; // hold all 2d images
|
static scrap_t *draw_scrap; // hold all 2d images
|
||||||
static byte white_block[8 * 8];
|
static byte white_block[8 * 8];
|
||||||
static dstring_t *draw_queue;
|
static dstring_t *draw_queue;
|
||||||
|
static dstring_t *line_queue;
|
||||||
static qpic_t *conchars;
|
static qpic_t *conchars;
|
||||||
static int conback_texture;
|
static int conback_texture;
|
||||||
static qpic_t *crosshair_pic;
|
static qpic_t *crosshair_pic;
|
||||||
|
@ -388,6 +389,7 @@ glsl_Draw_Init (void)
|
||||||
//crosshaircolor->callback (crosshaircolor);
|
//crosshaircolor->callback (crosshaircolor);
|
||||||
|
|
||||||
draw_queue = dstring_new ();
|
draw_queue = dstring_new ();
|
||||||
|
line_queue = dstring_new ();
|
||||||
|
|
||||||
vert_shader = GLSL_BuildShader (twod_vert_effects);
|
vert_shader = GLSL_BuildShader (twod_vert_effects);
|
||||||
frag_shader = GLSL_BuildShader (twod_frag_effects);
|
frag_shader = GLSL_BuildShader (twod_frag_effects);
|
||||||
|
@ -461,14 +463,26 @@ static void
|
||||||
flush_2d (void)
|
flush_2d (void)
|
||||||
{
|
{
|
||||||
GLSL_ScrapFlush (draw_scrap);
|
GLSL_ScrapFlush (draw_scrap);
|
||||||
|
|
||||||
qfeglBindTexture (GL_TEXTURE_2D, GLSL_ScrapTexture (draw_scrap));
|
qfeglBindTexture (GL_TEXTURE_2D, GLSL_ScrapTexture (draw_scrap));
|
||||||
|
if (draw_queue->size) {
|
||||||
qfeglVertexAttribPointer (quake_2d.vertex.location, 4, GL_FLOAT,
|
qfeglVertexAttribPointer (quake_2d.vertex.location, 4, GL_FLOAT,
|
||||||
0, 32, draw_queue->str);
|
0, 32, draw_queue->str);
|
||||||
qfeglVertexAttribPointer (quake_2d.color.location, 4, GL_FLOAT,
|
qfeglVertexAttribPointer (quake_2d.color.location, 4, GL_FLOAT,
|
||||||
0, 32, draw_queue->str + 16);
|
0, 32, draw_queue->str + 16);
|
||||||
|
|
||||||
qfeglDrawArrays (GL_TRIANGLES, 0, draw_queue->size / 32);
|
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;
|
draw_queue->size = 0;
|
||||||
|
line_queue->size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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);
|
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
|
static inline void
|
||||||
draw_blendscreen (quat_t color)
|
draw_blendscreen (quat_t color)
|
||||||
{
|
{
|
||||||
|
@ -784,12 +824,13 @@ void
|
||||||
GLSL_DrawReset (void)
|
GLSL_DrawReset (void)
|
||||||
{
|
{
|
||||||
draw_queue->size = 0;
|
draw_queue->size = 0;
|
||||||
|
line_queue->size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GLSL_FlushText (void)
|
GLSL_FlushText (void)
|
||||||
{
|
{
|
||||||
if (draw_queue->size)
|
if (draw_queue->size || line_queue->size)
|
||||||
flush_2d ();
|
flush_2d ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
#include "QF/render.h"
|
#include "QF/render.h"
|
||||||
#include "QF/sys.h"
|
#include "QF/sys.h"
|
||||||
|
|
||||||
|
#include "QF/ui/view.h"
|
||||||
|
|
||||||
#include "r_internal.h"
|
#include "r_internal.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -296,6 +298,18 @@ bi_Draw_Fill (progs_t *pr, void *_res)
|
||||||
r_funcs->Draw_Fill (x, y, w, h, color);
|
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
|
static void
|
||||||
bi_Draw_Crosshair (progs_t *pr, void *_res)
|
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);
|
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 *
|
static const char *
|
||||||
bi_draw_get_key (const void *p, void *unused)
|
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(type) PR_PARAM(type)
|
||||||
#define P(a, s) { .size = (s), .alignment = BITOP_LOG2 (a), }
|
#define P(a, s) { .size = (s), .alignment = BITOP_LOG2 (a), }
|
||||||
static builtin_t builtins[] = {
|
static builtin_t builtins[] = {
|
||||||
|
bi(Draw_Width, 0),
|
||||||
|
bi(Draw_Height, 0),
|
||||||
bi(Draw_FreePic, 1, p(ptr)),
|
bi(Draw_FreePic, 1, p(ptr)),
|
||||||
bi(Draw_MakePic, 3, p(int), p(int), p(string)),
|
bi(Draw_MakePic, 3, p(int), p(int), p(string)),
|
||||||
bi(Draw_CachePic, 2, p(string), p(int)),
|
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_nString, 4, p(int), p(int), p(string), p(int)),
|
||||||
bi(Draw_AltString, 3, p(int), p(int), p(string)),
|
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_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)),
|
bi(Draw_Crosshair, 5, p(int), p(int), p(int), p(int)),
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
|
@ -766,6 +766,165 @@ Draw_Fill (int x, int y, int w, int h, int c)
|
||||||
dest[u] = 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
|
void
|
||||||
Draw_FadeScreen (void)
|
Draw_FadeScreen (void)
|
||||||
|
|
|
@ -495,6 +495,7 @@ vid_render_funcs_t gl_vid_render_funcs = {
|
||||||
gl_Draw_CrosshairAt,
|
gl_Draw_CrosshairAt,
|
||||||
gl_Draw_TileClear,
|
gl_Draw_TileClear,
|
||||||
gl_Draw_Fill,
|
gl_Draw_Fill,
|
||||||
|
gl_Draw_Line,
|
||||||
gl_Draw_TextBox,
|
gl_Draw_TextBox,
|
||||||
gl_Draw_FadeScreen,
|
gl_Draw_FadeScreen,
|
||||||
gl_Draw_BlendScreen,
|
gl_Draw_BlendScreen,
|
||||||
|
|
|
@ -439,6 +439,7 @@ vid_render_funcs_t glsl_vid_render_funcs = {
|
||||||
glsl_Draw_CrosshairAt,
|
glsl_Draw_CrosshairAt,
|
||||||
glsl_Draw_TileClear,
|
glsl_Draw_TileClear,
|
||||||
glsl_Draw_Fill,
|
glsl_Draw_Fill,
|
||||||
|
glsl_Draw_Line,
|
||||||
glsl_Draw_TextBox,
|
glsl_Draw_TextBox,
|
||||||
glsl_Draw_FadeScreen,
|
glsl_Draw_FadeScreen,
|
||||||
glsl_Draw_BlendScreen,
|
glsl_Draw_BlendScreen,
|
||||||
|
|
|
@ -459,6 +459,7 @@ vid_render_funcs_t sw_vid_render_funcs = {
|
||||||
Draw_CrosshairAt,
|
Draw_CrosshairAt,
|
||||||
Draw_TileClear,
|
Draw_TileClear,
|
||||||
Draw_Fill,
|
Draw_Fill,
|
||||||
|
Draw_Line,
|
||||||
Draw_TextBox,
|
Draw_TextBox,
|
||||||
Draw_FadeScreen,
|
Draw_FadeScreen,
|
||||||
Draw_BlendScreen,
|
Draw_BlendScreen,
|
||||||
|
|
|
@ -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);
|
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
|
static void
|
||||||
vulkan_Draw_TextBox (int x, int y, int width, int lines, byte alpha)
|
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_CrosshairAt,
|
||||||
vulkan_Draw_TileClear,
|
vulkan_Draw_TileClear,
|
||||||
vulkan_Draw_Fill,
|
vulkan_Draw_Fill,
|
||||||
|
vulkan_Draw_Line,
|
||||||
vulkan_Draw_TextBox,
|
vulkan_Draw_TextBox,
|
||||||
vulkan_Draw_FadeScreen,
|
vulkan_Draw_FadeScreen,
|
||||||
vulkan_Draw_BlendScreen,
|
vulkan_Draw_BlendScreen,
|
||||||
|
|
|
@ -482,6 +482,10 @@
|
||||||
topology = triangle_list;
|
topology = triangle_list;
|
||||||
primitiveRestartEnable = false;
|
primitiveRestartEnable = false;
|
||||||
};
|
};
|
||||||
|
lines = {
|
||||||
|
topology = line_list;
|
||||||
|
primitiveRestartEnable = false;
|
||||||
|
};
|
||||||
twod = {
|
twod = {
|
||||||
topology = triangle_strip;
|
topology = triangle_strip;
|
||||||
primitiveRestartEnable = true;
|
primitiveRestartEnable = true;
|
||||||
|
@ -1045,6 +1049,10 @@
|
||||||
};
|
};
|
||||||
layout = twod_layout;
|
layout = twod_layout;
|
||||||
};
|
};
|
||||||
|
lines = {
|
||||||
|
@inherit = $properties.pipelines.twod;
|
||||||
|
inputAssembly = $properties.inputAssembly.lines;
|
||||||
|
};
|
||||||
lighting = {
|
lighting = {
|
||||||
@inherit = $properties.pipelines.comp_base;
|
@inherit = $properties.pipelines.comp_base;
|
||||||
subpass = 3;
|
subpass = 3;
|
||||||
|
|
|
@ -1072,8 +1072,10 @@ Vulkan_DrawWorld (qfv_renderframe_t *rFrame)
|
||||||
int world_id = worldent.renderer.model->render_id;
|
int world_id = worldent.renderer.model->render_id;
|
||||||
bctx->main_pass.ent_frame = 0; // world is always frame 0
|
bctx->main_pass.ent_frame = 0; // world is always frame 0
|
||||||
bctx->main_pass.inst_id = world_id;
|
bctx->main_pass.inst_id = world_id;
|
||||||
|
if (bctx->main_pass.instances) {
|
||||||
DARRAY_APPEND (&bctx->main_pass.instances[world_id].entities,
|
DARRAY_APPEND (&bctx->main_pass.instances[world_id].entities,
|
||||||
worldent.renderer.render_id);
|
worldent.renderer.render_id);
|
||||||
|
}
|
||||||
R_VisitWorldNodes (brush, ctx);
|
R_VisitWorldNodes (brush, ctx);
|
||||||
if (!bctx->vertex_buffer) {
|
if (!bctx->vertex_buffer) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -82,8 +82,11 @@ typedef struct cachepic_s {
|
||||||
|
|
||||||
typedef struct drawframe_s {
|
typedef struct drawframe_s {
|
||||||
size_t vert_offset;
|
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_quads;
|
||||||
|
uint32_t num_lines;
|
||||||
VkCommandBuffer cmd;
|
VkCommandBuffer cmd;
|
||||||
VkDescriptorSet descriptors;
|
VkDescriptorSet descriptors;
|
||||||
} drawframe_t;
|
} drawframe_t;
|
||||||
|
@ -109,7 +112,8 @@ typedef struct drawctx_s {
|
||||||
VkDeviceMemory vert_memory;
|
VkDeviceMemory vert_memory;
|
||||||
VkBuffer ind_buffer;
|
VkBuffer ind_buffer;
|
||||||
VkDeviceMemory ind_memory;
|
VkDeviceMemory ind_memory;
|
||||||
VkPipeline pipeline;
|
VkPipeline quad_pipeline;
|
||||||
|
VkPipeline line_pipeline;
|
||||||
VkPipelineLayout layout;
|
VkPipelineLayout layout;
|
||||||
drawframeset_t frames;
|
drawframeset_t frames;
|
||||||
} drawctx_t;
|
} drawctx_t;
|
||||||
|
@ -119,6 +123,11 @@ typedef struct drawctx_s {
|
||||||
#define VERTS_PER_QUAD (4)
|
#define VERTS_PER_QUAD (4)
|
||||||
#define INDS_PER_QUAD (5) // one per vert plus primitive reset
|
#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
|
static void
|
||||||
create_quad_buffers (vulkan_ctx_t *ctx)
|
create_quad_buffers (vulkan_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
|
@ -133,7 +142,7 @@ create_quad_buffers (vulkan_ctx_t *ctx)
|
||||||
VkBuffer vbuf, ibuf;
|
VkBuffer vbuf, ibuf;
|
||||||
VkDeviceMemory vmem, imem;
|
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);
|
ind_size = MAX_QUADS * INDS_PER_QUAD * sizeof (uint32_t);
|
||||||
|
|
||||||
vbuf = QFV_CreateBuffer (device, vert_size,
|
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++) {
|
for (size_t f = 0; f < frames; f++) {
|
||||||
drawframe_t *frame = &dctx->frames.a[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->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_quads = 0;
|
||||||
|
frame->num_lines = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The indices will never change so pre-generate and stash them
|
// 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);
|
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);
|
Hash_DelTable (dctx->pic_cache);
|
||||||
delete_memsuper (dctx->pic_memsuper);
|
delete_memsuper (dctx->pic_memsuper);
|
||||||
delete_memsuper (dctx->string_memsuper);
|
delete_memsuper (dctx->string_memsuper);
|
||||||
|
@ -409,7 +423,8 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx)
|
||||||
|
|
||||||
flush_draw_scrap (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");
|
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;
|
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++;
|
frame->num_quads++;
|
||||||
|
|
||||||
subpic_t *subpic = *(subpic_t **) pic->data;
|
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);
|
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
|
static inline void
|
||||||
draw_blendscreen (quat_t color, vulkan_ctx_t *ctx)
|
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;
|
drawctx_t *dctx = ctx->draw_context;
|
||||||
drawframe_t *dframe = &dctx->frames.a[ctx->curFrame];
|
drawframe_t *dframe = &dctx->frames.a[ctx->curFrame];
|
||||||
|
|
||||||
|
if (!dframe->num_quads && !dframe->num_lines) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
VkCommandBuffer cmd = dframe->cmd;
|
VkCommandBuffer cmd = dframe->cmd;
|
||||||
//FIXME which pass?
|
//FIXME which pass?
|
||||||
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passTranslucent], cmd);
|
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passTranslucent], cmd);
|
||||||
|
|
||||||
VkMappedMemoryRange range = {
|
VkMappedMemoryRange ranges[] = {
|
||||||
VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0,
|
{ VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0,
|
||||||
dctx->vert_memory, dframe->vert_offset,
|
dctx->vert_memory, dframe->vert_offset,
|
||||||
dframe->num_quads * VERTS_PER_QUAD * sizeof (drawvert_t),
|
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);
|
dfunc->vkResetCommandBuffer (cmd, 0);
|
||||||
VkCommandBufferInheritanceInfo inherit = {
|
VkCommandBufferInheritanceInfo inherit = {
|
||||||
|
@ -843,10 +891,6 @@ Vulkan_FlushText (qfv_renderframe_t *rFrame)
|
||||||
|
|
||||||
QFV_duCmdBeginLabel (device, cmd, "twod", { 0.6, 0.2, 0, 1});
|
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};
|
VkDeviceSize offsets[] = {dframe->vert_offset};
|
||||||
dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, &dctx->vert_buffer, offsets);
|
dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, &dctx->vert_buffer, offsets);
|
||||||
dfunc->vkCmdBindIndexBuffer (cmd, dctx->ind_buffer, 0,
|
dfunc->vkCmdBindIndexBuffer (cmd, dctx->ind_buffer, 0,
|
||||||
|
@ -858,13 +902,27 @@ Vulkan_FlushText (qfv_renderframe_t *rFrame)
|
||||||
VkPipelineLayout layout = dctx->layout;
|
VkPipelineLayout layout = dctx->layout;
|
||||||
dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
layout, 0, 2, set, 0, 0);
|
layout, 0, 2, set, 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,
|
dfunc->vkCmdDrawIndexed (cmd, dframe->num_quads * INDS_PER_QUAD,
|
||||||
1, 0, 0, 0);
|
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);
|
QFV_duCmdEndLabel (device, cmd);
|
||||||
dfunc->vkEndCommandBuffer (cmd);
|
dfunc->vkEndCommandBuffer (cmd);
|
||||||
|
|
||||||
dframe->num_quads = 0;
|
dframe->num_quads = 0;
|
||||||
|
dframe->num_lines = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -10,6 +10,9 @@ struct _qpic_t {
|
||||||
};
|
};
|
||||||
typedef struct _qpic_t *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 void Draw_FreePic (qpic_t pic);
|
||||||
@extern qpic_t Draw_MakePic (int width, int heiight, string data);
|
@extern qpic_t Draw_MakePic (int width, int heiight, string data);
|
||||||
@extern qpic_t Draw_CachePic (string name, int alpha);
|
@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_nString (int x, int y, string text, int n);
|
||||||
@extern void Draw_AltString (int x, int y, string text);
|
@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_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 Draw_Crosshair (int ch, int x, int y);
|
||||||
@extern void text_box (int x, int y, int width, int lines);
|
@extern void text_box (int x, int y, int width, int lines);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
#include <draw.h>
|
#include <draw.h>
|
||||||
|
|
||||||
|
int Draw_Width (void) = #0;
|
||||||
|
int Draw_Height (void) = #0;
|
||||||
|
|
||||||
void Draw_FreePic (qpic_t pic) = #0;
|
void Draw_FreePic (qpic_t pic) = #0;
|
||||||
qpic_t Draw_MakePic (int width, int heiight, string data) = #0;
|
qpic_t Draw_MakePic (int width, int heiight, string data) = #0;
|
||||||
qpic_t (string name, int alpha) Draw_CachePic = #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, int n) Draw_nString = #0;
|
||||||
void (int x, int y, string text) Draw_AltString = #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 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 ch, int x, int y) Draw_Crosshair = #0;
|
||||||
|
|
||||||
void (int x, int y, int width, int lines) text_box =
|
void (int x, int y, int width, int lines) text_box =
|
||||||
|
|
Loading…
Reference in a new issue