]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_decals.c
rewrote memory system entirely (hunk, cache, and zone are gone, memory pools replaced...
[xonotic/darkplaces.git] / r_decals.c
index 6c45f70e5a89893918291c772312f9a70f898381..84b9d842e094822832ffcd58593324c6ffa9db95 100644 (file)
@@ -20,377 +20,175 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 
-#define MAX_DECALS 2048
-
-typedef struct decal_s
-{
-       vec3_t          org;
-       vec3_t          direction;
-       vec2_t          texcoord[4];
-       vec3_t          vert[4];
-       byte            color[4];
-       rtexture_t      *tex;
-       msurface_t      *surface;
-       byte            *lightmapaddress;
-       int                     lightmapstep;
-}
-decal_t;
-
-decal_t *decals;
-int currentdecal; // wraps around in decal array, replacing old ones when a new one is needed
-
 cvar_t r_drawdecals = {0, "r_drawdecals", "1"};
-cvar_t r_decals_lighting = {0, "r_decals_lighting", "1"};
 
-void r_decals_start(void)
+static void r_decals_start(void)
 {
-       decals = (decal_t *) qmalloc(MAX_DECALS * sizeof(decal_t));
-       memset(decals, 0, MAX_DECALS * sizeof(decal_t));
-       currentdecal = 0;
 }
 
-void r_decals_shutdown(void)
+static void r_decals_shutdown(void)
 {
-       qfree(decals);
 }
 
-void r_decals_newmap(void)
+static void r_decals_newmap(void)
 {
-       memset(decals, 0, MAX_DECALS * sizeof(decal_t));
-       currentdecal = 0;
 }
 
 void R_Decals_Init(void)
 {
        Cvar_RegisterVariable (&r_drawdecals);
-       Cvar_RegisterVariable (&r_decals_lighting);
 
        R_RegisterModule("R_Decals", r_decals_start, r_decals_shutdown, r_decals_newmap);
 }
 
-// these are static globals only to avoid putting unnecessary things on the stack
-static vec3_t decalorg;
-static float decalbestdist;
-static msurface_t *decalbestsurf;
-static int decalbestlightmapofs;
-void R_RecursiveDecalSurface (mnode_t *node)
+static int decalindexarray[2*3] =
 {
-       // these are static because only one occurance of them need exist at once, so avoid putting them on the stack
-       static float ndist, dist;
-       static msurface_t *surf, *endsurf;
-       static vec3_t impact;
-       static int ds, dt;
-
-loc0:
-       if (node->contents < 0)
-               return;
-
-       ndist = PlaneDiff(decalorg, node->plane);
-
-       if (ndist > 16)
-       {
-               node = node->children[0];
-               goto loc0;
-       }
-       if (ndist < -16)
-       {
-               node = node->children[1];
-               goto loc0;
-       }
+       0, 1, 2,
+       0, 2, 3,
+};
 
-// mark the polygons
-       surf = cl.worldmodel->surfaces + node->firstsurface;
-       endsurf = surf + node->numsurfaces;
-       for (;surf < endsurf;surf++)
-       {
-               if (surf->flags & SURF_DRAWTILED)
-                       continue;       // no lightmaps
-
-               dist = PlaneDiff(decalorg, surf->plane);
-               if (surf->flags & SURF_PLANEBACK)
-                       dist = -dist;
-               if (dist < 0)
-                       continue;
-               if (dist >= decalbestdist)
-                       continue;
+void R_DrawDecals (void)
+{
+       renderdecal_t *r;
+       int i, j, lightmapstep, ds, dt;
+       float fscale, fr, fg, fb, dist, f, ifog, impact[3], v[3], org[3], dir[3], right[3], up[3], tvertex[4][5];
+       particletexture_t *tex;
+       byte *lightmap;
+       msurface_t *surf;
+       rdlight_t *rd;
+       rmeshinfo_t m;
 
-               impact[0] = decalorg[0] - surf->plane->normal[0] * dist;
-               impact[1] = decalorg[1] - surf->plane->normal[1] * dist;
-               impact[2] = decalorg[2] - surf->plane->normal[2] * dist;
+       if (!r_drawdecals.integer)
+               return;
 
-               ds = (int) (DotProduct(impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
-               dt = (int) (DotProduct(impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
+       ifog = 1;
 
-               if (ds < surf->texturemins[0] || dt < surf->texturemins[1])
-                       continue;
-               
-               ds -= surf->texturemins[0];
-               dt -= surf->texturemins[1];
-               
-               if (ds > surf->extents[0] || dt > surf->extents[1])
-                       continue;
+       Mod_CheckLoaded(cl.worldmodel);
 
-               decalbestsurf = surf;
-               decalbestdist = dist;
-               decalbestlightmapofs = (dt >> 4) * ((surf->extents[0] >> 4) + 1) + (ds >> 4);
-       }
+       memset(&m, 0, sizeof(m));
+       m.blendfunc1 = GL_SRC_ALPHA;
+       m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+       m.numtriangles = 2;
+       m.numverts = 4;
+       m.index = decalindexarray;
+       m.vertex = &tvertex[0][0];
+       m.vertexstep = sizeof(float[5]);
+       m.tex[0] = R_GetTexture(particlefonttexture);
+       m.texcoords[0] = &tvertex[0][3];
+       m.texcoordstep[0] = sizeof(float[5]);
 
-       if (node->children[0]->contents >= 0)
+       for (i = 0, r = r_refdef.decals;i < r_refdef.numdecals;i++, r++)
        {
-               if (node->children[1]->contents >= 0)
-               {
-                       R_RecursiveDecalSurface (node->children[0]);
-                       node = node->children[1];
-                       goto loc0;
-               }
-               else
+               if (r->ent)
                {
-                       node = node->children[0];
-                       goto loc0;
-               }
-       }
-       else if (node->children[1]->contents >= 0)
-       {
-               node = node->children[1];
-               goto loc0;
-       }
-}
-
-void R_Decal(vec3_t org, rtexture_t *tex, float s1, float t1, float s2, float t2, float scale, int cred, int cgreen, int cblue, int alpha)
-{
-       vec3_t center, right, up;
-       decal_t *decal;
-
-       if (alpha < 1)
-               return;
-
-       // find the best surface to place the decal on
-       decalbestsurf = NULL;
-       decalbestdist = 16;
-       decalbestlightmapofs = 0;
-       VectorCopy(org, decalorg);
+                       if (r->ent->visframe != r_framecount)
+                               continue;
 
-       R_RecursiveDecalSurface (cl.worldmodel->nodes);
+                       Mod_CheckLoaded(r->ent->model);
 
-       // abort if no suitable surface was found
-       if (decalbestsurf == NULL)
-               return;
-
-       // grab a decal from the array and advance to the next decal to replace, wrapping to replace an old decal if necessary
-       decal = decals + currentdecal;
-       currentdecal++;
-       if (currentdecal >= MAX_DECALS)
-               currentdecal = 0;
-       decal->tex = tex;
-       VectorCopy(decalbestsurf->plane->normal, decal->direction);
-       // reverse direction
-       if (decalbestsurf->flags & SURF_PLANEBACK)
-               VectorNegate(decal->direction, decal->direction);
-       VectorNegate(decal->direction, decal->direction);
-       // 0.25 to push it off the surface a bit
-       decalbestdist -= 0.25f;
-       decal->org[0] = center[0] = org[0] + decal->direction[0] * decalbestdist;
-       decal->org[1] = center[1] = org[1] + decal->direction[1] * decalbestdist;
-       decal->org[2] = center[2] = org[2] + decal->direction[2] * decalbestdist;
-       // set up the 4 corners
-       scale *= 0.5f;
-       VectorVectors(decal->direction, right, up);
-       decal->texcoord[0][0] = s1;
-       decal->texcoord[0][1] = t1;
-       decal->vert[0][0] = center[0] - right[0] * scale - up[0] * scale;
-       decal->vert[0][1] = center[1] - right[1] * scale - up[1] * scale;
-       decal->vert[0][2] = center[2] - right[2] * scale - up[2] * scale;
-       decal->texcoord[1][0] = s1;
-       decal->texcoord[1][1] = t2;
-       decal->vert[1][0] = center[0] - right[0] * scale + up[0] * scale;
-       decal->vert[1][1] = center[1] - right[1] * scale + up[1] * scale;
-       decal->vert[1][2] = center[2] - right[2] * scale + up[2] * scale;
-       decal->texcoord[2][0] = s2;
-       decal->texcoord[2][1] = t2;
-       decal->vert[2][0] = center[0] + right[0] * scale + up[0] * scale;
-       decal->vert[2][1] = center[1] + right[1] * scale + up[1] * scale;
-       decal->vert[2][2] = center[2] + right[2] * scale + up[2] * scale;
-       decal->texcoord[3][0] = s2;
-       decal->texcoord[3][1] = t1;
-       decal->vert[3][0] = center[0] + right[0] * scale - up[0] * scale;
-       decal->vert[3][1] = center[1] + right[1] * scale - up[1] * scale;
-       decal->vert[3][2] = center[2] + right[2] * scale - up[2] * scale;
-       // store the color
-       decal->color[0] = (byte) bound(0, cred, 255);
-       decal->color[1] = (byte) bound(0, cgreen, 255);
-       decal->color[2] = (byte) bound(0, cblue, 255);
-       decal->color[3] = (byte) bound(0, alpha, 255);
-       // store the surface information for lighting
-       decal->surface = decalbestsurf;
-       decal->lightmapstep = ((decalbestsurf->extents[0]>>4)+1) * ((decalbestsurf->extents[1]>>4)+1)*3; // LordHavoc: *3 for colored lighting
-       if (decalbestsurf->samples)
-               decal->lightmapaddress = decalbestsurf->samples + decalbestlightmapofs * 3; // LordHavoc: *3 for colored lighitng
-       else
-               decal->lightmapaddress = NULL;
-}
+                       surf = r->ent->model->surfaces + r->surface;
 
-void GL_DrawDecals (void)
-{
-       decal_t *p;
-       int i, j, k, dynamiclight, bits, texnum, iscale, ir, ig, ib, lit, cr, cg, cb;
-       float /*fscale, */fr, fg, fb, dist, rad, mindist;
-       byte *lightmap;
-       vec3_t v;
-       msurface_t *surf;
-       dlight_t *dl;
+                       // skip decals on surfaces that aren't visible in this frame
+                       if (surf->visframe != r_framecount)
+                               continue;
 
-       if (!r_drawdecals.value)
-               return;
+                       softwaretransformforentity(r->ent);
+                       softwaretransform(r->org, org);
+                       softwaretransformdirection(r->dir, dir);
 
-       dynamiclight = (int) r_dynamic.value != 0 && (int) r_decals_lighting.value != 0;
+                       // do not render if the view origin is behind the decal
+                       VectorSubtract(org, r_origin, v);
+                       if (DotProduct(dir, v) < 0)
+                               continue;
+               }
+               else
+               {
+                       surf = cl.worldmodel->surfaces + r->surface;
 
-       mindist = DotProduct(r_origin, vpn) + 4.0f;
+                       // skip decals on surfaces that aren't visible in this frame
+                       if (surf->visframe != r_framecount)
+                               continue;
 
-       if (r_render.value)
-       {
-               glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-               glEnable(GL_BLEND);
-//             glShadeModel(GL_FLAT);
-               glDepthMask(0); // disable zbuffer updates
-               glDisable(GL_ALPHA_TEST);
-               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-       }
-       texnum = -1;
+                       // do not render if the view origin is behind the decal
+                       VectorSubtract(r->org, r_origin, v);
+                       if (DotProduct(r->dir, v) < 0)
+                               continue;
 
-       for (i = 0, p = decals;i < MAX_DECALS;i++, p++)
-       {
-               if (p->tex == NULL)
-                       break;
-               // skip decals on surfaces that aren't visible in this frame
-               if (p->surface->visframe != r_framecount)
-                       continue;
+                       VectorCopy(r->org, org);
+                       VectorCopy(r->dir, dir);
+               }
 
-               // do not render if the decal is behind the view
-               if (DotProduct(p->org, vpn) < mindist)
-                       continue;
+               dist = -PlaneDiff(r->org, surf->plane);
+               VectorMA(r->org, dist, surf->plane->normal, impact);
 
-               // do not render if the view origin is behind the decal
-               VectorSubtract(p->org, r_origin, v);
-               if (DotProduct(p->direction, v) < 0)
-                       continue;
+               ds = (int) (DotProduct(impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) - surf->texturemins[0];
+               dt = (int) (DotProduct(impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) - surf->texturemins[1];
 
-               // get the surface lighting
-               surf = p->surface;
-               lightmap = p->lightmapaddress;
-               // dynamic lighting
-               lit = false;
-               if (dynamiclight)
-               {
-                       fr = fg = fb = 0.0f;
-                       if (surf->dlightframe == r_framecount)
-                       {
-                               for (j = 0;j < 8;j++)
-                               {
-                                       bits = surf->dlightbits[j];
-                                       if (bits)
-                                       {
-                                               for (k = 0, dl = cl_dlights + j * 32;bits;k++, dl++)
-                                               {
-                                                       if (bits & (1 << k))
-                                                       {
-                                                               bits -= 1 << k;
-                                                               VectorSubtract(p->org, dl->origin, v);
-                                                               dist = DotProduct(v, v) + LIGHTOFFSET;
-                                                               rad = dl->radius * dl->radius;
-                                                               if (dist < rad)
-                                                               {
-                                                                       rad *= 128.0f / dist;
-                                                                       fr += rad * dl->color[0];
-                                                                       fg += rad * dl->color[1];
-                                                                       fb += rad * dl->color[2];
-                                                                       lit = true;
-                                                               }
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               }
-               if (lit)
+               if (ds < 0 || dt < 0 || ds > surf->extents[0] || dt > surf->extents[1])
                {
-#if SLOWMATH
-                       ir = fr * 256.0f;
-                       ig = fg * 256.0f;
-                       ib = fb * 256.0f;
-#else
-                       fr += 8388608.0f;
-                       fg += 8388608.0f;
-                       fb += 8388608.0f;
-                       ir = (*((long *)&fr) & 0x7FFFFF) << 8;
-                       ig = (*((long *)&fg) & 0x7FFFFF) << 8;
-                       ib = (*((long *)&fb) & 0x7FFFFF) << 8;
-#endif
-               }
-               else
-                       ir = ig = ib = 0;
-#if 1
-               if (lightmap)
-               {
-                       if (surf->styles[0] != 255)
-                       {
-                               iscale = d_lightstylevalue[surf->styles[0]];
-                               ir += lightmap[0] * iscale;
-                               ig += lightmap[1] * iscale;
-                               ib += lightmap[2] * iscale;
-                               if (surf->styles[1] != 255)
-                               {
-                                       lightmap += p->lightmapstep;
-                                       iscale = d_lightstylevalue[surf->styles[1]];
-                                       ir += lightmap[0] * iscale;
-                                       ig += lightmap[1] * iscale;
-                                       ib += lightmap[2] * iscale;
-                                       if (surf->styles[2] != 255)
-                                       {
-                                               lightmap += p->lightmapstep;
-                                               iscale = d_lightstylevalue[surf->styles[2]];
-                                               ir += lightmap[0] * iscale;
-                                               ig += lightmap[1] * iscale;
-                                               ib += lightmap[2] * iscale;
-                                               if (surf->styles[3] != 255)
-                                               {
-                                                       lightmap += p->lightmapstep;
-                                                       iscale = d_lightstylevalue[surf->styles[3]];
-                                                       ir += lightmap[0] * iscale;
-                                                       ig += lightmap[1] * iscale;
-                                                       ib += lightmap[2] * iscale;
-                                               }
-                                       }
-                               }
-                       }
+                       // this should never happen
+                       continue;
                }
-#else
+
+               if (fogenabled)
+                       ifog = 1 - exp(fogdensity/DotProduct(v,v));
+
+               tex = &particletexture[r->tex][0];
+               VectorVectors(dir, right, up);
+               VectorScale(right, r->scale, right);
+               VectorScale(up, r->scale, up);
+               tvertex[0][0] = org[0] - right[0] - up[0];
+               tvertex[0][1] = org[1] - right[1] - up[1];
+               tvertex[0][2] = org[2] - right[2] - up[2];
+               tvertex[0][3] = tex->s1;
+               tvertex[0][4] = tex->t1;
+               tvertex[1][0] = org[0] - right[0] + up[0];
+               tvertex[1][1] = org[1] - right[1] + up[1];
+               tvertex[1][2] = org[2] - right[2] + up[2];
+               tvertex[1][3] = tex->s1;
+               tvertex[1][4] = tex->t2;
+               tvertex[2][0] = org[0] + right[0] + up[0];
+               tvertex[2][1] = org[1] + right[1] + up[1];
+               tvertex[2][2] = org[2] + right[2] + up[2];
+               tvertex[2][3] = tex->s2;
+               tvertex[2][4] = tex->t2;
+               tvertex[3][0] = org[0] + right[0] - up[0];
+               tvertex[3][1] = org[1] + right[1] - up[1];
+               tvertex[3][2] = org[2] + right[2] - up[2];
+               tvertex[3][3] = tex->s2;
+               tvertex[3][4] = tex->t1;
+
+               // lighting
                fr = fg = fb = 0.0f;
-               if (lightmap)
+
+               if ((lightmap = surf->samples))
                {
                        if (surf->styles[0] != 255)
                        {
-                               fscale = d_lightstylevalue[surf->styles[0]] * (1.0f / 256.0f);
+                               lightmap += ((dt >> 4) * ((surf->extents[0] >> 4) + 1) + (ds >> 4)) * 3;
+                               fscale = d_lightstylevalue[surf->styles[0]] * (1.0f / 32768.0f);
                                fr += lightmap[0] * fscale;
                                fg += lightmap[1] * fscale;
                                fb += lightmap[2] * fscale;
                                if (surf->styles[1] != 255)
                                {
-                                       lightmap += p->lightmapstep;
-                                       fscale = d_lightstylevalue[surf->styles[1]] * (1.0f / 256.0f);
+                                       lightmapstep = (((surf->extents[0] >> 4) + 1) * ((surf->extents[1] >> 4) + 1)) * 3;
+                                       lightmap += lightmapstep;
+                                       fscale = d_lightstylevalue[surf->styles[1]] * (1.0f / 32768.0f);
                                        fr += lightmap[0] * fscale;
                                        fg += lightmap[1] * fscale;
                                        fb += lightmap[2] * fscale;
                                        if (surf->styles[2] != 255)
                                        {
-                                               lightmap += p->lightmapstep;
-                                               fscale = d_lightstylevalue[surf->styles[2]] * (1.0f / 256.0f);
+                                               lightmap += lightmapstep;
+                                               fscale = d_lightstylevalue[surf->styles[2]] * (1.0f / 32768.0f);
                                                fr += lightmap[0] * fscale;
                                                fg += lightmap[1] * fscale;
                                                fb += lightmap[2] * fscale;
                                                if (surf->styles[3] != 255)
                                                {
-                                                       lightmap += p->lightmapstep;
-                                                       fscale = d_lightstylevalue[surf->styles[3]] * (1.0f / 256.0f);
+                                                       lightmap += lightmapstep;
+                                                       fscale = d_lightstylevalue[surf->styles[3]] * (1.0f / 32768.0f);
                                                        fr += lightmap[0] * fscale;
                                                        fg += lightmap[1] * fscale;
                                                        fb += lightmap[2] * fscale;
@@ -398,89 +196,140 @@ void GL_DrawDecals (void)
                                        }
                                }
                        }
-                       /*
-                       for (j = 0;j < MAXLIGHTMAPS && surf->styles[j] != 255;j++)
-                       {
-                               fscale = d_lightstylevalue[surf->styles[j]] * (1.0f / 256.0f);
-                               fr += lightmap[0] * fscale;
-                               fg += lightmap[1] * fscale;
-                               fb += lightmap[2] * fscale;
-                               lightmap += p->lightmapstep;
-                       }
-                       */
-               }
-#endif
-               /*
-               {
-                       int ir, ig, ib;
-                       byte br, bg, bb, ba;
-                       // apply color to lighting
-                       ir = (int) (fr * p->color[0] * (1.0f / 128.0f));
-                       ig = (int) (fg * p->color[1] * (1.0f / 128.0f));
-                       ib = (int) (fb * p->color[2] * (1.0f / 128.0f));
-                       // compute byte color
-                       br = (byte) min(ir, 255);
-                       bg = (byte) min(ig, 255);
-                       bb = (byte) min(ib, 255);
-                       ba = p->color[3];
-                       // put into transpoly system for sorted drawing later
-                       transpolybegin(R_GetTexture(p->tex), 0, R_GetTexture(p->tex), TPOLYTYPE_ALPHA);
-                       transpolyvertub(p->vert[0][0], p->vert[0][1], p->vert[0][2], 0,1,br,bg,bb,ba);
-                       transpolyvertub(p->vert[1][0], p->vert[1][1], p->vert[1][2], 0,0,br,bg,bb,ba);
-                       transpolyvertub(p->vert[2][0], p->vert[2][1], p->vert[2][2], 1,0,br,bg,bb,ba);
-                       transpolyvertub(p->vert[3][0], p->vert[3][1], p->vert[3][2], 1,1,br,bg,bb,ba);
-                       transpolyend();
                }
-               */
-               if (r_render.value)
+
+               if (surf->dlightframe == r_framecount)
                {
-                       j = R_GetTexture(p->tex);
-                       if (texnum != j)
-                       {
-                               glEnd();
-                               texnum = j;
-                               glBindTexture(GL_TEXTURE_2D, texnum);
-                               glBegin(GL_QUADS);
-                       }
-                       /*
-                       if (lighthalf)
-                               glColor4f(fr * p->color[0] * (1.0f / 255.0f / 256.0f), fg * p->color[1] * (1.0f / 255.0f / 256.0f), fb * p->color[2] * (1.0f / 255.0f / 256.0f), p->color[3] * (1.0f / 255.0f));
-                       else
-                               glColor4f(fr * p->color[0] * (1.0f / 255.0f / 128.0f), fg * p->color[1] * (1.0f / 255.0f / 128.0f), fb * p->color[2] * (1.0f / 255.0f / 128.0f), p->color[3] * (1.0f / 255.0f));
-                       */
-                       if (lighthalf)
-                       {
-                               cr = (ir * p->color[0]) >> 16;
-                               cg = (ig * p->color[1]) >> 16;
-                               cb = (ib * p->color[2]) >> 16;
-                       }
-                       else
+                       for (j = 0;j < r_numdlights;j++)
                        {
-                               cr = (ir * p->color[0]) >> 15;
-                               cg = (ig * p->color[1]) >> 15;
-                               cb = (ib * p->color[2]) >> 15;
+                               if (surf->dlightbits[j >> 5] & (1 << (j & 31)))
+                               {
+                                       rd = &r_dlight[j];
+                                       VectorSubtract(r->org, rd->origin, v);
+                                       dist = DotProduct(v, v) + LIGHTOFFSET;
+                                       if (dist < rd->cullradius2)
+                                       {
+                                               f = (1.0f / dist) - rd->lightsubtract;
+                                               if (f > 0)
+                                               {
+                                                       fr += f * rd->light[0];
+                                                       fg += f * rd->light[1];
+                                                       fb += f * rd->light[2];
+                                               }
+                                       }
+                               }
                        }
-                       cr = min(cr, 255);
-                       cg = min(cg, 255);
-                       cb = min(cb, 255);
-                       glColor4ub(cr, cg, cb, p->color[3]);
-
-                       glTexCoord2f(p->texcoord[0][0], p->texcoord[0][1]);
-                       glVertex3fv(p->vert[0]);
-                       glTexCoord2f(p->texcoord[1][0], p->texcoord[1][1]);
-                       glVertex3fv(p->vert[1]);
-                       glTexCoord2f(p->texcoord[2][0], p->texcoord[2][1]);
-                       glVertex3fv(p->vert[2]);
-                       glTexCoord2f(p->texcoord[3][0], p->texcoord[3][1]);
-                       glVertex3fv(p->vert[3]);
                }
+
+               // if the surface is transparent, render as transparent
+               m.transparent = !(surf->flags & SURF_CLIPSOLID);
+               m.cr = r->color[0] * fr;
+               m.cg = r->color[1] * fg;
+               m.cb = r->color[2] * fb;
+               m.ca = r->color[3];
+
+               if (fogenabled)
+               {
+                       m.cr *= ifog;
+                       m.cg *= ifog;
+                       m.cb *= ifog;
+               }
+
+               R_Mesh_Draw(&m);
        }
 
-       if (r_render.value)
+       if (!fogenabled)
+               return;
+
+       m.blendfunc2 = GL_ONE;
+       m.cr = fogcolor[0];
+       m.cg = fogcolor[1];
+       m.cb = fogcolor[2];
+
+       for (i = 0, r = r_refdef.decals;i < r_refdef.numdecals;i++, r++)
        {
-               glEnd();
+               if (r->ent)
+               {
+                       if (r->ent->visframe != r_framecount)
+                               continue;
+
+                       Mod_CheckLoaded(r->ent->model);
+
+                       surf = r->ent->model->surfaces + r->surface;
+
+                       // skip decals on surfaces that aren't visible in this frame
+                       if (surf->visframe != r_framecount)
+                               continue;
+
+                       softwaretransformforentity(r->ent);
+                       softwaretransform(r->org, org);
+                       softwaretransformdirection(r->dir, dir);
 
-               glDepthMask(1); // enable zbuffer updates
-               glDisable(GL_ALPHA_TEST);
+                       // do not render if the view origin is behind the decal
+                       VectorSubtract(org, r_origin, v);
+                       if (DotProduct(dir, v) < 0)
+                               continue;
+               }
+               else
+               {
+                       surf = cl.worldmodel->surfaces + r->surface;
+
+                       // skip decals on surfaces that aren't visible in this frame
+                       if (surf->visframe != r_framecount)
+                               continue;
+
+                       // do not render if the view origin is behind the decal
+                       VectorSubtract(r->org, r_origin, v);
+                       if (DotProduct(r->dir, v) < 0)
+                               continue;
+
+                       VectorCopy(r->org, org);
+                       VectorCopy(r->dir, dir);
+               }
+
+               dist = -PlaneDiff(r->org, surf->plane);
+               VectorMA(r->org, dist, surf->plane->normal, impact);
+
+               ds = (int) (DotProduct(impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) - surf->texturemins[0];
+               dt = (int) (DotProduct(impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) - surf->texturemins[1];
+
+               if (ds < 0 || dt < 0 || ds > surf->extents[0] || dt > surf->extents[1])
+               {
+                       // this should never happen
+                       continue;
+               }
+
+               tex = &particletexture[r->tex][1];
+               VectorVectors(dir, right, up);
+               VectorScale(right, r->scale, right);
+               VectorScale(up, r->scale, up);
+               tvertex[0][0] = org[0] - right[0] - up[0];
+               tvertex[0][1] = org[1] - right[1] - up[1];
+               tvertex[0][2] = org[2] - right[2] - up[2];
+               tvertex[0][3] = tex->s1;
+               tvertex[0][4] = tex->t1;
+               tvertex[1][0] = org[0] - right[0] + up[0];
+               tvertex[1][1] = org[1] - right[1] + up[1];
+               tvertex[1][2] = org[2] - right[2] + up[2];
+               tvertex[1][3] = tex->s1;
+               tvertex[1][4] = tex->t2;
+               tvertex[2][0] = org[0] + right[0] + up[0];
+               tvertex[2][1] = org[1] + right[1] + up[1];
+               tvertex[2][2] = org[2] + right[2] + up[2];
+               tvertex[2][3] = tex->s2;
+               tvertex[2][4] = tex->t2;
+               tvertex[3][0] = org[0] + right[0] - up[0];
+               tvertex[3][1] = org[1] + right[1] - up[1];
+               tvertex[3][2] = org[2] + right[2] - up[2];
+               tvertex[3][3] = tex->s2;
+               tvertex[3][4] = tex->t1;
+
+               // if the surface is transparent, render as transparent
+               m.transparent = !(surf->flags & SURF_CLIPSOLID);
+               m.ca = r->color[3] * exp(fogdensity/DotProduct(v,v));
+
+               if (m.ca >= (1.0f / 255.0f))
+                       R_Mesh_Draw(&m);
        }
 }
+