]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_decals.c
added cl_screen.c/h (eventually most 2D stuff should be moved here)
[xonotic/darkplaces.git] / r_decals.c
index f920b2ab68a824e37dacf5419dbf2dd41af9a7b0..74a9b35dbda1ffd983d97d97baa099df13fde444 100644 (file)
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 See the GNU General Public License for more details.
 
@@ -20,382 +20,579 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 
-#define MAX_DECALS 2048
+cvar_t r_drawdecals = {0, "r_drawdecals", "1"};
 
-typedef struct decal_s
+static void r_decals_start(void)
 {
-       vec3_t          org;
-       vec3_t          direction;
-       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 = {"r_drawdecals", "1"};
-cvar_t r_decals_lighting = {"r_decals_lighting", "1"};
-
-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] =
+{
+       0, 1, 2,
+       0, 2, 3,
+};
+*/
+
+void R_DrawDecals (void)
 {
-       // 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)
+       renderdecal_t *r;
+       int i, j, lightmapstep, ds, dt;
+       float fscale, fr, fg, fb, dist, f, fog, ifog, fogvec[3], impact[3], v[3], org[3], dir[3], right[3], up[3], tvxyz[4][4], tvst[4][2];
+       particletexture_t *tex, *texfog;
+       byte *lightmap;
+       msurface_t *surf;
+       rdlight_t *rd;
+       rmeshinfo_t m;
+
+       if (!r_drawdecals.integer)
                return;
 
-       ndist = PlaneDiff(decalorg, node->plane);
-       
-       if (ndist > 16)
-       {
-               node = node->children[0];
-               goto loc0;
-       }
-       if (ndist < -16)
+       fog = 0;
+       ifog = 1;
+
+       Mod_CheckLoaded(cl.worldmodel);
+
+       // LordHavoc: this meshinfo must match up with R_Mesh_DrawDecal
+       // LordHavoc: the commented out lines are hardwired behavior in R_Mesh_DrawDecal
+       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 = &tvxyz[0][0];
+       //m.vertexstep = sizeof(float[4]);
+       m.tex[0] = R_GetTexture(particlefonttexture);
+       m.texcoords[0] = &tvst[0][0];
+       //m.texcoordstep[0] = sizeof(float[2]);
+
+       for (i = 0, r = r_refdef.decals;i < r_refdef.numdecals;i++, r++)
        {
-               node = node->children[1];
-               goto loc0;
-       }
+               if (r->ent)
+               {
+                       if (r->ent->visframe != r_framecount)
+                               continue;
 
-// 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
+                       Mod_CheckLoaded(r->ent->model);
+                       if (r->ent->model->type != mod_brush)
+                               continue;
 
-               dist = PlaneDiff(decalorg, surf->plane);
-               if (surf->flags & SURF_PLANEBACK)
-                       dist = -dist;
-               if (dist < 0)
-                       continue;
-               if (dist >= decalbestdist)
-                       continue;
+                       surf = r->ent->model->surfaces + r->surface;
 
-               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;
+                       // skip decals on surfaces that aren't visible in this frame
+                       if (surf->visframe != r_framecount)
+                               continue;
 
-               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]);
+                       softwaretransformforentity(r->ent);
+                       softwaretransform(r->org, org);
+                       softwaretransformdirection(r->dir, dir);
 
-               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])
+                       // do not render if the view origin is behind the decal
+                       VectorSubtract(org, r_origin, fogvec);
+                       if (DotProduct(dir, fogvec) < 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, fogvec);
+                       if (DotProduct(r->dir, fogvec) < 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;
+               }
 
