]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_draw.c
Reworked VM_CL_PolygonBegin/Vertex/End functions to do the commit to the mesh in...
[xonotic/darkplaces.git] / gl_draw.c
index ac92aa5dbfb46653819912c87e5dbb6b4a7d1ffa..cdd5b766172ec63d233cf438d8ddb58448af165c 100644 (file)
--- a/gl_draw.c
+++ b/gl_draw.c
@@ -50,19 +50,19 @@ struct cachepic_s
 dp_fonts_t dp_fonts;
 static mempool_t *fonts_mempool = NULL;
 
-cvar_t r_textshadow = {CVAR_SAVE, "r_textshadow", "0", "draws a shadow on all text to improve readability (note: value controls offset, 1 = 1 pixel, 1.5 = 1.5 pixels, etc)"};
-cvar_t r_textbrightness = {CVAR_SAVE, "r_textbrightness", "0", "additional brightness for text color codes (0 keeps colors as is, 1 makes them all white)"};
-cvar_t r_textcontrast = {CVAR_SAVE, "r_textcontrast", "1", "additional contrast for text color codes (1 keeps colors as is, 0 makes them all black)"};
-
-cvar_t r_font_postprocess_blur = {CVAR_SAVE, "r_font_postprocess_blur", "0", "font blur amount"};
-cvar_t r_font_postprocess_outline = {CVAR_SAVE, "r_font_postprocess_outline", "0", "font outline amount"};
-cvar_t r_font_postprocess_shadow_x = {CVAR_SAVE, "r_font_postprocess_shadow_x", "0", "font shadow X shift amount, applied during outlining"};
-cvar_t r_font_postprocess_shadow_y = {CVAR_SAVE, "r_font_postprocess_shadow_y", "0", "font shadow Y shift amount, applied during outlining"};
-cvar_t r_font_postprocess_shadow_z = {CVAR_SAVE, "r_font_postprocess_shadow_z", "0", "font shadow Z shift amount, applied during blurring"};
-cvar_t r_font_hinting = {CVAR_SAVE, "r_font_hinting", "3", "0 = no hinting, 1 = light autohinting, 2 = full autohinting, 3 = full hinting"};
-cvar_t r_font_antialias = {CVAR_SAVE, "r_font_antialias", "1", "0 = monochrome, 1 = grey" /* , 2 = rgb, 3 = bgr" */};
-cvar_t r_nearest_2d = {CVAR_SAVE, "r_nearest_2d", "0", "use nearest filtering on all 2d textures (including conchars)"};
-cvar_t r_nearest_conchars = {CVAR_SAVE, "r_nearest_conchars", "0", "use nearest filtering on conchars texture"};
+cvar_t r_textshadow = {CVAR_CLIENT | CVAR_SAVE, "r_textshadow", "0", "draws a shadow on all text to improve readability (note: value controls offset, 1 = 1 pixel, 1.5 = 1.5 pixels, etc)"};
+cvar_t r_textbrightness = {CVAR_CLIENT | CVAR_SAVE, "r_textbrightness", "0", "additional brightness for text color codes (0 keeps colors as is, 1 makes them all white)"};
+cvar_t r_textcontrast = {CVAR_CLIENT | CVAR_SAVE, "r_textcontrast", "1", "additional contrast for text color codes (1 keeps colors as is, 0 makes them all black)"};
+
+cvar_t r_font_postprocess_blur = {CVAR_CLIENT | CVAR_SAVE, "r_font_postprocess_blur", "0", "font blur amount"};
+cvar_t r_font_postprocess_outline = {CVAR_CLIENT | CVAR_SAVE, "r_font_postprocess_outline", "0", "font outline amount"};
+cvar_t r_font_postprocess_shadow_x = {CVAR_CLIENT | CVAR_SAVE, "r_font_postprocess_shadow_x", "0", "font shadow X shift amount, applied during outlining"};
+cvar_t r_font_postprocess_shadow_y = {CVAR_CLIENT | CVAR_SAVE, "r_font_postprocess_shadow_y", "0", "font shadow Y shift amount, applied during outlining"};
+cvar_t r_font_postprocess_shadow_z = {CVAR_CLIENT | CVAR_SAVE, "r_font_postprocess_shadow_z", "0", "font shadow Z shift amount, applied during blurring"};
+cvar_t r_font_hinting = {CVAR_CLIENT | CVAR_SAVE, "r_font_hinting", "3", "0 = no hinting, 1 = light autohinting, 2 = full autohinting, 3 = full hinting"};
+cvar_t r_font_antialias = {CVAR_CLIENT | CVAR_SAVE, "r_font_antialias", "1", "0 = monochrome, 1 = grey" /* , 2 = rgb, 3 = bgr" */};
+cvar_t r_nearest_2d = {CVAR_CLIENT | CVAR_SAVE, "r_nearest_2d", "0", "use nearest filtering on all 2d textures (including conchars)"};
+cvar_t r_nearest_conchars = {CVAR_CLIENT | CVAR_SAVE, "r_nearest_conchars", "0", "use nearest filtering on conchars texture"};
 
 //=============================================================================
 /* Support Routines */
