]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_draw.c
Rename host_t -> host_static_t.
[xonotic/darkplaces.git] / gl_draw.c
index 0b15ad291e024bcb3b80383a31f5cddc294beb14..b4978abb1e4715a803a8eaae17b452c569705e4a 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 = {CF_CLIENT | CF_ARCHIVE, "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 = {CF_CLIENT | CF_ARCHIVE, "r_textbrightness", "0", "additional brightness for text color codes (0 keeps colors as is, 1 makes them all white)"};
+cvar_t r_textcontrast = {CF_CLIENT | CF_ARCHIVE, "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 = {CF_CLIENT | CF_ARCHIVE, "r_font_postprocess_blur", "0", "font blur amount"};
+cvar_t r_font_postprocess_outline = {CF_CLIENT | CF_ARCHIVE, "r_font_postprocess_outline", "0", "font outline amount"};
+cvar_t r_font_postprocess_shadow_x = {CF_CLIENT | CF_ARCHIVE, "r_font_postprocess_shadow_x", "0", "font shadow X shift amount, applied during outlining"};
+cvar_t r_font_postprocess_shadow_y = {CF_CLIENT | CF_ARCHIVE, "r_font_postprocess_shadow_y", "0", "font shadow Y shift amount, applied during outlining"};
+cvar_t r_font_postprocess_shadow_z = {CF_CLIENT | CF_ARCHIVE, "r_font_postprocess_shadow_z", "0", "font shadow Z shift amount, applied during blurring"};
+cvar_t r_font_hinting = {CF_CLIENT | CF_ARCHIVE, "r_font_hinting", "3", "0 = no hinting, 1 = light autohinting, 2 = full autohinting, 3 = full hinting"};
+cvar_t r_font_antialias = {CF_CLIENT | CF_ARCHIVE, "r_font_antialias", "1", "0 = monochrome, 1 = grey" /* , 2 = rgb, 3 = bgr" */};
+cvar_t r_nearest_2d = {CF_CLIENT | CF_ARCHIVE, "r_nearest_2d", "0", "use nearest filtering on all 2d textures (including conchars)"};
+cvar_t r_nearest_conchars = {CF_CLIENT | CF_ARCHIVE, "r_nearest_conchars", "0", "use nearest filtering on conchars texture"};
 
 //=============================================================================
 /* Support Routines */
@@ -94,7 +94,9 @@ cachepic_t *Draw_CachePic_Flags(const char *path, unsigned int cachepicflags)
                texflags |= TEXF_MIPMAP;
        if (!(cachepicflags & CACHEPICFLAG_NOCOMPRESSION) && gl_texturecompression_2d.integer && gl_texturecompression.integer)
                texflags |= TEXF_COMPRESS;
-       if ((cachepicflags & CACHEPICFLAG_NEAREST) || r_nearest_2d.integer)
+       if (cachepicflags & CACHEPICFLAG_LINEAR)
+               texflags |= TEXF_FORCELINEAR;
+       else if ((cachepicflags & CACHEPICFLAG_NEAREST) || r_nearest_2d.integer)
                texflags |= TEXF_FORCENEAREST;
 
        // check whether the picture has already been cached
@@ -105,32 +107,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 +156,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 | TEXF_FORCE_RELOAD, (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)
@@ -189,12 +206,15 @@ int Draw_GetPicHeight(cachepic_t *pic)
        return pic->height;
 }
 
-qboolean Draw_IsPicLoaded(cachepic_t *pic)
+qbool Draw_IsPicLoaded(cachepic_t *pic)
 {
        if (pic == NULL)
                return false;
        if (pic->autoload && (!pic->skinframe || !pic->skinframe->base))
+       {
+               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 +224,10 @@ rtexture_t *Draw_GetPicTexture(cachepic_t *pic)
        if (pic == NULL)
                return NULL;
        if (pic->autoload && (!pic->skinframe || !pic->skinframe->base))
+       {
+               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;
 }
@@ -214,12 +237,17 @@ void Draw_Frame(void)
        int i;
        cachepic_t *pic;
        static double nextpurgetime;
-       if (nextpurgetime > realtime)
+       if (nextpurgetime > host.realtime)
                return;
-       nextpurgetime = realtime + 0.05;
+       nextpurgetime = host.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 +266,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)
                {
-                       R_UpdateTexture(pic->skinframe->base, pixels_bgra, 0, 0, 0, width, height, 1);
+                       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, 0);
                        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 +293,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 | TEXF_FORCE_RELOAD, 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 +316,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;
                }
        }