-               decalbestsurf = surf;
-               decalbestdist = dist;
-               decalbestlightmapofs = (dt >> 4) * ((surf->extents[0] >> 4) + 1) + (ds >> 4);
-       }
+               tex = &particletexture[r->tex][0];
+               VectorVectors(dir, right, up);
+               VectorScale(right, r->scale, right);
+               VectorScale(up, r->scale, up);
+               tvxyz[0][0] = org[0] - right[0] - up[0];
+               tvxyz[0][1] = org[1] - right[1] - up[1];
+               tvxyz[0][2] = org[2] - right[2] - up[2];
+               tvxyz[1][0] = org[0] - right[0] + up[0];
+               tvxyz[1][1] = org[1] - right[1] + up[1];
+               tvxyz[1][2] = org[2] - right[2] + up[2];
+               tvxyz[2][0] = org[0] + right[0] + up[0];
+               tvxyz[2][1] = org[1] + right[1] + up[1];
+               tvxyz[2][2] = org[2] + right[2] + up[2];
+               tvxyz[3][0] = org[0] + right[0] - up[0];
+               tvxyz[3][1] = org[1] + right[1] - up[1];
+               tvxyz[3][2] = org[2] + right[2] - up[2];
+               tvst[0][0] = tex->s1;
+               tvst[0][1] = tex->t1;
+               tvst[1][0] = tex->s1;
+               tvst[1][1] = tex->t2;
+               tvst[2][0] = tex->s2;
+               tvst[2][1] = tex->t2;
+               tvst[3][0] = tex->s2;
+               tvst[3][1] = tex->t1;
+
+               // lighting
+               fr = fg = fb = 0.0f;
 
-       if (node->children[0]->contents >= 0)
-       {
-               if (node->children[1]->contents >= 0)
+               if ((lightmap = surf->samples))
                {
-                       R_RecursiveDecalSurface (node->children[0]);
-                       node = node->children[1];
-                       goto loc0;
+                       if (surf->styles[0] != 255)
+                       {
+                               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)
+                               {
+                                       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 += 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 += lightmapstep;
+                                                       fscale = d_lightstylevalue[surf->styles[3]] * (1.0f / 32768.0f);
+                                                       fr += lightmap[0] * fscale;
+                                                       fg += lightmap[1] * fscale;
+                                                       fb += lightmap[2] * fscale;
+                                               }
+                                       }
+                               }
+                       }
                }
-               else
+
+               if (surf->dlightframe == r_framecount)
                {
-                       node = node->children[0];
-                       goto loc0;
+                       for (j = 0;j < r_numdlights;j++)
+                       {
+                               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];
+                                               }
+                                       }
+                               }
+                       }
                }
-       }
-       else if (node->children[1]->contents >= 0)
-       {
-               node = node->children[1];
-               goto loc0;
+
+               // 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)
+               {
+                       fog = exp(fogdensity/DotProduct(fogvec,fogvec));
+                       texfog = &particletexture[r->tex][1];
+                       if (fog >= (1.0f / 64.0f))
+                       {
+                               if (fog >= (1.0f - (1.0f / 64.0f)))
+                               {
+                                       // fully fogged, just use the fog texture and render as alpha
+                                       m.cr = fogcolor[0];
+                                       m.cg = fogcolor[1];
+                                       m.cb = fogcolor[2];
+                                       m.ca = r->color[3];
+                                       tvst[0][0] = texfog->s1;
+                                       tvst[0][1] = texfog->t1;
+                                       tvst[1][0] = texfog->s1;
+                                       tvst[1][1] = texfog->t2;
+                                       tvst[2][0] = texfog->s2;
+                                       tvst[2][1] = texfog->t2;
+                                       tvst[3][0] = texfog->s2;
+                                       tvst[3][1] = texfog->t1;
+                                       R_Mesh_DrawDecal(&m);
+                               }
+                               else
+                               {
+                                       // partially fogged, darken the first pass
+                                       ifog = 1 - fog;
+                                       m.cr *= ifog;
+                                       m.cg *= ifog;
+                                       m.cb *= ifog;
+                                       if (tex->s1 == texfog->s1 && tex->t1 == texfog->t1)
+                                       {
+                                               // fog texture is the same as the base, just change the color
+                                               m.cr += fogcolor[0] * fog;
+                                               m.cg += fogcolor[1] * fog;
+                                               m.cb += fogcolor[2] * fog;
+                                               R_Mesh_DrawDecal(&m);
+                                       }
+                                       else
+                                       {
+                                               // render the first pass (alpha), then do additive fog
+                                               R_Mesh_DrawDecal(&m);
+                                               m.blendfunc2 = GL_ONE;
+                                               m.cr = fogcolor[0];
+                                               m.cg = fogcolor[1];
+                                               m.cb = fogcolor[2];
+                                               m.ca = r->color[3] * fog;
+                                               tvst[0][0] = texfog->s1;
+                                               tvst[0][1] = texfog->t1;
+                                               tvst[1][0] = texfog->s1;
+                                               tvst[1][1] = texfog->t2;
+                                               tvst[2][0] = texfog->s2;
+                                               tvst[2][1] = texfog->t2;
+                                               tvst[3][0] = texfog->s2;
+                                               tvst[3][1] = texfog->t1;
+                                               R_Mesh_DrawDecal(&m);
+                                               m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+                                       }
+                               }
+                       }
+                       else
+                               R_Mesh_DrawDecal(&m);
+               }
+               else
+                       R_Mesh_DrawDecal(&m);
        }
 }
 
