]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_decals.c
fixed monster interpolation in normal quake, which makes dpcrush not lerped unfortunately
[xonotic/darkplaces.git] / r_decals.c
index 07a350fc50f1c3af1938fd171b657fd881b3a520..74a9b35dbda1ffd983d97d97baa099df13fde444 100644 (file)
@@ -41,17 +41,271 @@ void R_Decals_Init(void)
        R_RegisterModule("R_Decals", r_decals_start, r_decals_shutdown, r_decals_newmap);
 }
 
+/*
 static int decalindexarray[2*3] =
 {
        0, 1, 2,
        0, 2, 3,
 };
+*/
 
 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];
+       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;
+
+       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++)
+       {
+               if (r->ent)
+               {
+                       if (r->ent->visframe != r_framecount)
+                               continue;
+
+                       Mod_CheckLoaded(r->ent->model);
+                       if (r->ent->model->type != mod_brush)
+                               continue;
+
+                       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, 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;
+               }
+
+               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 ((lightmap = surf->samples))
+               {
+                       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;
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               if (surf->dlightframe == r_framecount)
+               {
+                       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];
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               // 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_DrawDecals (void)
+{
+       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;
@@ -71,10 +325,10 @@ void R_DrawDecals (void)
        m.numtriangles = 2;
        m.numverts = 4;
        m.index = decalindexarray;
-       m.vertex = &tvertex[0][0];
+       m.vertex = &tv[0][0];
        m.vertexstep = sizeof(float[5]);
        m.tex[0] = R_GetTexture(particlefonttexture);
-       m.texcoords[0] = &tvertex[0][3];
+       m.texcoords[0] = &tv[0][3];
        m.texcoordstep[0] = sizeof(float[5]);
 
        for (i = 0, r = r_refdef.decals;i < r_refdef.numdecals;i++, r++)
@@ -85,6 +339,8 @@ void R_DrawDecals (void)
                                continue;
 
                        Mod_CheckLoaded(r->ent->model);
+                       if (r->ent->model->type != mod_brush)
+                               continue;
 
                        surf = r->ent->model->surfaces + r->surface;
 
@@ -131,32 +387,35 @@ void R_DrawDecals (void)
                }
 
                if (fogenabled)
+               {
                        ifog = 1 - exp(fogdensity/DotProduct(v,v));
+                       ifog = bound(0, ifog, 1);
+               }
 
                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;
+               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;
@@ -235,7 +494,7 @@ void R_DrawDecals (void)
                        m.cb *= ifog;
                }
 
-               R_Mesh_Draw(&m);
+               R_Mesh_DrawDecal(&m);
        }
 
        if (!fogenabled)
@@ -287,7 +546,9 @@ void R_DrawDecals (void)
                        VectorCopy(r->dir, dir);
                }
 
-               m.ca = r->color[3] * exp(fogdensity/DotProduct(v,v));
+               fog = exp(fogdensity/DotProduct(v,v));
+               fog = bound(0, fog, 1);
+               m.ca = r->color[3] * fog;
 
                if (m.ca >= 0.01f)
                {
@@ -307,31 +568,31 @@ void R_DrawDecals (void)
                        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;
+                       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_Draw(&m);
+                       R_Mesh_DrawDecal(&m);
                }
        }
 }
-
+*/