@@ -105,32 +105,39 @@ cachepic_t *Draw_CachePic_Flags(const char *path, unsigned int cachepicflags)
                if (!strcmp(path, pic->name))
                {
                        // if it was created (or replaced) by Draw_NewPic, just return it
-                       if (pic->flags & CACHEPICFLAG_NEWPIC)
-                       {
-                               if (pic->skinframe)
-                                       R_SkinFrame_MarkUsed(pic->skinframe);
-                               pic->lastusedframe = draw_frame;
-                               return pic;
-                       }
-                       if (!((pic->texflags ^ texflags) & ~(TEXF_COMPRESS | TEXF_MIPMAP))) // ignore TEXF_COMPRESS when comparing, because fallback pics remove the flag, and ignore TEXF_MIPMAP because QC specifies that
+                       if (!(pic->flags & CACHEPICFLAG_NEWPIC))
                        {
+                               // reload the pic if texflags changed in important ways
+                               // ignore TEXF_COMPRESS when comparing, because fallback pics remove the flag, and ignore TEXF_MIPMAP because QC specifies that
+                               if ((pic->texflags ^ texflags) & ~(TEXF_COMPRESS | TEXF_MIPMAP))
+                               {
+                                       Con_DPrintf("Draw_CachePic(\"%s\"): frame %i: reloading pic due to mismatch on flags\n", path, draw_frame);
+                                       goto reload;
+                               }
                                if (!pic->skinframe || !pic->skinframe->base)
+                               {
+                                       if (pic->flags & CACHEPICFLAG_FAILONMISSING)
+                                               return NULL;
+                                       Con_DPrintf("Draw_CachePic(\"%s\"): frame %i: reloading pic\n", path, draw_frame);
                                        goto reload;
+                               }
                                if (!(cachepicflags & CACHEPICFLAG_NOTPERSISTENT))
                                        pic->autoload = false; // caller is making this pic persistent
-                               R_SkinFrame_MarkUsed(pic->skinframe);
-                               pic->lastusedframe = draw_frame;
-                               return pic;
                        }
+                       if (pic->skinframe)
+                               R_SkinFrame_MarkUsed(pic->skinframe);
+                       pic->lastusedframe = draw_frame;
+                       return pic;
                }
        }
 
        if (numcachepics == MAX_CACHED_PICS)
        {
-               Con_Printf ("Draw_CachePic: numcachepics == MAX_CACHED_PICS\n");
+               Con_DPrintf ("Draw_CachePic(\"%s\"): frame %i: numcachepics == MAX_CACHED_PICS\n", path, draw_frame);
                // FIXME: support NULL in callers?
                return cachepics; // return the first one
        }