-void R_Decal(vec3_t org, rtexture_t *tex, float scale, int cred, int cgreen, int cblue, int alpha)
+/*
+void R_DrawDecals (void)
 {
-       vec3_t center, right, up;
-       decal_t *decal;
+       renderdecal_t *r;
+       int i, j, lightmapstep, ds, dt;
+       float fscale, fr, fg, fb, dist, f, fog, ifog, impact[3], v[3], org[3], dir[3], right[3], up[3], tv[4][5];
+       particletexture_t *tex;
+       byte *lightmap;
+       msurface_t *surf;
+       rdlight_t *rd;
+       rmeshinfo_t m;
 
-       if (alpha < 1)
+       if (!r_drawdecals.integer)
                return;
 
-       // find the best surface to place the decal on
-       decalbestsurf = NULL;
-       decalbestdist = 16;
-       decalbestlightmapofs = 0;
-       VectorCopy(org, decalorg);
+       ifog = 1;
 
-       R_RecursiveDecalSurface (cl.worldmodel->nodes);
+       Mod_CheckLoaded(cl.worldmodel);
 
-       // abort if no suitable surface was found
-       if (decalbestsurf == NULL)
-               return;
+       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 = &tv[0][0];
+       m.vertexstep = sizeof(float[5]);
+       m.tex[0] = R_GetTexture(particlefonttexture);
+       m.texcoords[0] = &tv[0][3];
+       m.texcoordstep[0] = sizeof(float[5]);
 
-       // 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->vert[0][0] = center[0] - right[0] * scale - up[0] * scale; // texcoords 0 1
-       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->vert[1][0] = center[0] - right[0] * scale + up[0] * scale; // texcoords 0 0
-       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->vert[2][0] = center[0] + right[0] * scale + up[0] * scale; // texcoords 1 0
-       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->vert[3][0] = center[0] + right[0] * scale - up[0] * scale; // texcoords 1 1
-       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;
-}
+       for (i = 0, r = r_refdef.decals;i < r_refdef.numdecals;i++, r++)
+       {
+               if (r->ent)
+               {
+                       if (r->ent->visframe != r_framecount)
+                               continue;
 
-void GL_DrawDecals (void)
-{
-       decal_t *p;
-       int i, j, k, dynamiclight, bits, texnum;
-       float scale, fr, fg, fb, dist, rad, mindist;
-       byte *lightmap;
-       vec3_t v;
-       msurface_t *surf;
-       dlight_t *dl;
+                       Mod_CheckLoaded(r->ent->model);
+                       if (r->ent->model->type != mod_brush)
+                               continue;
 
-       if (!r_drawdecals.value)
-               return;
+                       surf = r->ent->model->surfaces + r->surface;
 
-       dynamiclight = (int) r_dynamic.value != 0 && (int) r_decals_lighting.value != 0;
+                       // skip decals on surfaces that aren't visible in this frame
+                       if (surf->visframe != r_framecount)
+                               continue;
 
-       mindist = DotProduct(r_origin, vpn) + 4.0f;
+                       softwaretransformforentity(r->ent);
+                       softwaretransform(r->org, org);
+                       softwaretransformdirection(r->dir, dir);
 
-       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(org, r_origin, v);
+                       if (DotProduct(dir, v) < 0)
+                               continue;
+               }
+               else
+               {
+                       surf = cl.worldmodel->surfaces + r->surface;
 
-       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;
+                       // skip decals on surfaces that aren't visible in this frame
+                       if (surf->visframe != r_framecount)
+                               continue;
 
-               // do not render if the decal is behind the view
-               if (DotProduct(p->org, vpn) < mindist)
-                       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);
 
-               // do not render if the view origin is behind the decal
-               VectorSubtract(p->org, r_origin, v);
-               if (DotProduct(p->direction, v) < 0)
+               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;
+               }
+
+               if (fogenabled)
+               {
+                       ifog = 1 - exp(fogdensity/DotProduct(v,v));
+                       ifog = bound(0, ifog, 1);
+               }
 
-               // get the surface lighting
-               surf = p->surface;
-               lightmap = p->lightmapaddress;
+               tex = &particletexture[r->tex][0];
+               VectorVectors(dir, right, up);
+               VectorScale(right, r->scale, right);
+               VectorScale(up, r->scale, up);
+               tv[0][0] = org[0] - right[0] - up[0];
+               tv[0][1] = org[1] - right[1] - up[1];
+               tv[0][2] = org[2] - right[2] - up[2];
+               tv[0][3] = tex->s1;
+               tv[0][4] = tex->t1;
+               tv[1][0] = org[0] - right[0] + up[0];
+               tv[1][1] = org[1] - right[1] + up[1];
+               tv[1][2] = org[2] - right[2] + up[2];
+               tv[1][3] = tex->s1;
+               tv[1][4] = tex->t2;
+               tv[2][0] = org[0] + right[0] + up[0];
+               tv[2][1] = org[1] + right[1] + up[1];
+               tv[2][2] = org[2] + right[2] + up[2];
+               tv[2][3] = tex->s2;
+               tv[2][4] = tex->t2;
+               tv[3][0] = org[0] + right[0] - up[0];
+               tv[3][1] = org[1] + right[1] - up[1];
+               tv[3][2] = org[2] + right[2] - up[2];
+               tv[3][3] = tex->s2;
+               tv[3][4] = tex->t1;
+
+               // lighting
                fr = fg = fb = 0.0f;
-               if (lightmap)
+
+               if ((lightmap = surf->samples))
                {
                        if (surf->styles[0] != 255)
                        {
-                               scale = d_lightstylevalue[surf->styles[0]] * (1.0f / 256.0f);
-                               fr += lightmap[0] * scale;
-                               fg += lightmap[1] * scale;
-                               fb += lightmap[2] * scale;
+                               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;
-                                       scale = d_lightstylevalue[surf->styles[1]] * (1.0f / 256.0f);
-                                       fr += lightmap[0] * scale;
-                                       fg += lightmap[1] * scale;
-                                       fb += lightmap[2] * scale;
+                                       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;
-                                               scale = d_lightstylevalue[surf->styles[2]] * (1.0f / 256.0f);
-                                               fr += lightmap[0] * scale;
-                                               fg += lightmap[1] * scale;
-                                               fb += lightmap[2] * scale;
+                                               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;
-                                                       scale = d_lightstylevalue[surf->styles[3]] * (1.0f / 256.0f);
-                                                       fr += lightmap[0] * scale;
-                                                       fg += lightmap[1] * scale;
-                                                       fb += lightmap[2] * scale;
+                                                       lightmap += lightmapstep;
+                                                       fscale = d_lightstylevalue[surf->styles[3]] * (1.0f / 32768.0f);
+                                                       fr += lightmap[0] * fscale;
+                                                       fg += lightmap[1] * fscale;
+                                                       fb += lightmap[2] * fscale;
                                                }
                                        }
                                }
                        }
-                       /*
-                       for (j = 0;j < MAXLIGHTMAPS && surf->styles[j] != 255;j++)
-                       {
-                               scale = d_lightstylevalue[surf->styles[j]] * (1.0f / 256.0f);
-                               fr += lightmap[0] * scale;
-                               fg += lightmap[1] * scale;
-                               fb += lightmap[2] * scale;
-                               lightmap += p->lightmapstep;
-                       }
-                       */
                }
