mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-26 06:10:56 +00:00
[glsl] Implement font rendering
It's not the best code, but it does the job of getting the basics working.
This commit is contained in:
parent
1f5ec68b4a
commit
46967dbc05
4 changed files with 225 additions and 8 deletions
|
@ -31,6 +31,7 @@
|
||||||
#include "QF/qtypes.h"
|
#include "QF/qtypes.h"
|
||||||
|
|
||||||
typedef struct scrap_s scrap_t;
|
typedef struct scrap_s scrap_t;
|
||||||
|
struct tex_s;
|
||||||
|
|
||||||
int GLSL_LoadQuakeTexture (const char *identifier, int width, int height,
|
int GLSL_LoadQuakeTexture (const char *identifier, int width, int height,
|
||||||
const byte *data);
|
const byte *data);
|
||||||
|
@ -40,6 +41,7 @@ int GLSL_LoadRGBTexture (const char *identifier, int width, int height,
|
||||||
const byte *data);
|
const byte *data);
|
||||||
int GLSL_LoadRGBATexture (const char *identifier, int width, int height,
|
int GLSL_LoadRGBATexture (const char *identifier, int width, int height,
|
||||||
const byte *data);
|
const byte *data);
|
||||||
|
int GLSL_LoadTex (const char *identifier, int mips, struct tex_s *tex);
|
||||||
void GLSL_ReleaseTexture (int tex);
|
void GLSL_ReleaseTexture (int tex);
|
||||||
void GLSL_TextureInit (void);
|
void GLSL_TextureInit (void);
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include "QF/draw.h"
|
#include "QF/draw.h"
|
||||||
#include "QF/dstring.h"
|
#include "QF/dstring.h"
|
||||||
#include "QF/hash.h"
|
#include "QF/hash.h"
|
||||||
|
#include "QF/image.h"
|
||||||
#include "QF/quakefs.h"
|
#include "QF/quakefs.h"
|
||||||
#include "QF/sys.h"
|
#include "QF/sys.h"
|
||||||
#include "QF/vid.h"
|
#include "QF/vid.h"
|
||||||
|
@ -53,6 +54,8 @@
|
||||||
#include "QF/GLSL/qf_textures.h"
|
#include "QF/GLSL/qf_textures.h"
|
||||||
#include "QF/GLSL/qf_vid.h"
|
#include "QF/GLSL/qf_vid.h"
|
||||||
|
|
||||||
|
#include "r_font.h"
|
||||||
|
#include "r_text.h"
|
||||||
#include "r_internal.h"
|
#include "r_internal.h"
|
||||||
|
|
||||||
typedef struct cachepic_s {
|
typedef struct cachepic_s {
|
||||||
|
@ -66,6 +69,16 @@ typedef struct {
|
||||||
float color[4];
|
float color[4];
|
||||||
} drawvert_t;
|
} drawvert_t;
|
||||||
|
|
||||||
|
typedef struct glslfont_s {
|
||||||
|
rfont_t *font;
|
||||||
|
GLuint texid;
|
||||||
|
} glslfont_t;
|
||||||
|
|
||||||
|
typedef struct glfontset_s
|
||||||
|
DARRAY_TYPE (glslfont_t) glslfontset_t;
|
||||||
|
|
||||||
|
static glslfontset_t glsl_fonts = DARRAY_STATIC_INIT (16);
|
||||||
|
|
||||||
static const char *twod_vert_effects[] =
|
static const char *twod_vert_effects[] =
|
||||||
{
|
{
|
||||||
"QuakeForge.Vertex.2d",
|
"QuakeForge.Vertex.2d",
|
||||||
|
@ -79,6 +92,12 @@ static const char *twod_frag_effects[] =
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const char *twod_alpha_frag_effects[] =
|
||||||
|
{
|
||||||
|
"QuakeForge.Fragment.2d.alpha",
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
static float proj_matrix[16];
|
static float proj_matrix[16];
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
|
@ -89,17 +108,30 @@ static struct {
|
||||||
shaderparam_t vertex;
|
shaderparam_t vertex;
|
||||||
shaderparam_t color;
|
shaderparam_t color;
|
||||||
} quake_2d = {
|
} quake_2d = {
|
||||||
0,
|
.texture = {"texture", 1},
|
||||||
{"texture", 1},
|
.palette = {"palette", 1},
|
||||||
{"palette", 1},
|
.matrix = {"mvp_mat", 1},
|
||||||
{"mvp_mat", 1},
|
.vertex = {"vertex", 0},
|
||||||
{"vertex", 0},
|
.color = {"vcolor", 0},
|
||||||
{"vcolor", 0},
|
};
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
int program;
|
||||||
|
shaderparam_t texture;
|
||||||
|
shaderparam_t matrix;
|
||||||
|
shaderparam_t vertex;
|
||||||
|
shaderparam_t color;
|
||||||
|
} alpha_2d = {
|
||||||
|
.texture = {"texture", 1},
|
||||||
|
.matrix = {"mvp_mat", 1},
|
||||||
|
.vertex = {"vertex", 0},
|
||||||
|
.color = {"vcolor", 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
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 *glyph_queue;
|
||||||
static dstring_t *line_queue;
|
static dstring_t *line_queue;
|
||||||
static qpic_t *conchars;
|
static qpic_t *conchars;
|
||||||
static int conback_texture;
|
static int conback_texture;
|
||||||
|
@ -380,6 +412,7 @@ glsl_Draw_Init (void)
|
||||||
|
|
||||||
draw_queue = dstring_new ();
|
draw_queue = dstring_new ();
|
||||||
line_queue = dstring_new ();
|
line_queue = dstring_new ();
|
||||||
|
glyph_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);
|
||||||
|
@ -396,6 +429,20 @@ glsl_Draw_Init (void)
|
||||||
GLSL_FreeShader (vert_shader);
|
GLSL_FreeShader (vert_shader);
|
||||||
GLSL_FreeShader (frag_shader);
|
GLSL_FreeShader (frag_shader);
|
||||||
|
|
||||||
|
vert_shader = GLSL_BuildShader (twod_vert_effects);
|
||||||
|
frag_shader = GLSL_BuildShader (twod_alpha_frag_effects);
|
||||||
|
vert = GLSL_CompileShader ("quakeico.vert", vert_shader,
|
||||||
|
GL_VERTEX_SHADER);
|
||||||
|
frag = GLSL_CompileShader ("alpha2d.frag", frag_shader,
|
||||||
|
GL_FRAGMENT_SHADER);
|
||||||
|
alpha_2d.program = GLSL_LinkProgram ("alpha2d", vert, frag);
|
||||||
|
GLSL_ResolveShaderParam (alpha_2d.program, &alpha_2d.texture);
|
||||||
|
GLSL_ResolveShaderParam (alpha_2d.program, &alpha_2d.matrix);
|
||||||
|
GLSL_ResolveShaderParam (alpha_2d.program, &alpha_2d.vertex);
|
||||||
|
GLSL_ResolveShaderParam (alpha_2d.program, &alpha_2d.color);
|
||||||
|
GLSL_FreeShader (vert_shader);
|
||||||
|
GLSL_FreeShader (frag_shader);
|
||||||
|
|
||||||
draw_scrap = GLSL_CreateScrap (2048, GL_LUMINANCE, 0);
|
draw_scrap = GLSL_CreateScrap (2048, GL_LUMINANCE, 0);
|
||||||
|
|
||||||
draw_chars = W_GetLumpName ("conchars");
|
draw_chars = W_GetLumpName ("conchars");
|
||||||
|
@ -866,12 +913,121 @@ glsl_Draw_BlendScreen (quat_t color)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
glsl_Draw_AddFont (struct rfont_s *font)
|
glsl_Draw_AddFont (struct rfont_s *rfont)
|
||||||
{
|
{
|
||||||
return 0;
|
int fontid = glsl_fonts.size;
|
||||||
|
DARRAY_OPEN_AT (&glsl_fonts, fontid, 1);
|
||||||
|
glslfont_t *font = &glsl_fonts.a[fontid];
|
||||||
|
|
||||||
|
font->font = rfont;
|
||||||
|
tex_t tex = {
|
||||||
|
.width = rfont->scrap.width,
|
||||||
|
.height = rfont->scrap.height,
|
||||||
|
.format = tex_a,
|
||||||
|
.loaded = 1,
|
||||||
|
.data = rfont->scrap_bitmap,
|
||||||
|
};
|
||||||
|
font->texid = GLSL_LoadTex ("", 1, &tex);
|
||||||
|
return fontid;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
vrect_t *glyph_rects;
|
||||||
|
dstring_t *batch;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
float color[4];
|
||||||
|
} glslrgctx_t;
|
||||||
|
|
||||||
|
static void
|
||||||
|
glsl_render_glyph (uint32_t glyphid, int x, int y, void *_rgctx)
|
||||||
|
{
|
||||||
|
glslrgctx_t *rgctx = _rgctx;
|
||||||
|
vrect_t *rect = &rgctx->glyph_rects[glyphid];
|
||||||
|
dstring_t *batch = rgctx->batch;
|
||||||
|
int size = 6 * sizeof (drawvert_t);
|
||||||
|
|
||||||
|
batch->size += size;
|
||||||
|
dstring_adjust (batch);
|
||||||
|
drawvert_t *verts = (drawvert_t *) (batch->str + batch->size - size);
|
||||||
|
|
||||||
|
float w = rect->width;
|
||||||
|
float h = rect->height;
|
||||||
|
float u = rect->x;
|
||||||
|
float v = rect->y;
|
||||||
|
float s = 1.0 / rgctx->width;
|
||||||
|
float t = 1.0 / rgctx->height;
|
||||||
|
|
||||||
|
verts[0] = (drawvert_t) {
|
||||||
|
.xyst = { x, y, u * s, v * t },
|
||||||
|
};
|
||||||
|
verts[1] = (drawvert_t) {
|
||||||
|
.xyst = { x + w, y, (u + w) * s, v * t },
|
||||||
|
};
|
||||||
|
verts[2] = (drawvert_t) {
|
||||||
|
.xyst = { x + w, y + h, (u + w) * s, (v + h) * t },
|
||||||
|
};
|
||||||
|
verts[3] = (drawvert_t) {
|
||||||
|
.xyst = { x, y, u * s, v * t },
|
||||||
|
};
|
||||||
|
verts[4] = (drawvert_t) {
|
||||||
|
.xyst = { x + w, y + h, (u + w) * s, (v + h) * t },
|
||||||
|
};
|
||||||
|
verts[5] = (drawvert_t) {
|
||||||
|
.xyst = { x, y + h, u * s, (v + h) * t },
|
||||||
|
};
|
||||||
|
|
||||||
|
QuatCopy (rgctx->color, verts[0].color);
|
||||||
|
QuatCopy (rgctx->color, verts[1].color);
|
||||||
|
QuatCopy (rgctx->color, verts[2].color);
|
||||||
|
QuatCopy (rgctx->color, verts[3].color);
|
||||||
|
QuatCopy (rgctx->color, verts[4].color);
|
||||||
|
QuatCopy (rgctx->color, verts[5].color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
glsl_Draw_FontString (int x, int y, int fontid, const char *str)
|
glsl_Draw_FontString (int x, int y, int fontid, const char *str)
|
||||||
{
|
{
|
||||||
|
if (fontid < 0 || (unsigned) fontid > glsl_fonts.size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
glslfont_t *font = &glsl_fonts.a[fontid];
|
||||||
|
rfont_t *rfont = font->font;
|
||||||
|
glslrgctx_t rgctx = {
|
||||||
|
.glyph_rects = rfont->glyph_rects,
|
||||||
|
.batch = glyph_queue,
|
||||||
|
.width = rfont->scrap.width,
|
||||||
|
.height = rfont->scrap.height,
|
||||||
|
};
|
||||||
|
quat_t color = { 127, 255, 153, 255 };
|
||||||
|
QuatScale (color, 1.0f/255.0f, rgctx.color);
|
||||||
|
//FIXME ewwwwwww
|
||||||
|
rtext_t text = {
|
||||||
|
.text = str,
|
||||||
|
.language = "en",
|
||||||
|
.script = HB_SCRIPT_LATIN,
|
||||||
|
.direction = HB_DIRECTION_LTR,
|
||||||
|
};
|
||||||
|
|
||||||
|
rshaper_t *shaper = RText_NewShaper (rfont);
|
||||||
|
RText_RenderText (shaper, &text, x, y, glsl_render_glyph, &rgctx);
|
||||||
|
RText_DeleteShaper (shaper);
|
||||||
|
|
||||||
|
qfeglUseProgram (alpha_2d.program);
|
||||||
|
qfeglEnableVertexAttribArray (alpha_2d.vertex.location);
|
||||||
|
qfeglEnableVertexAttribArray (alpha_2d.color.location);
|
||||||
|
qfeglUniformMatrix4fv (alpha_2d.matrix.location, 1, false, proj_matrix);
|
||||||
|
qfeglBindTexture (GL_TEXTURE_2D, font->texid);
|
||||||
|
qfeglBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
if (glyph_queue->size) {
|
||||||
|
qfeglVertexAttribPointer (alpha_2d.vertex.location, 4, GL_FLOAT,
|
||||||
|
0, 32, glyph_queue->str);
|
||||||
|
qfeglVertexAttribPointer (alpha_2d.color.location, 4, GL_FLOAT,
|
||||||
|
0, 32, glyph_queue->str + 16);
|
||||||
|
|
||||||
|
qfeglDrawArrays (GL_TRIANGLES, 0, glyph_queue->size / 32);
|
||||||
|
}
|
||||||
|
glyph_queue->size = 0;
|
||||||
|
qfeglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
qfeglUseProgram (quake_2d.program);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "QF/cmd.h"
|
#include "QF/cmd.h"
|
||||||
|
#include "QF/image.h"
|
||||||
#include "QF/mathlib.h"
|
#include "QF/mathlib.h"
|
||||||
#include "QF/model.h"
|
#include "QF/model.h"
|
||||||
#include "QF/render.h"
|
#include "QF/render.h"
|
||||||
|
@ -238,6 +239,47 @@ GLSL_LoadRGBATexture (const char *identifier, int width, int height,
|
||||||
return tnum;
|
return tnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
GLSL_LoadTex (const char *identifier, int linear, tex_t *tex)
|
||||||
|
{
|
||||||
|
GLuint tnum;
|
||||||
|
qfeglGenTextures (1, &tnum);
|
||||||
|
int format = GL_RGB;
|
||||||
|
|
||||||
|
switch (tex->format) {
|
||||||
|
case tex_l:
|
||||||
|
case tex_a:
|
||||||
|
format = GL_LUMINANCE;
|
||||||
|
break;
|
||||||
|
case tex_la:
|
||||||
|
format = GL_LUMINANCE_ALPHA;
|
||||||
|
break;
|
||||||
|
case tex_rgb:
|
||||||
|
format = GL_RGB;
|
||||||
|
break;
|
||||||
|
case tex_rgba:
|
||||||
|
format = GL_RGBA;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Sys_Error ("GL_CreateScrap: Invalid texture format");
|
||||||
|
}
|
||||||
|
|
||||||
|
qfeglBindTexture (GL_TEXTURE_2D, tnum);
|
||||||
|
qfeglTexImage2D (GL_TEXTURE_2D, 0, format, tex->width, tex->height,
|
||||||
|
0, format, GL_UNSIGNED_BYTE, tex->data);
|
||||||
|
qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
if (linear) {
|
||||||
|
qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
} else {
|
||||||
|
qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
qfeglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
}
|
||||||
|
qfeglGenerateMipmap (GL_TEXTURE_2D);
|
||||||
|
return tnum;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GLSL_ReleaseTexture (int tex)
|
GLSL_ReleaseTexture (int tex)
|
||||||
{
|
{
|
||||||
|
|
|
@ -432,6 +432,23 @@ main (void)
|
||||||
gl_FragColor = palettedColor (pix) * color;
|
gl_FragColor = palettedColor (pix) * color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- Fragment.2d.alpha
|
||||||
|
|
||||||
|
uniform sampler2D texture;
|
||||||
|
varying vec4 color;
|
||||||
|
varying vec2 st;
|
||||||
|
|
||||||
|
void
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
float alpha;
|
||||||
|
|
||||||
|
alpha = texture2D (texture, st).r;
|
||||||
|
if (alpha == 0.0)
|
||||||
|
discard;
|
||||||
|
gl_FragColor = alpha * color;
|
||||||
|
}
|
||||||
|
|
||||||
-- Vertex.iqm
|
-- Vertex.iqm
|
||||||
|
|
||||||
uniform mat4 mvp_mat;
|
uniform mat4 mvp_mat;
|
||||||
|
|
Loading…
Reference in a new issue