+       Con_DPrintf("Draw_CachePic(\"%s\"): frame %i: loading pic%s\n", path, draw_frame, (cachepicflags & CACHEPICFLAG_NOTPERSISTENT) ? " notpersist" : "");
        pic = cachepics + (numcachepics++);
        memset(pic, 0, sizeof(*pic));
        strlcpy (pic->name, path, sizeof(pic->name));
@@ -147,8 +154,16 @@ reload:
        pic->autoload = (cachepicflags & CACHEPICFLAG_NOTPERSISTENT) != 0;
        pic->lastusedframe = draw_frame;
 
-       // load high quality image (this falls back to low quality too)
-       pic->skinframe = R_SkinFrame_LoadExternal(pic->name, texflags, (cachepicflags & CACHEPICFLAG_QUIET) == 0, (cachepicflags & CACHEPICFLAG_FAILONMISSING) == 0);
+       if (pic->skinframe)
+       {
+               // reload image after it was unloaded or texflags changed significantly
+               R_SkinFrame_LoadExternal_SkinFrame(pic->skinframe, pic->name, texflags | TEXF_FORCE_RELOAD, (cachepicflags & CACHEPICFLAG_QUIET) == 0, (cachepicflags & CACHEPICFLAG_FAILONMISSING) == 0);
+       }
+       else
+       {
+               // load high quality image (this falls back to low quality too)
+               pic->skinframe = R_SkinFrame_LoadExternal(pic->name, texflags | TEXF_FORCE_RELOAD, (cachepicflags & CACHEPICFLAG_QUIET) == 0, (cachepicflags & CACHEPICFLAG_FAILONMISSING) == 0);
+       }
 
        // get the dimensions of the image we loaded (if it was successful)
        if (pic->skinframe && pic->skinframe->base)
@@ -194,7 +209,10 @@ qboolean Draw_IsPicLoaded(cachepic_t *pic)
        if (pic == NULL)
                return false;
        if (pic->autoload && (!pic->skinframe || !pic->skinframe->base))
-               pic->skinframe = R_SkinFrame_LoadExternal(pic->name, pic->texflags, false, true);
+       {
+               Con_DPrintf("Draw_IsPicLoaded(\"%s\"): Loading external skin\n", pic->name);
+               pic->skinframe = R_SkinFrame_LoadExternal(pic->name, pic->texflags | TEXF_FORCE_RELOAD, false, true);
+       }
        // skinframe will only be NULL if the pic was created with CACHEPICFLAG_FAILONMISSING and not found
        return pic->skinframe != NULL && pic->skinframe->base != NULL;
 }
@@ -204,7 +222,10 @@ rtexture_t *Draw_GetPicTexture(cachepic_t *pic)
        if (pic == NULL)
                return NULL;
        if (pic->autoload && (!pic->skinframe || !pic->skinframe->base))
-               pic->skinframe = R_SkinFrame_LoadExternal(pic->name, pic->texflags, false, true);
+       {
+               Con_DPrintf("Draw_GetPicTexture(\"%s\"): Loading external skin\n", pic->name);
+               pic->skinframe = R_SkinFrame_LoadExternal(pic->name, pic->texflags | TEXF_FORCE_RELOAD, false, true);
+       }
        pic->lastusedframe = draw_frame;
        return pic->skinframe ? pic->skinframe->base : NULL;
 }
@@ -218,8 +239,13 @@ void Draw_Frame(void)
                return;
        nextpurgetime = realtime + 0.05;
        for (i = 0, pic = cachepics;i < numcachepics;i++, pic++)
-               if (pic->autoload && pic->skinframe && pic->skinframe->base && pic->lastusedframe < draw_frame)
+       {
+               if (pic->autoload && pic->skinframe && pic->skinframe->base && pic->lastusedframe < draw_frame - 3)
+               {
+                       Con_DPrintf("Draw_Frame(%i): Unloading \"%s\"\n", draw_frame, pic->name);
                        R_SkinFrame_PurgeSkinFrame(pic->skinframe);
+               }
+       }
        draw_frame++;
 }
 
