diff --git a/include/QF/GLSL/qf_draw.h b/include/QF/GLSL/qf_draw.h
index fd694e213..aa708a96a 100644
--- a/include/QF/GLSL/qf_draw.h
+++ b/include/QF/GLSL/qf_draw.h
@@ -30,6 +30,7 @@
 
 void GLSL_Set2D (void);
 void GLSL_Set2DScaled (void);
+void GLSL_End2D (void);
 void GLSL_DrawReset (void);
 void GLSL_FlushText (void);
 
diff --git a/libs/video/renderer/glsl/glsl_draw.c b/libs/video/renderer/glsl/glsl_draw.c
index cc6dcfcdd..679e29df5 100644
--- a/libs/video/renderer/glsl/glsl_draw.c
+++ b/libs/video/renderer/glsl/glsl_draw.c
@@ -58,7 +58,7 @@
 #include "r_internal.h"
 
 typedef struct {
-	int         texnum;
+	subpic_t   *subpic;
 } glpic_t;
 
 typedef struct cachepic_s {
@@ -67,6 +67,11 @@ typedef struct cachepic_s {
 	qpic_t     *pic;
 } cachepic_t;
 
+typedef struct {
+	float       xyst[4];
+	float       color[4];
+} drawvert_t;
+
 static const char quakeicon_vert[] =
 #include "quakeico.vc"
 ;
@@ -83,30 +88,12 @@ static float proj_matrix[16];
 
 static struct {
 	int         program;
-	shaderparam_t charmap;
+	shaderparam_t texture;
 	shaderparam_t palette;
 	shaderparam_t matrix;
 	shaderparam_t vertex;
 	shaderparam_t color;
-	shaderparam_t dchar;
-} quake_text = {
-	0,
-	{"texture", 1},
-	{"palette", 1},
-	{"mvp_mat", 1},
-	{"vertex", 0},
-	{"vcolor", 0},
-	{"dchar", 0},
-};
-
-static struct {
-	int         program;
-	shaderparam_t icon;
-	shaderparam_t palette;
-	shaderparam_t matrix;
-	shaderparam_t vertex;
-	shaderparam_t color;
-} quake_icon = {
+} quake_2d = {
 	0,
 	{"texture", 1},
 	{"palette", 1},
@@ -115,13 +102,14 @@ static struct {
 	{"vcolor", 0},
 };
 
+static scrap_t *draw_scrap;		// hold all 2d images
 static byte white_block[8 * 8];
 static dstring_t *char_queue;
-static int  char_texture;
+static qpic_t *conchars;
 static int  conback_texture;
 static qpic_t *crosshair_pic;
 static qpic_t *white_pic;
-static qpic_t *backtile_pic;
+//FIXME static qpic_t *backtile_pic;
 static hashtab_t *pic_cache;
 static cvar_t *glsl_conback_texnum;
 
@@ -134,10 +122,11 @@ make_glpic (const char *name, qpic_t *p)
 	if (p) {
 		// FIXME is alignment ok?
 		pic = malloc (sizeof (qpic_t) + sizeof (glpic_t));
-		*pic = *p;
+		pic->width = p->width;
+		pic->height = p->height;
 		gl = (glpic_t *) pic->data;
-		gl->texnum = GLSL_LoadQuakeTexture (name, p->width, p->height,
-											p->data);
+		gl->subpic = GLSL_ScrapSubpic (draw_scrap, pic->width, pic->height);
+		GLSL_SubpicUpdate (gl->subpic, p->data, 1);
 	}
 	return pic;
 }
@@ -147,7 +136,7 @@ pic_free (qpic_t *pic)
 {
 	glpic_t    *gl = (glpic_t *) pic->data;
 
-	GLSL_ReleaseTexture (gl->texnum);
+	GLSL_SubpicDelete (gl->subpic);
 	free (pic);
 }
 
@@ -195,44 +184,59 @@ pic_data (const char *name, int w, int h, const byte *data)
 
 static void
 make_quad (qpic_t *pic, float x, float y, int w, int h,
-		   int srcx, int srcy, int srcw, int srch, float verts[6][4])
+		   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;
 
-	sl = (float) srcx / (float) pic->width;
-	sh = sl + (float) srcw / (float) pic->width;
-	tl = (float) srcy / (float) pic->height;
-	th = tl + (float) srch / (float) pic->height;
+	gl = (glpic_t *) pic->data;
+	sp = gl->subpic;
 
-	verts[0][0] = x;
-	verts[0][1] = y;
-	verts[0][2] = sl;
-	verts[0][3] = tl;
+	srcx += sp->rect->x;
+	srcy += sp->rect->y;
+	sl = (srcx + 0.25) * sp->size;
+	sh = sl + (srcw - 0.5) * sp->size;
+	tl = (srcy + 0.25) * sp->size;
+	th = tl + (srch - 0.5) * sp->size;
 
-	verts[1][0] = x + w;
-	verts[1][1] = y;
-	verts[1][2] = sh;
-	verts[1][3] = tl;
+	verts[0].xyst[0] = x;
+	verts[0].xyst[1] = y;
+	verts[0].xyst[2] = sl;
+	verts[0].xyst[3] = tl;
 
-	verts[2][0] = x + w;
-	verts[2][1] = y + h;
-	verts[2][2] = sh;
-	verts[2][3] = th;
+	verts[1].xyst[0] = x + w;
+	verts[1].xyst[1] = y;
+	verts[1].xyst[2] = sh;
+	verts[1].xyst[3] = tl;
 
-	verts[3][0] = x;
-	verts[3][1] = y;
-	verts[3][2] = sl;
-	verts[3][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[4][0] = x + w;
-	verts[4][1] = y + h;
-	verts[4][2] = sh;
-	verts[4][3] = th;
+	verts[3].xyst[0] = x;
+	verts[3].xyst[1] = y;
+	verts[3].xyst[2] = sl;
+	verts[3].xyst[3] = tl;
 
-	verts[5][0] = x;
-	verts[5][1] = y + h;
-	verts[5][2] = sl;
-	verts[5][3] = th;
+	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
@@ -240,35 +244,15 @@ draw_pic (float x, float y, int w, int h, qpic_t *pic,
 		  int srcx, int srcy, int srcw, int srch,
 		  float *color)
 {
-	glpic_t    *gl;
-	float       verts[6][4];
+	drawvert_t  verts[6];
+	void       *v;
+	int         size = sizeof (verts);
 
-	make_quad (pic, x, y, w, h, srcx, srcy, srcw, srch, verts);
-	gl = (glpic_t *) pic->data;
-
-	qfeglUseProgram (quake_icon.program);
-	qfeglEnableVertexAttribArray (quake_icon.vertex.location);
-
-	qfeglUniformMatrix4fv (quake_icon.matrix.location, 1, false, proj_matrix);
-
-	qfeglUniform1i (quake_icon.icon.location, 0);
-	qfeglActiveTexture (GL_TEXTURE0 + 0);
-	qfeglEnable (GL_TEXTURE_2D);
-	qfeglBindTexture (GL_TEXTURE_2D, gl->texnum);
-
-	qfeglUniform1i (quake_icon.palette.location, 1);
-	qfeglActiveTexture (GL_TEXTURE0 + 1);
-	qfeglEnable (GL_TEXTURE_2D);
-	qfeglBindTexture (GL_TEXTURE_2D, glsl_palette);
-
-	qfeglVertexAttrib4fv (quake_icon.color.location, color);
-
-	qfeglVertexAttribPointer (quake_icon.vertex.location, 4, GL_FLOAT,
-							 0, 0, verts);
-
-	qfeglDrawArrays (GL_TRIANGLES, 0, 6);
-
-	qfeglDisableVertexAttribArray (quake_icon.vertex.location);
+	make_quad (pic, x, y, w, h, srcx, srcy, srcw, srch, verts, color);
+	char_queue->size += size;
+	dstring_adjust (char_queue);
+	v = char_queue->str + char_queue->size - size;
+	memcpy (v, verts, size);
 }
 
 qpic_t *
@@ -387,7 +371,7 @@ glsl_Draw_Init (void)
 	int         i;
 	int         frag, vert;
 	qpic_t     *pic;
-	glpic_t    *gl;
+	//FIXME glpic_t    *gl;
 
 	pic_cache = Hash_NewTable (127, cachepic_getkey, cachepic_free, 0);
 	QFS_GamedirCallback (Draw_ClearCache);
@@ -396,33 +380,26 @@ glsl_Draw_Init (void)
 	crosshaircolor->callback (crosshaircolor);
 
 	char_queue = dstring_new ();
-	vert = GLSL_CompileShader ("quaketxt.vert", quaketext_vert,
-							   GL_VERTEX_SHADER);
-	frag = GLSL_CompileShader ("quake2d.frag", quake2d_frag,
-							   GL_FRAGMENT_SHADER);
-	quake_text.program = GLSL_LinkProgram ("quaketxt", vert, frag);
-	GLSL_ResolveShaderParam (quake_text.program, &quake_text.charmap);
-	GLSL_ResolveShaderParam (quake_text.program, &quake_text.palette);
-	GLSL_ResolveShaderParam (quake_text.program, &quake_text.matrix);
-	GLSL_ResolveShaderParam (quake_text.program, &quake_text.vertex);
-	GLSL_ResolveShaderParam (quake_text.program, &quake_text.color);
-	GLSL_ResolveShaderParam (quake_text.program, &quake_text.dchar);
 
 	vert = GLSL_CompileShader ("quakeico.vert", quakeicon_vert,
 							   GL_VERTEX_SHADER);
-	quake_icon.program = GLSL_LinkProgram ("quakeico", vert, frag);
-	GLSL_ResolveShaderParam (quake_icon.program, &quake_icon.icon);
-	GLSL_ResolveShaderParam (quake_icon.program, &quake_icon.palette);
-	GLSL_ResolveShaderParam (quake_icon.program, &quake_icon.matrix);
-	GLSL_ResolveShaderParam (quake_icon.program, &quake_icon.vertex);
-	GLSL_ResolveShaderParam (quake_icon.program, &quake_icon.color);
+	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
 
-	char_texture = GLSL_LoadQuakeTexture ("conchars", 128, 128, draw_chars);
+	conchars = pic_data ("conchars", 128, 128, draw_chars);
 
 	pic = (qpic_t *) QFS_LoadFile ("gfx/conback.lmp", 0);
 	if (pic) {
@@ -440,11 +417,11 @@ glsl_Draw_Init (void)
 	memset (white_block, 0xfe, sizeof (white_block));
 	white_pic = pic_data ("white_block", 8, 8, white_block);
 
-	backtile_pic = glsl_Draw_PicFromWad ("backtile");
-	gl = (glpic_t *) backtile_pic->data;
-	qfeglBindTexture (GL_TEXTURE_2D, gl->texnum);
-	qfeglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-	qfeglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+	//FIXME 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 "
@@ -454,53 +431,25 @@ glsl_Draw_Init (void)
 static inline void
 queue_character (int x, int y, byte chr)
 {
-	unsigned short *v;
-	unsigned    i, c;
-	const int   size = 5 * 2 * 6;
+	quat_t      color = {1, 1, 1, 1};
+	int         cx, cy;
 
-	char_queue->size += size;
-	dstring_adjust (char_queue);
-	v = (unsigned short *) (char_queue->str + char_queue->size - size);
-	c = 0x738;
-	for (i = 0; i < 6; i++, c >>= 2) {
-		*v++ = x;
-		*v++ = y;
-		*v++ = c & 1;
-		*v++ = (c >> 1) & 1;
-		*v++ = chr;
-	}
+	cx = chr % 16;
+	cy = chr / 16;
+	draw_pic (x, y, 8, 8, conchars, cx * 8, cy * 8, 8, 8, color);
 }
 
 static void
-flush_text (void)
+flush_2d (void)
 {
-	qfeglUseProgram (quake_text.program);
-	qfeglEnableVertexAttribArray (quake_text.vertex.location);
-	qfeglEnableVertexAttribArray (quake_text.dchar.location);
+	GLSL_ScrapFlush (draw_scrap);
+	qfeglBindTexture (GL_TEXTURE_2D, GLSL_ScrapTexture (draw_scrap));
+	qfeglVertexAttribPointer (quake_2d.vertex.location, 4, GL_FLOAT,
+							 0, 32, char_queue->str);
+	qfeglVertexAttribPointer (quake_2d.color.location, 4, GL_FLOAT,
+							 0, 32, char_queue->str + 16);
 
-	qfeglUniformMatrix4fv (quake_text.matrix.location, 1, false, proj_matrix);
-
-	qfeglUniform1i (quake_text.charmap.location, 0);
-	qfeglActiveTexture (GL_TEXTURE0 + 0);
-	qfeglEnable (GL_TEXTURE_2D);
-	qfeglBindTexture (GL_TEXTURE_2D, char_texture);
-
-	qfeglUniform1i (quake_text.palette.location, 1);
-	qfeglActiveTexture (GL_TEXTURE0 + 1);
-	qfeglEnable (GL_TEXTURE_2D);
-	qfeglBindTexture (GL_TEXTURE_2D, glsl_palette);
-
-	qfeglVertexAttrib4f (quake_text.color.location, 1, 1, 1, 1);
-
-	qfeglVertexAttribPointer (quake_text.vertex.location, 4, GL_UNSIGNED_SHORT,
-							 0, 10, char_queue->str);
-	qfeglVertexAttribPointer (quake_text.dchar.location, 1, GL_UNSIGNED_SHORT,
-							 0, 10, char_queue->str + 8);
-
-	qfeglDrawArrays (GL_TRIANGLES, 0, char_queue->size / 10);
-
-	qfeglDisableVertexAttribArray (quake_text.dchar.location);
-	qfeglDisableVertexAttribArray (quake_text.vertex.location);
+	qfeglDrawArrays (GL_TRIANGLES, 0, char_queue->size / 32);
 	char_queue->size = 0;
 }
 
@@ -670,51 +619,43 @@ void
 glsl_Draw_ConsoleBackground (int lines, byte alpha)
 {
 	float       ofs = (vid.conheight - lines) / (float) vid.conheight;
-	float       verts[][4] = {
-		{           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},
+	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
 
-	qfeglUseProgram (quake_icon.program);
-	qfeglEnableVertexAttribArray (quake_icon.vertex.location);
+	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);
 
-	qfeglUniformMatrix4fv (quake_icon.matrix.location, 1, false, proj_matrix);
-
-	qfeglUniform1i (quake_icon.icon.location, 0);
-	qfeglActiveTexture (GL_TEXTURE0 + 0);
-	qfeglEnable (GL_TEXTURE_2D);
 	if (glsl_conback_texnum->int_val)
 		qfeglBindTexture (GL_TEXTURE_2D, glsl_conback_texnum->int_val);
 	else
 		qfeglBindTexture (GL_TEXTURE_2D, conback_texture);
 
-	qfeglUniform1i (quake_icon.palette.location, 1);
-	qfeglActiveTexture (GL_TEXTURE0 + 1);
-	qfeglEnable (GL_TEXTURE_2D);
-	qfeglBindTexture (GL_TEXTURE_2D, glsl_palette);
-
-	qfeglVertexAttrib4f (quake_icon.color.location,
-						1, 1, 1, bound (0, alpha, 255) / 255.0);
-
-	qfeglVertexAttribPointer (quake_icon.vertex.location, 4, GL_FLOAT,
-							 0, 0, verts);
+	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);
-
-	qfeglDisableVertexAttribArray (quake_icon.vertex.location);
 }
 
 void
 glsl_Draw_TileClear (int x, int y, int w, int h)
 {
-	static quat_t color = { 1, 1, 1, 1 };
-	draw_pic (x, y, w, h, backtile_pic, 0, 0, w, h, color);
+	//FIXME static quat_t color = { 1, 1, 1, 1 };
+	//FIXME draw_pic (x, y, w, h, backtile_pic, 0, 0, w, h, color);
 }
 
 void
@@ -776,6 +717,24 @@ set_2d (int width, int height)
 	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));
+
+	qfeglVertexAttrib4f (quake_2d.color.location, 1, 1, 1, 1);
 }
 
 void
@@ -790,6 +749,13 @@ 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)
 {
@@ -800,7 +766,7 @@ void
 GLSL_FlushText (void)
 {
 	if (char_queue->size)
-		flush_text ();
+		flush_2d ();
 }
 
 void
diff --git a/libs/video/renderer/glsl/glsl_screen.c b/libs/video/renderer/glsl/glsl_screen.c
index 93ea1debe..776bbe4bd 100644
--- a/libs/video/renderer/glsl/glsl_screen.c
+++ b/libs/video/renderer/glsl/glsl_screen.c
@@ -197,6 +197,7 @@ glsl_SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc,
 		scr_funcs++;
 		GLSL_FlushText ();
 	}
+	GLSL_End2D ();
 	qfeglFlush ();
 }