-               // dynamic lighting
-               if (dynamiclight)
+
+               if (surf->dlightframe == r_framecount)
                {
-                       if (surf->dlightframe == r_framecount)
+                       for (j = 0;j < r_numdlights;j++)
                        {
-                               for (j = 0;j < 8;j++)
+                               if (surf->dlightbits[j >> 5] & (1 << (j & 31)))
                                {
-                                       bits = surf->dlightbits[j];
-                                       if (bits)
+                                       rd = &r_dlight[j];
+                                       VectorSubtract(r->org, rd->origin, v);
+                                       dist = DotProduct(v, v) + LIGHTOFFSET;
+                                       if (dist < rd->cullradius2)
                                        {
-                                               for (k = 0, dl = cl_dlights + j * 32;bits;k++, dl++)
+                                               f = (1.0f / dist) - rd->lightsubtract;
+                                               if (f > 0)
                                                {
-                                                       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];
-                                                               }
-                                                       }
+                                                       fr += f * rd->light[0];
+                                                       fg += f * rd->light[1];
+                                                       fb += f * rd->light[2];
                                                }
                                        }
                                }
                        }
                }
-               /*
+
+               // 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_DrawDecal(&m);
+       }
+
+       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++)
+       {
+               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);
+
+                       // do not render if the view origin is behind the decal
+                       VectorSubtract(org, r_origin, v);
+                       if (DotProduct(dir, v) < 0)
+                               continue;
+               }
+               else
                {
-                       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();
+                       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);
                }
-               */
-               if (r_render.value)
+
+               fog = exp(fogdensity/DotProduct(v,v));
+               fog = bound(0, fog, 1);
+               m.ca = r->color[3] * fog;
+
+               if (m.ca >= 0.01f)
                {
-                       j = R_GetTexture(p->tex);
-                       if (texnum != j)
+                       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])
                        {
-                               glEnd();
-                               texnum = j;
-                               glBindTexture(GL_TEXTURE_2D, texnum);
-                               glBegin(GL_QUADS);
+                               // this should never happen
+                               continue;
                        }