@@ -238,20 +264,23 @@ cachepic_t *Draw_NewPic(const char *picname, int width, int height, unsigned cha
        {
                if (pic->flags & CACHEPICFLAG_NEWPIC && pic->skinframe && pic->skinframe->base && pic->width == width && pic->height == height)
                {
+                       Con_DPrintf("Draw_NewPic(\"%s\"): frame %i: updating texture\n", picname, draw_frame);
                        R_UpdateTexture(pic->skinframe->base, pixels_bgra, 0, 0, 0, width, height, 1);
                        R_SkinFrame_MarkUsed(pic->skinframe);
                        pic->lastusedframe = draw_frame;
                        return pic;
                }
+               Con_DPrintf("Draw_NewPic(\"%s\"): frame %i: reloading pic because flags/size changed\n", picname, draw_frame);
        }
        else
        {
                if (numcachepics == MAX_CACHED_PICS)
                {
-                       Con_Printf ("Draw_NewPic: numcachepics == MAX_CACHED_PICS\n");
+                       Con_DPrintf ("Draw_NewPic(\"%s\"): frame %i: numcachepics == MAX_CACHED_PICS\n", picname, draw_frame);
                        // FIXME: support NULL in callers?
                        return cachepics; // return the first one
                }
+               Con_DPrintf("Draw_NewPic(\"%s\"): frame %i: creating new cachepic\n", picname, draw_frame);
                pic = cachepics + (numcachepics++);
                memset(pic, 0, sizeof(*pic));
                strlcpy (pic->name, picname, sizeof(pic->name));
@@ -262,12 +291,13 @@ cachepic_t *Draw_NewPic(const char *picname, int width, int height, unsigned cha
 
        R_SkinFrame_PurgeSkinFrame(pic->skinframe);
 
+       pic->autoload = false;
        pic->flags = CACHEPICFLAG_NEWPIC; // disable texflags checks in Draw_CachePic
        pic->flags |= (texflags & TEXF_CLAMP) ? 0 : CACHEPICFLAG_NOCLAMP;
        pic->flags |= (texflags & TEXF_FORCENEAREST) ? CACHEPICFLAG_NEAREST : 0;
        pic->width = width;
        pic->height = height;
-       pic->skinframe = R_SkinFrame_LoadInternalBGRA(picname, texflags, pixels_bgra, width, height, vid.sRGB2D);
+       pic->skinframe = R_SkinFrame_LoadInternalBGRA(picname, texflags | TEXF_FORCE_RELOAD, pixels_bgra, width, height, 0, 0, 0, vid.sRGB2D);
        pic->lastusedframe = draw_frame;
        return pic;
 }
@@ -284,9 +314,8 @@ void Draw_FreePic(const char *picname)
        {
                if (!strcmp (picname, pic->name) && pic->skinframe)
                {
+                       Con_DPrintf("Draw_FreePic(\"%s\"): frame %i: freeing pic\n", picname, draw_frame);
                        R_SkinFrame_PurgeSkinFrame(pic->skinframe);
-                       pic->width = 0;
-                       pic->height = 0;
                        return;
                }
        }
@@ -408,7 +437,7 @@ void LoadFont(qboolean override, const char *name, dp_font_t *fnt, float scale,
                                        }
                                        else
                                        {
-                                               Con_Printf("Warning: skipped unknown font property %s\n", com_token);
+                                               Con_DPrintf("Warning: skipped unknown font property %s\n", com_token);
                                                if(!COM_ParseToken_Simple(&p, false, false, true))
                                                        return;
                                        }
@@ -507,7 +536,7 @@ static float snap_to_pixel_y(float y, float roundUpAt)
        */
 }
 
-static void LoadFont_f(void)
+static void LoadFont_f(cmd_state_t *cmd)
 {
        dp_font_t *f;
        int i, sizes;
@@ -515,7 +544,7 @@ static void LoadFont_f(void)
        float sz, scale, voffset;
        char mainfont[MAX_QPATH];
 
-       if(Cmd_Argc() < 2)
+       if(Cmd_Argc(cmd) < 2)
        {
                Con_Printf("Available font commands:\n");
                for(i = 0; i < dp_fonts.maxsize; ++i)
@@ -535,17 +564,17 @@ static void LoadFont_f(void)
                        );
                return;
        }
-       f = FindFont(Cmd_Argv(1), true);
+       f = FindFont(Cmd_Argv(cmd, 1), true);
        if(f == NULL)
        {
                Con_Printf("font function not found\n");
                return;
        }
 
-       if(Cmd_Argc() < 3)
+       if(Cmd_Argc(cmd) < 3)
                filelist = "gfx/conchars";
        else
-               filelist = Cmd_Argv(2);
+               filelist = Cmd_Argv(cmd, 2);
 
        memset(f->fallbacks, 0, sizeof(f->fallbacks));
        memset(f->fallback_faces, 0, sizeof(f->fallback_faces));
@@ -604,23 +633,23 @@ static void LoadFont_f(void)
 
        scale = 1;
        voffset = 0;
-       if(Cmd_Argc() >= 4)
+       if(Cmd_Argc(cmd) >= 4)
        {
-               for(sizes = 0, i = 3; i < Cmd_Argc(); ++i)
+               for(sizes = 0, i = 3; i < Cmd_Argc(cmd); ++i)
                {
                        // special switches
-                       if (!strcmp(Cmd_Argv(i), "scale"))
+                       if (!strcmp(Cmd_Argv(cmd, i), "scale"))
                        {
                                i++;
-                               if (i < Cmd_Argc())
-                                       scale = atof(Cmd_Argv(i));
+                               if (i < Cmd_Argc(cmd))
+                                       scale = atof(Cmd_Argv(cmd, i));
                                continue;
                        }
-                       if (!strcmp(Cmd_Argv(i), "voffset"))
+                       if (!strcmp(Cmd_Argv(cmd, i), "voffset"))
                        {
                                i++;
-                               if (i < Cmd_Argc())
-                                       voffset = atof(Cmd_Argv(i));
+                               if (i < Cmd_Argc(cmd))
+                                       voffset = atof(Cmd_Argv(cmd, i));
                                continue;
                        }
 
@@ -628,7 +657,7 @@ static void LoadFont_f(void)
                                continue; // no slot for other sizes
 
                        // parse one of sizes
-                       sz = atof(Cmd_Argv(i));
+                       sz = atof(Cmd_Argv(cmd, i));
                        if (sz > 0.001f && sz < 1000.0f) // do not use crap sizes
                        {
                                // search for duplicated sizes
@@ -740,7 +769,7 @@ void GL_Draw_Init (void)
                if(!FONT_USER(i)->title[0])
                        dpsnprintf(FONT_USER(i)->title, sizeof(FONT_USER(i)->title), "user%d", j++);
 
-       Cmd_AddCommand ("loadfont",LoadFont_f, "loadfont function tganame loads a font; example: loadfont console gfx/veramono; loadfont without arguments lists the available functions");
+       Cmd_AddCommand(&cmd_client, "loadfont", LoadFont_f, "loadfont function tganame loads a font; example: loadfont console gfx/veramono; loadfont without arguments lists the available functions");
        R_RegisterModule("GL_Draw", gl_draw_start, gl_draw_shutdown, gl_draw_newmap, NULL, NULL);
 }
 
@@ -759,11 +788,13 @@ void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, flo
        int e0, e1, e2, e3;
        if (!pic)
                pic = Draw_CachePic("white");
+       // make sure pic is loaded - we don't use the texture here, Mod_Mesh_GetTexture looks up the skinframe by name
+       Draw_GetPicTexture(pic);
        if (width == 0)
                width = pic->width;
        if (height == 0)
                height = pic->height;
-       surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, pic->name, flags, pic->texflags, MATERIALFLAG_VERTEXCOLOR), true);
+       surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, pic->name, flags, pic->texflags, MATERIALFLAG_WALL | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX), true);
        e0 = Mod_Mesh_IndexForVertex(mod, surf, x        , y         , 0, 0, 0, -1, 0, 0, 0, 0, red, green, blue, alpha);
        e1 = Mod_Mesh_IndexForVertex(mod, surf, x + width, y         , 0, 0, 0, -1, 1, 0, 0, 0, red, green, blue, alpha);
        e2 = Mod_Mesh_IndexForVertex(mod, surf, x + width, y + height, 0, 0, 0, -1, 1, 1, 0, 0, red, green, blue, alpha);