@@ -294,7 +325,7 @@ void Draw_FreePic(const char *picname)
 
 static float snap_to_pixel_x(float x, float roundUpAt);
 extern int con_linewidth; // to force rewrapping
-void LoadFont(qboolean override, const char *name, dp_font_t *fnt, float scale, float voffset)
+void LoadFont(qbool override, const char *name, dp_font_t *fnt, float scale, float voffset)
 {
        int i, ch;
        float maxwidth;
@@ -408,7 +439,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;
                                        }
@@ -444,7 +475,7 @@ void LoadFont(qboolean override, const char *name, dp_font_t *fnt, float scale,
 }
 
 extern cvar_t developer_font;
-dp_font_t *FindFont(const char *title, qboolean allocate_new)
+dp_font_t *FindFont(const char *title, qbool allocate_new)
 {
        int i, oldsize;
 
@@ -507,7 +538,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 +546,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 +566,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 +635,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 +659,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
@@ -641,7 +672,7 @@ static void LoadFont_f(void)
 
                                if (sizes == MAX_FONT_SIZES)
                                {
-                                       Con_Printf("Warning: specified more than %i different font sizes, exceding ones are ignored\n", MAX_FONT_SIZES);
+                                       Con_Printf(CON_WARN "Warning: specified more than %i different font sizes, exceding ones are ignored\n", MAX_FONT_SIZES);
                                        sizes = -1;
                                        continue;
                                }
@@ -674,9 +705,6 @@ static void gl_draw_start(void)
        for(i = 0; i < dp_fonts.maxsize; ++i)
                if (dp_fonts.f[i].title[0])
                        LoadFont(false, va(vabuf, sizeof(vabuf), "gfx/font_%s", dp_fonts.f[i].title), &dp_fonts.f[i], 1, 0);
-
-       // draw the loading screen so people have something to see in the newly opened window
-       SCR_UpdateLoadingScreen(true, true);
 }
 
 static void gl_draw_shutdown(void)
@@ -740,7 +768,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(CF_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);
 }
 
@@ -750,20 +778,22 @@ void DrawQ_Start(void)
        R_ResetViewRendering2D_Common(0, NULL, NULL, 0, 0, vid.width, vid.height, vid_conwidth.integer, vid_conheight.integer);
 }
 
-qboolean r_draw2d_force = false;
+qbool r_draw2d_force = false;
 
 void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags)
 {
-       dp_model_t *mod = CL_Mesh_UI();
+       model_t *mod = CL_Mesh_UI();
        msurface_t *surf;
        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 | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW), 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);
@@ -780,20 +810,22 @@ void DrawQ_RotPic(float x, float y, cachepic_t *pic, float width, float height,
        float cosaf = cos(af);
        float sinar = sin(ar);
        float cosar = cos(ar);
-       dp_model_t *mod = CL_Mesh_UI();
+       model_t *mod = CL_Mesh_UI();
        msurface_t *surf;
        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 | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW), 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 +839,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
@@ -833,7 +865,7 @@ static const vec4_t string_colors[] =
 
 #define STRING_COLORS_COUNT    (sizeof(string_colors) / sizeof(vec4_t))
 
-static void DrawQ_GetTextColor(float color[4], int colorindex, float r, float g, float b, float a, qboolean shadow)
+static void DrawQ_GetTextColor(float color[4], int colorindex, float r, float g, float b, float a, qbool shadow)
 {
        float C = r_textcontrast.value;
        float B = r_textbrightness.value;
@@ -854,16 +886,38 @@ static void DrawQ_GetTextColor(float color[4], int colorindex, float r, float g,
        }
 }
 