-                       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));
-                       glTexCoord2f(0, 1);
-                       glVertex3fv(p->vert[0]);
-                       glTexCoord2f(0, 0);
-                       glVertex3fv(p->vert[1]);
-                       glTexCoord2f(1, 0);
-                       glVertex3fv(p->vert[2]);
-                       glTexCoord2f(1, 1);
-                       glVertex3fv(p->vert[3]);
-               }
-       }
-       
-       if (r_render.value)
-       {
-               glEnd();
 
-               glDepthMask(1); // enable zbuffer updates
-               glDisable(GL_ALPHA_TEST);
+                       tex = &particletexture[r->tex][1];
+                       VectorVectors(dir, right, up);
+                       VectorScale(right, r->scale, right);
+                       VectorScale(up, r->scale, up);
+                       tv[0][0] = org[0] - right[0] - up[0];
+                       tv[0][1] = org[1] - right[1] - up[1];
+                       tv[0][2] = org[2] - right[2] - up[2];
+                       tv[0][3] = tex->s1;
+                       tv[0][4] = tex->t1;
+                       tv[1][0] = org[0] - right[0] + up[0];
+                       tv[1][1] = org[1] - right[1] + up[1];
+                       tv[1][2] = org[2] - right[2] + up[2];
+                       tv[1][3] = tex->s1;
+                       tv[1][4] = tex->t2;
+                       tv[2][0] = org[0] + right[0] + up[0];
+                       tv[2][1] = org[1] + right[1] + up[1];
+                       tv[2][2] = org[2] + right[2] + up[2];
+                       tv[2][3] = tex->s2;
+                       tv[2][4] = tex->t2;
+                       tv[3][0] = org[0] + right[0] - up[0];
+                       tv[3][1] = org[1] + right[1] - up[1];
+                       tv[3][2] = org[2] + right[2] - up[2];
+                       tv[3][3] = tex->s2;
+                       tv[3][4] = tex->t1;
+
+                       // if the surface is transparent, render as transparent
+                       m.transparent = !(surf->flags & SURF_CLIPSOLID);
+                       R_Mesh_DrawDecal(&m);
+               }
        }
 }
+*/