@@ -785,15 +816,17 @@ void DrawQ_RotPic(float x, float y, cachepic_t *pic, float width, float height,
        int e0, e1, e2, e3;
        if (!pic)
                pic = Draw_CachePic("white");
+       // make sure pic is loaded - we don't use the texture here, Mod_Mesh_GetTexture looks up the skinframe by name
+       Draw_GetPicTexture(pic);
        if (width == 0)
                width = pic->width;
        if (height == 0)
                height = pic->height;
-       surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, pic->name, flags, pic->texflags, MATERIALFLAG_VERTEXCOLOR), true);
-       e0 = Mod_Mesh_IndexForVertex(mod, surf, x - cosaf * org_x - cosar * org_y, y - sinaf * org_x - sinar * org_y, 0, 0, 0, -1, 0, 0, 0, 0, red, green, blue, alpha);
-       e1 = Mod_Mesh_IndexForVertex(mod, surf, x + cosaf * (width - org_x) - cosar * org_y, y + sinaf * (width - org_x) - sinar * org_y, 0, 0, 0, -1, 1, 0, 0, 0, red, green, blue, alpha);
-       e2 = Mod_Mesh_IndexForVertex(mod, surf, x + cosaf * (width - org_x) + cosar * (height - org_y), sinaf*(width - org_x) + sinar * (height - org_y), 0, 0, 0, -1, 1, 1, 0, 0, red, green, blue, alpha);
-       e3 = Mod_Mesh_IndexForVertex(mod, surf, x - cosaf * org_x + cosar * (height - org_y), y - sinaf * org_x + sinar * (height - org_y), 0, 0, 0, -1, 0, 1, 0, 0, red, green, blue, alpha);
+       surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, pic->name, flags, pic->texflags, MATERIALFLAG_WALL | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX), true);
+       e0 = Mod_Mesh_IndexForVertex(mod, surf, x - cosaf *          org_x  - cosar *           org_y , y - sinaf *          org_x  - sinar *           org_y , 0, 0, 0, -1, 0, 0, 0, 0, red, green, blue, alpha);
+       e1 = Mod_Mesh_IndexForVertex(mod, surf, x + cosaf * (width - org_x) - cosar *           org_y , y + sinaf * (width - org_x) - sinar *           org_y , 0, 0, 0, -1, 1, 0, 0, 0, red, green, blue, alpha);
+       e2 = Mod_Mesh_IndexForVertex(mod, surf, x + cosaf * (width - org_x) + cosar * (height - org_y), y + sinaf * (width - org_x) + sinar * (height - org_y), 0, 0, 0, -1, 1, 1, 0, 0, red, green, blue, alpha);
+       e3 = Mod_Mesh_IndexForVertex(mod, surf, x - cosaf *          org_x  + cosar * (height - org_y), y - sinaf *          org_x  + sinar * (height - org_y), 0, 0, 0, -1, 0, 1, 0, 0, red, green, blue, alpha);
        Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
        Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
 }
