mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-12-23 11:01:46 +00:00
783 lines
17 KiB
C
783 lines
17 KiB
C
/*
|
|
glsl_draw.c
|
|
|
|
2D drawing support for GLSL
|
|
|
|
Copyright (C) 2011 Bill Currie <bill@taniwha.org>
|
|
|
|
Author: Bill Currie <bill@taniwha.org>
|
|
Date: 2011/12/23
|
|
|
|
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
|
|
|
|
#define NH_DEFINE
|
|
#include "namehack.h"
|
|
|
|
#ifdef HAVE_STRING_H
|
|
# include <string.h>
|
|
#endif
|
|
#ifdef HAVE_STRINGS_H
|
|
# include <strings.h>
|
|
#endif
|
|
|
|
#include "QF/cvar.h"
|
|
#include "QF/draw.h"
|
|
#include "QF/dstring.h"
|
|
#include "QF/hash.h"
|
|
#include "QF/quakefs.h"
|
|
#include "QF/sys.h"
|
|
#include "QF/vid.h"
|
|
|
|
#include "QF/GLSL/defines.h"
|
|
#include "QF/GLSL/funcs.h"
|
|
#include "QF/GLSL/qf_draw.h"
|
|
#include "QF/GLSL/qf_textures.h"
|
|
#include "QF/GLSL/qf_vid.h"
|
|
|
|
#include "r_internal.h"
|
|
|
|
typedef struct {
|
|
subpic_t *subpic;
|
|
} glpic_t;
|
|
|
|
typedef struct cachepic_s {
|
|
struct cachepic_s *next;
|
|
char *name;
|
|
qpic_t *pic;
|
|
} cachepic_t;
|
|
|
|
typedef struct {
|
|
float xyst[4];
|
|
float color[4];
|
|
} drawvert_t;
|
|
|
|
static const char quakeicon_vert[] =
|
|
#include "quakeico.vc"
|
|
;
|
|
|
|
static const char quaketext_vert[] =
|
|
#include "quaketxt.vc"
|
|
;
|
|
|
|
static const char quake2d_frag[] =
|
|
#include "quake2d.fc"
|
|
;
|
|
|
|
static float proj_matrix[16];
|
|
|
|
static struct {
|
|
int program;
|
|
shaderparam_t texture;
|
|
shaderparam_t palette;
|
|
shaderparam_t matrix;
|
|
shaderparam_t vertex;
|
|
shaderparam_t color;
|
|
} quake_2d = {
|
|
0,
|
|
{"texture", 1},
|
|
{"palette", 1},
|
|
{"mvp_mat", 1},
|
|
{"vertex", 0},
|
|
{"vcolor", 0},
|
|
};
|
|
|
|
static scrap_t *draw_scrap; // hold all 2d images
|
|
static byte white_block[8 * 8];
|
|
static dstring_t *draw_queue;
|
|
static qpic_t *conchars;
|
|
static int conback_texture;
|
|
static qpic_t *crosshair_pic;
|
|
static qpic_t *white_pic;
|
|
static qpic_t *backtile_pic;
|
|
static hashtab_t *pic_cache;
|
|
static cvar_t *glsl_conback_texnum;
|
|
|
|
static qpic_t *
|
|
make_glpic (const char *name, qpic_t *p)
|
|
{
|
|
qpic_t *pic = 0;
|
|
glpic_t *gl;
|
|
|
|
if (p) {
|
|
// FIXME is alignment ok?
|
|
pic = malloc (sizeof (qpic_t) + sizeof (glpic_t));
|
|
pic->width = p->width;
|
|
pic->height = p->height;
|
|
gl = (glpic_t *) pic->data;
|
|
gl->subpic = GLSL_ScrapSubpic (draw_scrap, pic->width, pic->height);
|
|
GLSL_SubpicUpdate (gl->subpic, p->data, 1);
|
|
}
|
|
return pic;
|
|
}
|
|
|
|
static void
|
|
pic_free (qpic_t *pic)
|
|
{
|
|
glpic_t *gl = (glpic_t *) pic->data;
|
|
|
|
GLSL_SubpicDelete (gl->subpic);
|
|
free (pic);
|
|
}
|
|
|
|
//FIXME nicer allocator
|
|
static cachepic_t *
|
|
new_cachepic (const char *name, qpic_t *pic)
|
|
{
|
|
cachepic_t *cp;
|
|
|
|
cp = malloc (sizeof (cachepic_t));
|
|
cp->name = strdup (name);
|
|
cp->pic = pic;
|
|
return cp;
|
|
}
|
|
|
|
static const char *
|
|
cachepic_getkey (const void *_cp, void *unused)
|
|
{
|
|
return ((cachepic_t *) _cp)->name;
|
|
}
|
|
|
|
static void
|
|
cachepic_free (void *_cp, void *unused)
|
|
{
|
|
cachepic_t *cp = (cachepic_t *) _cp;
|
|
pic_free (cp->pic);
|
|
free (cp->name);
|
|
free (cp);
|
|
}
|
|
|
|
static qpic_t *
|
|
pic_data (const char *name, int w, int h, const byte *data)
|
|
{
|
|
qpic_t *pic;
|
|
qpic_t *glpic;
|
|
|
|
pic = malloc (field_offset (qpic_t, data[w * h]));
|
|
pic->width = w;
|
|
pic->height = h;
|
|
memcpy (pic->data, data, pic->width * pic->height);
|
|
glpic = make_glpic (name, pic);
|
|
free (pic);
|
|
return glpic;
|
|
}
|
|
|
|
static void
|
|
make_quad (qpic_t *pic, float x, float y, int w, int h,
|
|
int srcx, int srcy, int srcw, int srch, drawvert_t verts[6],
|
|
float *color)
|
|
{
|
|
glpic_t *gl;
|
|
subpic_t *sp;
|
|
float sl, sh, tl, th;
|
|
|
|
gl = (glpic_t *) pic->data;
|
|
sp = gl->subpic;
|
|
|
|
srcx += sp->rect->x;
|
|
srcy += sp->rect->y;
|
|
sl = (srcx) * sp->size;
|
|
sh = sl + (srcw) * sp->size;
|
|
tl = (srcy) * sp->size;
|
|
th = tl + (srch) * sp->size;
|
|
|
|
verts[0].xyst[0] = x;
|
|
verts[0].xyst[1] = y;
|
|
verts[0].xyst[2] = sl;
|
|
verts[0].xyst[3] = tl;
|
|
|
|
verts[1].xyst[0] = x + w;
|
|
verts[1].xyst[1] = y;
|
|
verts[1].xyst[2] = sh;
|
|
verts[1].xyst[3] = tl;
|
|
|
|
verts[2].xyst[0] = x + w;
|
|
verts[2].xyst[1] = y + h;
|
|
verts[2].xyst[2] = sh;
|
|
verts[2].xyst[3] = th;
|
|
|
|
verts[3].xyst[0] = x;
|
|
verts[3].xyst[1] = y;
|
|
verts[3].xyst[2] = sl;
|
|
verts[3].xyst[3] = tl;
|
|
|
|
verts[4].xyst[0] = x + w;
|
|
verts[4].xyst[1] = y + h;
|
|
verts[4].xyst[2] = sh;
|
|
verts[4].xyst[3] = th;
|
|
|
|
verts[5].xyst[0] = x;
|
|
verts[5].xyst[1] = y + h;
|
|
verts[5].xyst[2] = sl;
|
|
verts[5].xyst[3] = th;
|
|
|
|
QuatCopy (color, verts[0].color);
|
|
QuatCopy (color, verts[1].color);
|
|
QuatCopy (color, verts[2].color);
|
|
QuatCopy (color, verts[3].color);
|
|
QuatCopy (color, verts[4].color);
|
|
QuatCopy (color, verts[5].color);
|
|
}
|
|
|
|
static void
|
|
draw_pic (float x, float y, int w, int h, qpic_t *pic,
|
|
int srcx, int srcy, int srcw, int srch,
|
|
float *color)
|
|
{
|
|
drawvert_t verts[6];
|
|
void *v;
|
|
int size = sizeof (verts);
|
|
|
|
make_quad (pic, x, y, w, h, srcx, srcy, srcw, srch, verts, color);
|
|
draw_queue->size += size;
|
|
dstring_adjust (draw_queue);
|
|
v = draw_queue->str + draw_queue->size - size;
|
|
memcpy (v, verts, size);
|
|
}
|
|
|
|
qpic_t *
|
|
glsl_Draw_MakePic (int width, int height, const byte *data)
|
|
{
|
|
return pic_data (0, width, height, data);
|
|
}
|
|
|
|
void
|
|
glsl_Draw_DestroyPic (qpic_t *pic)
|
|
{
|
|
pic_free (pic);
|
|
}
|
|
|
|
qpic_t *
|
|
glsl_Draw_PicFromWad (const char *name)
|
|
{
|
|
return make_glpic (name, W_GetLumpName (name));
|
|
}
|
|
|
|
qpic_t *
|
|
glsl_Draw_CachePic (const char *path, qboolean alpha)
|
|
{
|
|
qpic_t *p, *pic;
|
|
cachepic_t *cpic;
|
|
|
|
if ((cpic = Hash_Find (pic_cache, path)))
|
|
return cpic->pic;
|
|
if (strlen (path) < 4 || strcmp (path + strlen (path) - 4, ".lmp")
|
|
|| !(p = (qpic_t *) QFS_LoadFile (path, 0))) {
|
|
//FIXME load a null texture
|
|
Sys_Error ("Draw_CachePic: failed to load %s", path);
|
|
}
|
|
|
|
pic = make_glpic (path, p);
|
|
free (p);
|
|
cpic = new_cachepic (path, pic);
|
|
Hash_Add (pic_cache, cpic);
|
|
return pic;
|
|
}
|
|
|
|
void
|
|
glsl_Draw_UncachePic (const char *path)
|
|
{
|
|
Hash_Free (pic_cache, Hash_Del (pic_cache, path));
|
|
}
|
|
|
|
void
|
|
glsl_Draw_TextBox (int x, int y, int width, int lines, byte alpha)
|
|
{
|
|
static quat_t color = { 1, 1, 1, 0 };
|
|
qpic_t *p;
|
|
int cx, cy, n;
|
|
#define draw(px,py,pp) \
|
|
draw_pic (px, py, pp->width, pp->height, pp, \
|
|
0, 0, pp->width, pp->height, color)
|
|
|
|
color[3] = alpha / 255.0;
|
|
// draw left side
|
|
cx = x;
|
|
cy = y;
|
|
p = glsl_Draw_CachePic ("gfx/box_tl.lmp", true);
|
|
draw (cx, cy, p);
|
|
p = glsl_Draw_CachePic ("gfx/box_ml.lmp", true);
|
|
for (n = 0; n < lines; n++) {
|
|
cy += 8;
|
|
draw (cx, cy, p);
|
|
}
|
|
p = glsl_Draw_CachePic ("gfx/box_bl.lmp", true);
|
|
draw (cx, cy + 8, p);
|
|
|
|
// draw middle
|
|
cx += 8;
|
|
while (width > 0) {
|
|
cy = y;
|
|
p = glsl_Draw_CachePic ("gfx/box_tm.lmp", true);
|
|
draw (cx, cy, p);
|
|
p = glsl_Draw_CachePic ("gfx/box_mm.lmp", true);
|
|
for (n = 0; n < lines; n++) {
|
|
cy += 8;
|
|
if (n == 1)
|
|
p = glsl_Draw_CachePic ("gfx/box_mm2.lmp", true);
|
|
draw (cx, cy, p);
|
|
}
|
|
p = glsl_Draw_CachePic ("gfx/box_bm.lmp", true);
|
|
draw (cx, cy + 8, p);
|
|
width -= 2;
|
|
cx += 16;
|
|
}
|
|
|
|
// draw right side
|
|
cy = y;
|
|
p = glsl_Draw_CachePic ("gfx/box_tr.lmp", true);
|
|
draw (cx, cy, p);
|
|
p = glsl_Draw_CachePic ("gfx/box_mr.lmp", true);
|
|
for (n = 0; n < lines; n++) {
|
|
cy += 8;
|
|
draw (cx, cy, p);
|
|
}
|
|
p = glsl_Draw_CachePic ("gfx/box_br.lmp", true);
|
|
draw (cx, cy + 8, p);
|
|
#undef draw
|
|
}
|
|
|
|
static void
|
|
Draw_ClearCache (int phase)
|
|
{
|
|
if (phase)
|
|
return;
|
|
Hash_FlushTable (pic_cache);
|
|
}
|
|
|
|
void
|
|
glsl_Draw_Init (void)
|
|
{
|
|
int i;
|
|
int frag, vert;
|
|
qpic_t *pic;
|
|
//FIXME glpic_t *gl;
|
|
|
|
pic_cache = Hash_NewTable (127, cachepic_getkey, cachepic_free, 0);
|
|
QFS_GamedirCallback (Draw_ClearCache);
|
|
//FIXME temporary work around for the timing of cvar creation and palette
|
|
//loading
|
|
crosshaircolor->callback (crosshaircolor);
|
|
|
|
draw_queue = dstring_new ();
|
|
|
|
vert = GLSL_CompileShader ("quakeico.vert", quakeicon_vert,
|
|
GL_VERTEX_SHADER);
|
|
frag = GLSL_CompileShader ("quake2d.frag", quake2d_frag,
|
|
GL_FRAGMENT_SHADER);
|
|
quake_2d.program = GLSL_LinkProgram ("quake2d", vert, frag);
|
|
GLSL_ResolveShaderParam (quake_2d.program, &quake_2d.texture);
|
|
GLSL_ResolveShaderParam (quake_2d.program, &quake_2d.palette);
|
|
GLSL_ResolveShaderParam (quake_2d.program, &quake_2d.matrix);
|
|
GLSL_ResolveShaderParam (quake_2d.program, &quake_2d.vertex);
|
|
GLSL_ResolveShaderParam (quake_2d.program, &quake_2d.color);
|
|
|
|
draw_scrap = GLSL_CreateScrap (2048, GL_LUMINANCE, 0);
|
|
|
|
draw_chars = W_GetLumpName ("conchars");
|
|
for (i = 0; i < 256 * 64; i++)
|
|
if (draw_chars[i] == 0)
|
|
draw_chars[i] = 255; // proper transparent color
|
|
|
|
conchars = pic_data ("conchars", 128, 128, draw_chars);
|
|
|
|
pic = (qpic_t *) QFS_LoadFile ("gfx/conback.lmp", 0);
|
|
if (pic) {
|
|
SwapPic (pic);
|
|
conback_texture = GLSL_LoadQuakeTexture ("conback",
|
|
pic->width, pic->height,
|
|
pic->data);
|
|
free (pic);
|
|
}
|
|
|
|
pic = Draw_CrosshairPic ();
|
|
crosshair_pic = make_glpic ("crosshair", pic);
|
|
free (pic);
|
|
|
|
memset (white_block, 0xfe, sizeof (white_block));
|
|
white_pic = pic_data ("white_block", 8, 8, white_block);
|
|
|
|
backtile_pic = glsl_Draw_PicFromWad ("backtile");
|
|
//FIXME gl = (glpic_t *) backtile_pic->data;
|
|
//FIXME qfeglBindTexture (GL_TEXTURE_2D, gl->texnum);
|
|
//FIXME qfeglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
//FIXME qfeglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
|
|
glsl_conback_texnum = Cvar_Get ("glsl_conback_texnum", "0", CVAR_NONE,
|
|
NULL, "bind conback to this texture for "
|
|
"debugging");
|
|
}
|
|
|
|
static inline void
|
|
queue_character (int x, int y, byte chr)
|
|
{
|
|
quat_t color = {1, 1, 1, 1};
|
|
int cx, cy;
|
|
|
|
cx = chr % 16;
|
|
cy = chr / 16;
|
|
draw_pic (x, y, 8, 8, conchars, cx * 8, cy * 8, 8, 8, color);
|
|
}
|
|
|
|
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);
|
|
draw_queue->size = 0;
|
|
}
|
|
|
|
void
|
|
glsl_Draw_Character (int x, int y, unsigned int chr)
|
|
{
|
|
chr &= 255;
|
|
|
|
if (chr == 32)
|
|
return; // space
|
|
if (y <= -8)
|
|
return; // totally off screen
|
|
|
|
queue_character (x, y, chr);
|
|
}
|
|
|
|
void
|
|
glsl_Draw_String (int x, int y, const char *str)
|
|
{
|
|
byte chr;
|
|
|
|
if (!str || !str[0])
|
|
return; // totally off screen
|
|
if (y <= -8)
|
|
return; // totally off screen
|
|
|
|
while (*str) {
|
|
if ((chr = *str++) != 32)
|
|
queue_character (x, y, chr);
|
|
x += 8;
|
|
}
|
|
}
|
|
|
|
void
|
|
glsl_Draw_nString (int x, int y, const char *str, int count)
|
|
{
|
|
byte chr;
|
|
|
|
if (!str || !str[0])
|
|
return; // totally off screen
|
|
if (y <= -8)
|
|
return; // totally off screen
|
|
|
|
while (count-- && *str) {
|
|
if ((chr = *str++) != 32)
|
|
queue_character (x, y, chr);
|
|
x += 8;
|
|
}
|
|
}
|
|
|
|
void
|
|
glsl_Draw_AltString (int x, int y, const char *str)
|
|
{
|
|
byte chr;
|
|
|
|
if (!str || !str[0])
|
|
return;
|
|
if (y <= -8)
|
|
return; // totally off screen
|
|
|
|
while (*str) {
|
|
if ((chr = *str++ | 0x80) != (0x80 | 32)) { // Don't render spaces
|
|
queue_character (x, y, chr);
|
|
}
|
|
x += 8;
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_crosshair_plus (int ch, int x, int y)
|
|
{
|
|
glsl_Draw_Character (x - 4, y - 4, '+');
|
|
}
|
|
|
|
static void
|
|
draw_crosshair_pic (int ch, int x, int y)
|
|
{
|
|
static const int pos[CROSSHAIR_COUNT][4] = {
|
|
{0, 0, CROSSHAIR_WIDTH, CROSSHAIR_HEIGHT},
|
|
{CROSSHAIR_WIDTH, 0, CROSSHAIR_WIDTH, CROSSHAIR_HEIGHT},
|
|
{0, CROSSHAIR_HEIGHT, CROSSHAIR_WIDTH, CROSSHAIR_HEIGHT},
|
|
{CROSSHAIR_WIDTH, CROSSHAIR_HEIGHT, CROSSHAIR_WIDTH, CROSSHAIR_HEIGHT},
|
|
};
|
|
const int *p = pos[ch - 1];
|
|
|
|
draw_pic (x - CROSSHAIR_WIDTH + 1, y - CROSSHAIR_HEIGHT + 1,
|
|
CROSSHAIR_WIDTH * 2, CROSSHAIR_HEIGHT * 2, crosshair_pic,
|
|
p[0], p[1], p[2], p[3], crosshair_color);
|
|
}
|
|
|
|
static void (*crosshair_func[]) (int ch, int x, int y) = {
|
|
draw_crosshair_plus,
|
|
draw_crosshair_pic,
|
|
draw_crosshair_pic,
|
|
draw_crosshair_pic,
|
|
draw_crosshair_pic,
|
|
};
|
|
|
|
void
|
|
glsl_Draw_CrosshairAt (int ch, int x, int y)
|
|
{
|
|
unsigned c = ch - 1;
|
|
|
|
if (c >= sizeof (crosshair_func) / sizeof (crosshair_func[0]))
|
|
return;
|
|
|
|
crosshair_func[c] (c, x, y);
|
|
}
|
|
|
|
void
|
|
glsl_Draw_Crosshair (void)
|
|
{
|
|
int x, y;
|
|
|
|
x = vid.conwidth / 2 + cl_crossx->int_val;
|
|
y = vid.conheight / 2 + cl_crossy->int_val;
|
|
|
|
glsl_Draw_CrosshairAt (crosshair->int_val, x, y);
|
|
}
|
|
|
|
void
|
|
glsl_Draw_Pic (int x, int y, qpic_t *pic)
|
|
{
|
|
static quat_t color = { 1, 1, 1, 1};
|
|
draw_pic (x, y, pic->width, pic->height, pic,
|
|
0, 0, pic->width, pic->height, color);
|
|
}
|
|
|
|
void
|
|
glsl_Draw_Picf (float x, float y, qpic_t *pic)
|
|
{
|
|
static quat_t color = { 1, 1, 1, 1};
|
|
draw_pic (x, y, pic->width, pic->height, pic,
|
|
0, 0, pic->width, pic->height, color);
|
|
}
|
|
|
|
void
|
|
glsl_Draw_SubPic (int x, int y, qpic_t *pic, int srcx, int srcy, int width,
|
|
int height)
|
|
{
|
|
static quat_t color = { 1, 1, 1, 1};
|
|
draw_pic (x, y, width, height, pic, srcx, srcy, width, height, color);
|
|
}
|
|
|
|
void
|
|
glsl_Draw_ConsoleBackground (int lines, byte alpha)
|
|
{
|
|
float ofs = (vid.conheight - lines) / (float) vid.conheight;
|
|
quat_t color = {1, 1, 1, bound (0, alpha, 255) / 255.0};
|
|
drawvert_t verts[] = {
|
|
{{ 0, 0, 0, ofs}},
|
|
{{vid.conwidth, 0, 1, ofs}},
|
|
{{vid.conwidth, lines, 1, 1}},
|
|
{{ 0, 0, 0, ofs}},
|
|
{{vid.conwidth, lines, 1, 1}},
|
|
{{ 0, lines, 0, 1}},
|
|
};
|
|
|
|
GLSL_FlushText (); // Flush text that should be rendered before the console
|
|
|
|
QuatCopy (color, verts[0].color);
|
|
QuatCopy (color, verts[1].color);
|
|
QuatCopy (color, verts[2].color);
|
|
QuatCopy (color, verts[3].color);
|
|
QuatCopy (color, verts[4].color);
|
|
QuatCopy (color, verts[5].color);
|
|
|
|
if (glsl_conback_texnum->int_val)
|
|
qfeglBindTexture (GL_TEXTURE_2D, glsl_conback_texnum->int_val);
|
|
else
|
|
qfeglBindTexture (GL_TEXTURE_2D, conback_texture);
|
|
|
|
qfeglVertexAttribPointer (quake_2d.vertex.location, 4, GL_FLOAT,
|
|
0, sizeof (drawvert_t), &verts[0].xyst);
|
|
qfeglVertexAttribPointer (quake_2d.color.location, 4, GL_FLOAT,
|
|
0, sizeof (drawvert_t), &verts[0].color);
|
|
|
|
qfeglDrawArrays (GL_TRIANGLES, 0, 6);
|
|
}
|
|
|
|
void
|
|
glsl_Draw_TileClear (int x, int y, int w, int h)
|
|
{
|
|
static quat_t color = { 1, 1, 1, 1 };
|
|
vrect_t *tile_rect = VRect_New (x, y, w, h);
|
|
vrect_t *sub = VRect_New (0, 0, 0, 0); // filled in later;
|
|
glpic_t *gl = (glpic_t *) backtile_pic->data;
|
|
subpic_t *sp = gl->subpic;
|
|
int sub_sx, sub_sy, sub_ex, sub_ey;
|
|
int i, j;
|
|
|
|
sub_sx = x / sp->width;
|
|
sub_sy = y / sp->height;
|
|
sub_ex = (x + w + sp->width - 1) / sp->width;
|
|
sub_ey = (y + h + sp->height - 1) / sp->height;
|
|
for (j = sub_sy; j < sub_ey; j++) {
|
|
for (i = sub_sx; i < sub_ex; i++) {
|
|
vrect_t *t = sub;
|
|
|
|
sub->x = i * sp->width;
|
|
sub->y = j * sp->height;
|
|
sub->width = sp->width;
|
|
sub->height = sp->height;
|
|
sub = VRect_Intersect (sub, tile_rect);
|
|
VRect_Delete (t);
|
|
draw_pic (sub->x, sub->y, sub->width, sub->height, backtile_pic,
|
|
sub->x % sp->width, sub->y % sp->height,
|
|
sub->width, sub->height, color);
|
|
}
|
|
}
|
|
VRect_Delete (sub);
|
|
VRect_Delete (tile_rect);
|
|
flush_2d ();
|
|
}
|
|
|
|
void
|
|
glsl_Draw_Fill (int x, int y, int w, int h, int c)
|
|
{
|
|
quat_t color;
|
|
|
|
VectorScale (vid.palette + c * 3, 1.0f/255.0f, color);
|
|
color[3] = 1.0;
|
|
draw_pic (x, y, w, h, white_pic, 0, 0, 8, 8, color);
|
|
}
|
|
|
|
static inline void
|
|
draw_blendscreen (quat_t color)
|
|
{
|
|
draw_pic (0, 0, vid.conwidth, vid.conheight, white_pic, 0, 0, 8, 8, color);
|
|
}
|
|
|
|
void
|
|
glsl_Draw_FadeScreen (void)
|
|
{
|
|
static quat_t color = { 0, 0, 0, 0.7 };
|
|
|
|
GLSL_FlushText (); // Flush text that should be rendered before the menu
|
|
draw_blendscreen (color);
|
|
}
|
|
|
|
static void
|
|
ortho_mat (float *proj, float xmin, float xmax, float ymin, float ymax,
|
|
float znear, float zfar)
|
|
{
|
|
proj[0] = 2 / (xmax - xmin);
|
|
proj[4] = 0;
|
|
proj[8] = 0;
|
|
proj[12] = -(xmax + xmin) / (xmax - xmin);
|
|
|
|
proj[1] = 0;
|
|
proj[5] = 2 / (ymax - ymin);
|
|
proj[9] = 0;
|
|
proj[13] = -(ymax + ymin) / (ymax - ymin);
|
|
|
|
proj[2] = 0;
|
|
proj[6] = 0;
|
|
proj[10] = -2 / (zfar - znear);
|
|
proj[14] = -(zfar + znear) / (zfar - znear);
|
|
|
|
proj[3] = 0;
|
|
proj[7] = 0;
|
|
proj[11] = 0;
|
|
proj[15] = 1;
|
|
}
|
|
|
|
static void
|
|
set_2d (int width, int height)
|
|
{
|
|
qfeglViewport (0, 0, vid.width, vid.height);
|
|
|
|
qfeglDisable (GL_DEPTH_TEST);
|
|
qfeglDisable (GL_CULL_FACE);
|
|
|
|
ortho_mat (proj_matrix, 0, width, height, 0, -99999, 99999);
|
|
|
|
qfeglUseProgram (quake_2d.program);
|
|
qfeglEnableVertexAttribArray (quake_2d.vertex.location);
|
|
qfeglEnableVertexAttribArray (quake_2d.color.location);
|
|
|
|
qfeglUniformMatrix4fv (quake_2d.matrix.location, 1, false, proj_matrix);
|
|
|
|
qfeglUniform1i (quake_2d.palette.location, 1);
|
|
qfeglActiveTexture (GL_TEXTURE0 + 1);
|
|
qfeglEnable (GL_TEXTURE_2D);
|
|
qfeglBindTexture (GL_TEXTURE_2D, glsl_palette);
|
|
|
|
qfeglUniform1i (quake_2d.texture.location, 0);
|
|
qfeglActiveTexture (GL_TEXTURE0 + 0);
|
|
qfeglEnable (GL_TEXTURE_2D);
|
|
qfeglBindTexture (GL_TEXTURE_2D, GLSL_ScrapTexture (draw_scrap));
|
|
}
|
|
|
|
void
|
|
GLSL_Set2D (void)
|
|
{
|
|
set_2d (vid.width, vid.height);
|
|
}
|
|
|
|
void
|
|
GLSL_Set2DScaled (void)
|
|
{
|
|
set_2d (vid.conwidth, vid.conheight);
|
|
}
|
|
|
|
void
|
|
GLSL_End2D (void)
|
|
{
|
|
qfeglDisableVertexAttribArray (quake_2d.vertex.location);
|
|
qfeglDisableVertexAttribArray (quake_2d.color.location);
|
|
}
|
|
|
|
void
|
|
GLSL_DrawReset (void)
|
|
{
|
|
draw_queue->size = 0;
|
|
}
|
|
|
|
void
|
|
GLSL_FlushText (void)
|
|
{
|
|
if (draw_queue->size)
|
|
flush_2d ();
|
|
}
|
|
|
|
void
|
|
glsl_Draw_BlendScreen (quat_t color)
|
|
{
|
|
if (!color[3])
|
|
return;
|
|
draw_blendscreen (color);
|
|
}
|