+// returns a colorindex (format 0x1RGBA) if str is a valid RGB string
+// returns 0 otherwise
+static int RGBstring_to_colorindex(const char *str)
+{
+       Uchar ch; 
+       int ind = 0x0001 << 4;
+       do {
+               if (*str <= '9' && *str >= '0')
+                       ind |= (*str - '0');
+               else
+               {
+                       ch = tolower(*str);
+                       if (ch >= 'a' && ch <= 'f')
+                               ind |= (ch - 87);
+                       else
+                               return 0;
+               }
+               ++str;
+               ind <<= 4;
+       } while(!(ind & 0x10000));
+       return ind | 0xf; // add costant alpha value
+}
+
 // NOTE: this function always draws exactly one character if maxwidth <= 0
-float DrawQ_TextWidth_UntilWidth_TrackColors_Scale(const char *text, size_t *maxlen, float w, float h, float sw, float sh, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxwidth)
+float DrawQ_TextWidth_UntilWidth_TrackColors_Scale(const char *text, size_t *maxlen, float w, float h, float sw, float sh, int *outcolor, qbool ignorecolorcodes, const dp_font_t *fnt, float maxwidth)
 {
        const char *text_start = text;
-       int colorindex = STRING_COLOR_DEFAULT;
+       int colorindex;
        size_t i;
        float x = 0;
        Uchar ch, mapch, nextch;
        Uchar prevch = 0; // used for kerning
-       int tempcolorindex;
        float kx;
        int map_index = 0;
        size_t bytes_left;
@@ -872,8 +926,8 @@ float DrawQ_TextWidth_UntilWidth_TrackColors_Scale(const char *text, size_t *max
        //ft2_font_map_t *prevmap = NULL;
        ft2_font_t *ft2 = fnt->ft2;
        // float ftbase_x;
-       qboolean snap = true;
-       qboolean least_one = false;
+       qbool snap = true;
+       qbool least_one = false;
        float dw; // display w
        //float dh; // display h
        const float *width_of;
@@ -910,7 +964,7 @@ float DrawQ_TextWidth_UntilWidth_TrackColors_Scale(const char *text, size_t *max
 
        // maxwidth /= fnt->scale; // w and h are multiplied by it already
        // ftbase_x = snap_to_pixel_x(0);
-       
+
        if(maxwidth <= 0)
        {
                least_one = true;
@@ -944,7 +998,6 @@ float DrawQ_TextWidth_UntilWidth_TrackColors_Scale(const char *text, size_t *max
                        x += width_of[(int) ' '] * dw;
                        continue;
                }
-               // i points to the char after ^
                if (ch == STRING_COLOR_TAG && !ignorecolorcodes && i < *maxlen)
                {
                        ch = *text; // colors are ascii, so no u8_ needed
@@ -955,41 +1008,19 @@ float DrawQ_TextWidth_UntilWidth_TrackColors_Scale(const char *text, size_t *max
                                ++i;
                                continue;
                        }
-                       // i points to the char after ^...
-                       // i+3 points to 3 in ^x123
-                       // i+3 == *maxlen would mean that char is missing
                        else if (ch == STRING_COLOR_RGB_TAG_CHAR && i + 3 < *maxlen ) // ^x found
                        {
-                               // building colorindex...
-                               ch = tolower(text[1]);
-                               tempcolorindex = 0x10000; // binary: 1,0000,0000,0000,0000
-                               if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 12;
-                               else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 12;
-                               else tempcolorindex = 0;
+                               const char *text_p = &text[1];
+                               int tempcolorindex = RGBstring_to_colorindex(text_p);
                                if (tempcolorindex)
                                {
-                                       ch = tolower(text[2]);
-                                       if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 8;
-                                       else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 8;
-                                       else tempcolorindex = 0;
-                                       if (tempcolorindex)
-                                       {
-                                               ch = tolower(text[3]);
-                                               if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 4;
-                                               else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 4;
-                                               else tempcolorindex = 0;
-                                               if (tempcolorindex)
-                                               {
-                                                       colorindex = tempcolorindex | 0xf;
-                                                       // ...done! now colorindex has rgba codes (1,rrrr,gggg,bbbb,aaaa)
-                                                       i+=4;
-                                                       text += 4;
-                                                       continue;
-                                               }
-                                       }
+                                       colorindex = tempcolorindex;
+                                       i+=4;
+                                       text += 4;
+                                       continue;
                                }
                        }
-                       else if (ch == STRING_COLOR_TAG) // ^^ found, ignore the first ^ and go to print the second
+                       else if (ch == STRING_COLOR_TAG) // ^^ found
                        {
                                i++;
                                text++;
@@ -1044,14 +1075,13 @@ float DrawQ_TextWidth_UntilWidth_TrackColors_Scale(const char *text, size_t *max
 }
 
 float DrawQ_Color[4];
-float DrawQ_String_Scale(float startx, float starty, const char *text, size_t maxlen, float w, float h, float sw, float sh, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt)
+float DrawQ_String_Scale(float startx, float starty, const char *text, size_t maxlen, float w, float h, float sw, float sh, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qbool ignorecolorcodes, const dp_font_t *fnt)
 {
        int shadow, colorindex = STRING_COLOR_DEFAULT;
        size_t i;
        float x = startx, y, s, t, u, v, thisw;
        Uchar ch, mapch, nextch;
        Uchar prevch = 0; // used for kerning
-       int tempcolorindex;
        int map_index = 0;
        //ft2_font_map_t *prevmap = NULL; // the previous map
        ft2_font_map_t *map = NULL;     // the currently used map
@@ -1060,12 +1090,12 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
        const char *text_start = text;
        float kx, ky;
        ft2_font_t *ft2 = fnt->ft2;
-       qboolean snap = true;
+       qbool snap = true;
        float pix_x, pix_y;
        size_t bytes_left;
        float dw, dh;
        const float *width_of;
-       dp_model_t *mod = CL_Mesh_UI();
+       model_t *mod = CL_Mesh_UI();
        msurface_t *surf = NULL;
        int e0, e1, e2, e3;
        int tw, th;
@@ -1165,35 +1195,15 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma
                                }
                                else if (ch == STRING_COLOR_RGB_TAG_CHAR && i+3 < maxlen ) // ^x found
                                {
-                                       // building colorindex...
-                                       ch = tolower(text[1]);
-                                       tempcolorindex = 0x10000; // binary: 1,0000,0000,0000,0000
-                                       if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 12;
-                                       else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 12;
-                                       else tempcolorindex = 0;
-                                       if (tempcolorindex)
+                                       const char *text_p = &text[1];
+                                       int tempcolorindex = RGBstring_to_colorindex(text_p);
+                                       if(tempcolorindex)
                                        {
-                                               ch = tolower(text[2]);
-                                               if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 8;
-                                               else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 8;
-                                               else tempcolorindex = 0;
-                                               if (tempcolorindex)
-                                               {
-                                                       ch = tolower(text[3]);
-                                                       if (ch <= '9' && ch >= '0') tempcolorindex |= (ch - '0') << 4;
-                                                       else if (ch >= 'a' && ch <= 'f') tempcolorindex |= (ch - 87) << 4;
-                                                       else tempcolorindex = 0;
-                                                       if (tempcolorindex)
-                                                       {
-                                                               colorindex = tempcolorindex | 0xf;
-                                                               // ...done! now colorindex has rgba codes (1,rrrr,gggg,bbbb,aaaa)
-                                                               //Con_Printf("^1colorindex:^7 %x\n", colorindex);
-                                                               DrawQ_GetTextColor(DrawQ_Color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
-                                                               i+=4;
-                                                               text+=4;
-                                                               continue;
-                                                       }
-                                               }
+                                               colorindex = tempcolorindex;
+                                               DrawQ_GetTextColor(DrawQ_Color, colorindex, basered, basegreen, baseblue, basealpha, shadow != 0);
+                                               i+=4;
+                                               text+=4;
+                                               continue;
                                        }
                                }
                                else if (ch == STRING_COLOR_TAG)
@@ -1240,7 +1250,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 | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW), 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 +1291,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 | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW), 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]);
@@ -1307,27 +1317,27 @@ out:
 
        if (outcolor)
                *outcolor = colorindex;
-       
+
        // note: this relies on the proper text (not shadow) being drawn last
        return x;
 }
 
-float DrawQ_String(float startx, float starty, const char *text, size_t maxlen, float w, float h, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt)
+float DrawQ_String(float startx, float starty, const char *text, size_t maxlen, float w, float h, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qbool ignorecolorcodes, const dp_font_t *fnt)
 {
        return DrawQ_String_Scale(startx, starty, text, maxlen, w, h, 1, 1, basered, basegreen, baseblue, basealpha, flags, outcolor, ignorecolorcodes, fnt);
 }
 
-float DrawQ_TextWidth_UntilWidth_TrackColors(const char *text, size_t *maxlen, float w, float h, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxwidth)
+float DrawQ_TextWidth_UntilWidth_TrackColors(const char *text, size_t *maxlen, float w, float h, int *outcolor, qbool ignorecolorcodes, const dp_font_t *fnt, float maxwidth)
 {
        return DrawQ_TextWidth_UntilWidth_TrackColors_Scale(text, maxlen, w, h, 1, 1, outcolor, ignorecolorcodes, fnt, maxwidth);
 }
 
-float DrawQ_TextWidth(const char *text, size_t maxlen, float w, float h, qboolean ignorecolorcodes, const dp_font_t *fnt)
+float DrawQ_TextWidth(const char *text, size_t maxlen, float w, float h, qbool ignorecolorcodes, const dp_font_t *fnt)
 {
        return DrawQ_TextWidth_UntilWidth(text, &maxlen, w, h, ignorecolorcodes, fnt, 1000000000);
 }
 
-float DrawQ_TextWidth_UntilWidth(const char *text, size_t *maxlen, float w, float h, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxWidth)
+float DrawQ_TextWidth_UntilWidth(const char *text, size_t *maxlen, float w, float h, qbool ignorecolorcodes, const dp_font_t *fnt, float maxWidth)
 {
        return DrawQ_TextWidth_UntilWidth_TrackColors(text, maxlen, w, h, NULL, ignorecolorcodes, fnt, maxWidth);
 }
@@ -1335,7 +1345,7 @@ float DrawQ_TextWidth_UntilWidth(const char *text, size_t *maxlen, float w, floa
 #if 0
 // not used
 // no ^xrgb management
-static int DrawQ_BuildColoredText(char *output2c, size_t maxoutchars, const char *text, int maxreadchars, qboolean ignorecolorcodes, int *outcolor)
+static int DrawQ_BuildColoredText(char *output2c, size_t maxoutchars, const char *text, int maxreadchars, qbool ignorecolorcodes, int *outcolor)
 {
        int color, numchars = 0;
        char *outputend2c = output2c + maxoutchars - 2;
@@ -1374,16 +1384,18 @@ static int DrawQ_BuildColoredText(char *output2c, size_t maxoutchars, const char
 
 void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height, float s1, float t1, float r1, float g1, float b1, float a1, float s2, float t2, float r2, float g2, float b2, float a2, float s3, float t3, float r3, float g3, float b3, float a3, float s4, float t4, float r4, float g4, float b4, float a4, int flags)
 {
-       dp_model_t *mod = CL_Mesh_UI();
+       model_t *mod = CL_Mesh_UI();
        msurface_t *surf;
        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 | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW), 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);
@@ -1394,7 +1406,7 @@ void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height
 
 void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, float g, float b, float alpha, int flags)
 {
-       dp_model_t *mod = CL_Mesh_UI();
+       model_t *mod = CL_Mesh_UI();
        msurface_t *surf;
        int e0, e1, e2, e3;
        float offsetx, offsety;
@@ -1409,7 +1421,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 | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW), 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,7 +1443,7 @@ 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_GL20:
+       case RENDERPATH_GL32:
        case RENDERPATH_GLES2:
                GL_Scissor(ix, vid.height - iy - ih, iw, ih);
                break;
@@ -1461,8 +1473,7 @@ void DrawQ_RecalcView(void)
 
 void DrawQ_FlushUI(void)
 {
-       int i;
-       dp_model_t *mod = CL_Mesh_UI();
+       model_t *mod = CL_Mesh_UI();
        if (mod->num_surfaces == 0)
                return;
 
@@ -1472,24 +1483,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_Mod_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);
 }