@@ -807,8 +840,8 @@ void DrawQ_Fill(float x, float y, float width, float height, float red, float gr
 static const vec4_t string_colors[] =
 {
        // Quake3 colors
-       // LordHavoc: why on earth is cyan before magenta in Quake3?
-       // LordHavoc: note: Doom3 uses white for [0] and [7]
+       // LadyHavoc: why on earth is cyan before magenta in Quake3?
+       // LadyHavoc: note: Doom3 uses white for [0] and [7]
        {0.0, 0.0, 0.0, 1.0}, // black
        {1.0, 0.0, 0.0, 1.0}, // red
        {0.0, 1.0, 0.0, 1.0}, // green
@@ -1240,7 +1273,7 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
                                        u = 0.0625f * thisw - (1.0f / tw);
                                        v = 0.0625f - (1.0f / th);
                                }
-                               surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, fnt->pic->name, flags, TEXF_ALPHA | TEXF_CLAMP, MATERIALFLAG_VERTEXCOLOR), true);
+                               surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, fnt->pic->name, flags, TEXF_ALPHA | TEXF_CLAMP, MATERIALFLAG_WALL | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX), true);
                                e0 = Mod_Mesh_IndexForVertex(mod, surf, x         , y   , 10, 0, 0, -1, s  , t  , 0, 0, DrawQ_Color[0], DrawQ_Color[1], DrawQ_Color[2], DrawQ_Color[3]);
                                e1 = Mod_Mesh_IndexForVertex(mod, surf, x+dw*thisw, y   , 10, 0, 0, -1, s+u, t  , 0, 0, DrawQ_Color[0], DrawQ_Color[1], DrawQ_Color[2], DrawQ_Color[3]);
                                e2 = Mod_Mesh_IndexForVertex(mod, surf, x+dw*thisw, y+dh, 10, 0, 0, -1, s+u, t+v, 0, 0, DrawQ_Color[0], DrawQ_Color[1], DrawQ_Color[2], DrawQ_Color[3]);
@@ -1281,7 +1314,7 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
                                }
                                else
                                        kx = ky = 0;
-                               surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, map->pic->name, flags, TEXF_ALPHA | TEXF_CLAMP, MATERIALFLAG_VERTEXCOLOR), true);
+                               surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, map->pic->name, flags, TEXF_ALPHA | TEXF_CLAMP, MATERIALFLAG_WALL | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX), true);
                                e0 = Mod_Mesh_IndexForVertex(mod, surf, x + dw * map->glyphs[mapch].vxmin, y + dh * map->glyphs[mapch].vymin, 10, 0, 0, -1, map->glyphs[mapch].txmin, map->glyphs[mapch].tymin, 0, 0, DrawQ_Color[0], DrawQ_Color[1], DrawQ_Color[2], DrawQ_Color[3]);
                                e1 = Mod_Mesh_IndexForVertex(mod, surf, x + dw * map->glyphs[mapch].vxmax, y + dh * map->glyphs[mapch].vymin, 10, 0, 0, -1, map->glyphs[mapch].txmax, map->glyphs[mapch].tymin, 0, 0, DrawQ_Color[0], DrawQ_Color[1], DrawQ_Color[2], DrawQ_Color[3]);
                                e2 = Mod_Mesh_IndexForVertex(mod, surf, x + dw * map->glyphs[mapch].vxmax, y + dh * map->glyphs[mapch].vymax, 10, 0, 0, -1, map->glyphs[mapch].txmax, map->glyphs[mapch].tymax, 0, 0, DrawQ_Color[0], DrawQ_Color[1], DrawQ_Color[2], DrawQ_Color[3]);
@@ -1379,11 +1412,13 @@ void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height
        int e0, e1, e2, e3;
        if (!pic)
                pic = Draw_CachePic("white");
+       // make sure pic is loaded - we don't use the texture here, Mod_Mesh_GetTexture looks up the skinframe by name
+       Draw_GetPicTexture(pic);
        if (width == 0)
                width = pic->width;
        if (height == 0)
                height = pic->height;
-       surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, pic->name, flags, pic->texflags, MATERIALFLAG_VERTEXCOLOR), true);
+       surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, pic->name, flags, pic->texflags, MATERIALFLAG_WALL | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX), true);
        e0 = Mod_Mesh_IndexForVertex(mod, surf, x        , y         , 0, 0, 0, -1, s1, t1, 0, 0, r1, g1, b1, a1);
        e1 = Mod_Mesh_IndexForVertex(mod, surf, x + width, y         , 0, 0, 0, -1, s2, t2, 0, 0, r2, g2, b2, a2);
        e2 = Mod_Mesh_IndexForVertex(mod, surf, x + width, y + height, 0, 0, 0, -1, s4, t4, 0, 0, r4, g4, b4, a4);
@@ -1409,7 +1444,7 @@ void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, f
                offsetx = 0.5f * width * vid_conwidth.value / vid.width;
                offsety = 0;
        }
-       surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_VERTEXCOLOR), true);
+       surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_WALL | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX), true);
        e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r, g, b, alpha);
        e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r, g, b, alpha);
        e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r, g, b, alpha);
@@ -1431,23 +1466,10 @@ void DrawQ_SetClipArea(float x, float y, float width, float height)
        ih = (int)(0.5 + height * ((float)r_refdef.view.height / vid_conheight.integer));
        switch(vid.renderpath)
        {
-       case RENDERPATH_GL11:
-       case RENDERPATH_GL13:
-       case RENDERPATH_GL20:
-       case RENDERPATH_GLES1:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
-       case RENDERPATH_SOFT:
                GL_Scissor(ix, vid.height - iy - ih, iw, ih);
                break;
-       case RENDERPATH_D3D9:
-               GL_Scissor(ix, iy, iw, ih);
-               break;
-       case RENDERPATH_D3D10:
-               Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-               break;
-       case RENDERPATH_D3D11:
-               Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
-               break;
        }
 
        GL_ScissorTest(true);
@@ -1474,7 +1496,6 @@ void DrawQ_RecalcView(void)
 
 void DrawQ_FlushUI(void)
 {
-       int i;
        dp_model_t *mod = CL_Mesh_UI();
        if (mod->num_surfaces == 0)
                return;
@@ -1485,24 +1506,13 @@ void DrawQ_FlushUI(void)
                return;
        }
 
-       // TODO: render the mesh using R_Q1BSP_Draw or similar, for full material support.
+       // this is roughly equivalent to R_Q1BSP_Draw, so the UI can use full material feature set
+       r_refdef.view.colorscale = 1;
+       r_textureframe++; // used only by R_GetCurrentTexture
        GL_DepthMask(false);
-       R_Mesh_PrepareVertices_Generic_Arrays(mod->surfmesh.num_vertices, mod->surfmesh.data_vertex3f, mod->surfmesh.data_lightmapcolor4f, mod->surfmesh.data_texcoordtexture2f);
-       for (i = 0; i < mod->num_surfaces; i++)
-       {
-               msurface_t *surf = mod->data_surfaces + i;
-               texture_t *tex = surf->texture;
-               if (tex->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
-                       GL_BlendFunc(tex->customblendfunc[0], tex->customblendfunc[1]);
-               else if (tex->currentmaterialflags & MATERIALFLAG_ADD)
-                       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
-               else if (tex->currentmaterialflags & MATERIALFLAG_ALPHA)
-                       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-               else
-                       GL_BlendFunc(GL_ONE, GL_ZERO);
-               R_SetupShader_Generic(tex->currentskinframe->base, NULL, GL_MODULATE, 1, (tex->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND) ? false : true, true, false);
-               R_Mesh_Draw(surf->num_firstvertex, surf->num_vertices, surf->num_firsttriangle, surf->num_triangles, mod->surfmesh.data_element3i, NULL, 0, mod->surfmesh.data_element3s, NULL, 0);
-       }
+
+       Mod_Mesh_Finalize(mod);
+       R_DrawModelSurfaces(&cl_meshentities[MESH_UI].render, false, false, false, false, false, true);
 
        Mod_Mesh_Reset(mod);
 }