Rewrote most of r_lightning.c, it now uses CL_MeshEntities in MESH_PARTICLES rather...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 25 Mar 2018 20:04:14 +0000 (20:04 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 25 Mar 2018 20:04:14 +0000 (20:04 +0000)
Changed the texture generation so it is in the same orientation as the external texture to reduce some code duplication, and changed the look of it to more closely mimic the model-based lightning.

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@12356 d7cf8633-e32d-0410-b094-e92efae38249

cl_main.c
client.h
gl_rmain.c
r_lightning.c
render.h

index b13cb5f..ebde7da 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -1776,7 +1776,10 @@ void CL_RelinkBeams(void)
                                r_refdef.scene.lights[r_refdef.scene.numlights] = &r_refdef.scene.templights[r_refdef.scene.numlights];r_refdef.scene.numlights++;
                        }
                        if (cl_beams_polygons.integer)
+                       {
+                               CL_Beam_AddPolygons(b);
                                continue;
+                       }
                }
 
                // calculate pitch and yaw
index 05bed86..fd42d2b 100644 (file)
--- a/client.h
+++ b/client.h
@@ -2041,6 +2041,7 @@ void CL_NewFrameReceived(int num);
 void CL_ParseEntityLump(char *entitystring);
 void CL_FindNonSolidLocation(const vec3_t in, vec3_t out, vec_t radius);
 void CL_RelinkLightFlashes(void);
+void CL_Beam_AddPolygons(const beam_t *b);
 void Sbar_ShowFPS(void);
 void Sbar_ShowFPS_Update(void);
 void Host_SaveConfig(void);
index 39aa73a..bd40407 100644 (file)
@@ -7612,10 +7612,6 @@ void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
                R_DrawExplosions();
                if (r_timereport_active)
                        R_TimeReport("explosions");
-
-               R_DrawLightningBeams();
-               if (r_timereport_active)
-                       R_TimeReport("lightning");
        }
 
        if (cl.csqc_loaded)
index 8568292..addcece 100644 (file)
@@ -2,7 +2,7 @@
 #include "quakedef.h"
 #include "image.h"
 
-cvar_t r_lightningbeam_thickness = {CVAR_SAVE, "r_lightningbeam_thickness", "4", "thickness of the lightning beam effect"};
+cvar_t r_lightningbeam_thickness = {CVAR_SAVE, "r_lightningbeam_thickness", "8", "thickness of the lightning beam effect"};
 cvar_t r_lightningbeam_scroll = {CVAR_SAVE, "r_lightningbeam_scroll", "5", "speed of texture scrolling on the lightning beam effect"};
 cvar_t r_lightningbeam_repeatdistance = {CVAR_SAVE, "r_lightningbeam_repeatdistance", "128", "how far to stretch the texture along the lightning beam effect"};
 cvar_t r_lightningbeam_color_red = {CVAR_SAVE, "r_lightningbeam_color_red", "1", "color of the lightning beam effect"};
@@ -10,159 +10,89 @@ cvar_t r_lightningbeam_color_green = {CVAR_SAVE, "r_lightningbeam_color_green",
 cvar_t r_lightningbeam_color_blue = {CVAR_SAVE, "r_lightningbeam_color_blue", "1", "color of the lightning beam effect"};
 cvar_t r_lightningbeam_qmbtexture = {CVAR_SAVE, "r_lightningbeam_qmbtexture", "0", "load the qmb textures/particles/lightning.pcx texture instead of generating one, can look better"};
 
-skinframe_t *r_lightningbeamtexture;
-skinframe_t *r_lightningbeamqmbtexture;
-
-int r_lightningbeamelement3i[18] = {0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11};
-unsigned short r_lightningbeamelement3s[18] = {0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11};
+static texture_t cl_beams_externaltexture;
+static texture_t cl_beams_builtintexture;
 
 static void r_lightningbeams_start(void)
 {
-       r_lightningbeamtexture = NULL;
-       r_lightningbeamqmbtexture = NULL;
+       memset(&cl_beams_externaltexture, 0, sizeof(cl_beams_externaltexture));
+       memset(&cl_beams_builtintexture, 0, sizeof(cl_beams_builtintexture));
 }
 
-static void r_lightningbeams_setupqmbtexture(void)
+static void CL_Beams_SetupExternalTexture(void)
 {
-       r_lightningbeamqmbtexture = R_SkinFrame_LoadExternal("textures/particles/lightning.pcx", TEXF_ALPHA | TEXF_FORCELINEAR, false);
-       if (r_lightningbeamqmbtexture == NULL)
+       if (Mod_LoadTextureFromQ3Shader(&cl_beams_externaltexture, "textures/particles/lightning", false, false, TEXF_ALPHA | TEXF_FORCELINEAR))
+               cl_beams_externaltexture.basematerialflags = cl_beams_externaltexture.currentmaterialflags = MATERIALFLAG_WALL | MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOCULLFACE;
+       else
                Cvar_SetValueQuick(&r_lightningbeam_qmbtexture, false);
 }
 
-static void r_lightningbeams_setuptexture(void)
+static void CL_Beams_SetupBuiltinTexture(void)
 {
-#if 0
-#define BEAMWIDTH 128
-#define BEAMHEIGHT 64
-#define PATHPOINTS 8
-       int i, j, px, py, nearestpathindex, imagenumber;
-       float particlex, particley, particlexv, particleyv, dx, dy, s, maxpathstrength;
-       unsigned char *pixels;
-       int *image;
-       struct lightningpathnode_s
-       {
-               float x, y, strength;
-       }
-       path[PATHPOINTS], temppath;
-
-       image = Mem_Alloc(tempmempool, BEAMWIDTH * BEAMHEIGHT * sizeof(int));
-       pixels = Mem_Alloc(tempmempool, BEAMWIDTH * BEAMHEIGHT * sizeof(unsigned char[4]));
+       // beam direction is horizontal in the lightning texture
+       int texwidth = 128;
+       int texheight = 64;
+       float r, g, b, intensity, thickness = texheight * 0.25f, border = thickness + 2.0f, ithickness = 1.0f / thickness, center, n;
+       int x, y;
+       unsigned char *data;
+       skinframe_t *skinframe;
+       float centersamples[17][2];
 
-       for (imagenumber = 0, maxpathstrength = 0.0339476;maxpathstrength < 0.5;imagenumber++, maxpathstrength += 0.01)
+       // make a repeating noise pattern for the beam path
+       for (x = 0; x < 16; x++)
        {
-               for (i = 0;i < PATHPOINTS;i++)
-               {
-                       path[i].x = lhrandom(0, 1);
-                       path[i].y = lhrandom(0.2, 0.8);
-                       path[i].strength = lhrandom(0, 1);
-               }
-               for (i = 0;i < PATHPOINTS;i++)
-               {
-                       for (j = i + 1;j < PATHPOINTS;j++)
-                       {
-                               if (path[j].x < path[i].x)
-                               {
-                                       temppath = path[j];
-                                       path[j] = path[i];
-                                       path[i] = temppath;
-                               }
-                       }
-               }
-               particlex = path[0].x;
-               particley = path[0].y;
-               particlexv = lhrandom(0, 0.02);
-               particlexv = lhrandom(-0.02, 0.02);
-               memset(image, 0, BEAMWIDTH * BEAMHEIGHT * sizeof(int));
-               for (i = 0;i < 65536;i++)
-               {
-                       for (nearestpathindex = 0;nearestpathindex < PATHPOINTS;nearestpathindex++)
-                               if (path[nearestpathindex].x > particlex)
-                                       break;
-                       nearestpathindex %= PATHPOINTS;
-                       dx = path[nearestpathindex].x + lhrandom(-0.01, 0.01);dx = bound(0, dx, 1) - particlex;if (dx < 0) dx += 1;
-                       dy = path[nearestpathindex].y + lhrandom(-0.01, 0.01);dy = bound(0, dy, 1) - particley;
-                       s = path[nearestpathindex].strength / sqrt(dx*dx+dy*dy);
-                       particlexv = particlexv /* (1 - lhrandom(0.08, 0.12))*/ + dx * s;
-                       particleyv = particleyv /* (1 - lhrandom(0.08, 0.12))*/ + dy * s;
-                       particlex += particlexv * maxpathstrength;particlex -= (int) particlex;
-                       particley += particleyv * maxpathstrength;particley = bound(0, particley, 1);
-                       px = particlex * BEAMWIDTH;
-                       py = particley * BEAMHEIGHT;
-                       if (px >= 0 && py >= 0 && px < BEAMWIDTH && py < BEAMHEIGHT)
-                               image[py*BEAMWIDTH+px] += 16;
-               }
-
-               for (py = 0;py < BEAMHEIGHT;py++)
-               {
-                       for (px = 0;px < BEAMWIDTH;px++)
-                       {
-                               pixels[(py*BEAMWIDTH+px)*4+2] = bound(0, image[py*BEAMWIDTH+px] * 1.0f, 255.0f);
-                               pixels[(py*BEAMWIDTH+px)*4+1] = bound(0, image[py*BEAMWIDTH+px] * 1.0f, 255.0f);
-                               pixels[(py*BEAMWIDTH+px)*4+0] = bound(0, image[py*BEAMWIDTH+px] * 1.0f, 255.0f);
-                               pixels[(py*BEAMWIDTH+px)*4+3] = 255;
-                       }
-               }
-
-               Image_WriteTGABGRA(va(vabuf, sizeof(vabuf), "lightningbeam%i.tga", imagenumber), BEAMWIDTH, BEAMHEIGHT, pixels);
+               centersamples[x][0] = lhrandom(border, texheight - border);
+               centersamples[x][1] = lhrandom(0.2f, 1.00f);
        }
+       centersamples[16][0] = centersamples[0][0];
+       centersamples[16][1] = centersamples[0][1];
 
-       r_lightningbeamtexture = R_LoadTexture2D(r_lightningbeamtexturepool, "lightningbeam", BEAMWIDTH, BEAMHEIGHT, pixels, TEXTYPE_BGRA, TEXF_FORCELINEAR, NULL);
-
-       Mem_Free(pixels);
-       Mem_Free(image);
-#else
-#define BEAMWIDTH 64
-#define BEAMHEIGHT 128
-       float r, g, b, intensity, fx, width, center;
-       int x, y;
-       unsigned char *data, *noise1, *noise2;
-
-       data = (unsigned char *)Mem_Alloc(tempmempool, BEAMWIDTH * BEAMHEIGHT * 4);
-       noise1 = (unsigned char *)Mem_Alloc(tempmempool, BEAMHEIGHT * BEAMHEIGHT);
-       noise2 = (unsigned char *)Mem_Alloc(tempmempool, BEAMHEIGHT * BEAMHEIGHT);
-       fractalnoise(noise1, BEAMHEIGHT, BEAMHEIGHT / 8);
-       fractalnoise(noise2, BEAMHEIGHT, BEAMHEIGHT / 16);
+       data = (unsigned char *)Mem_Alloc(tempmempool, texwidth * texheight * 4);
 
-       for (y = 0;y < BEAMHEIGHT;y++)
+       // iterate by columns and draw the entire column of pixels
+       for (x = 0; x < texwidth; x++)
        {
-               width = 0.15;//((noise1[y * BEAMHEIGHT] * (1.0f / 256.0f)) * 0.1f + 0.1f);
-               center = (noise1[y * BEAMHEIGHT + (BEAMHEIGHT / 2)] / 256.0f) * (1.0f - width * 2.0f) + width;
-               for (x = 0;x < BEAMWIDTH;x++, fx++)
+               r = x * 16.0f / texwidth;
+               y = (int)r;
+               g = r - y;
+               center = centersamples[y][0] * (1.0f - g) + centersamples[y+1][0] * g;
+               n = centersamples[y][1] * (1.0f - g) + centersamples[y + 1][1] * g;
+               for (y = 0; y < texheight; y++)
                {
-                       fx = (((float) x / BEAMWIDTH) - center) / width;
-                       intensity = 1.0f - sqrt(fx * fx);
+                       intensity = 1.0f - fabs((y - center) * ithickness);
                        if (intensity > 0)
-                               intensity = pow(intensity, 2) * ((noise2[y * BEAMHEIGHT + x] * (1.0f / 256.0f)) * 0.33f + 0.66f);
-                       intensity = bound(0, intensity, 1);
-                       r = intensity * 1.0f;
-                       g = intensity * 1.0f;
-                       b = intensity * 1.0f;
-                       data[(y * BEAMWIDTH + x) * 4 + 2] = (unsigned char)(bound(0, r, 1) * 255.0f);
-                       data[(y * BEAMWIDTH + x) * 4 + 1] = (unsigned char)(bound(0, g, 1) * 255.0f);
-                       data[(y * BEAMWIDTH + x) * 4 + 0] = (unsigned char)(bound(0, b, 1) * 255.0f);
-                       data[(y * BEAMWIDTH + x) * 4 + 3] = (unsigned char)255;
+                       {
+                               intensity = pow(intensity * n, 2);
+                               r = intensity * 1.000f * 255.0f;
+                               g = intensity * 2.000f * 255.0f;
+                               b = intensity * 4.000f * 255.0f;
+                               data[(y * texwidth + x) * 4 + 2] = (unsigned char)(bound(0, r, 255));
+                               data[(y * texwidth + x) * 4 + 1] = (unsigned char)(bound(0, g, 255));
+                               data[(y * texwidth + x) * 4 + 0] = (unsigned char)(bound(0, b, 255));
+                       }
+                       else
+                               intensity = 0.0f;
+                       data[(y * texwidth + x) * 4 + 3] = (unsigned char)255;
                }
        }
 
-       r_lightningbeamtexture = R_SkinFrame_LoadInternalBGRA("lightningbeam", TEXF_FORCELINEAR, data, BEAMWIDTH, BEAMHEIGHT, false);
-       Mem_Free(noise1);
-       Mem_Free(noise2);
+       skinframe = R_SkinFrame_LoadInternalBGRA("lightningbeam", TEXF_FORCELINEAR, data, texwidth, texheight, false);
+       Mod_LoadCustomMaterial(&cl_beams_builtintexture, "cl_beams_builtintexture", 0, MATERIALFLAG_WALL | MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOCULLFACE, skinframe);
        Mem_Free(data);
-#endif
 }
 
 static void r_lightningbeams_shutdown(void)
 {
-       r_lightningbeamtexture = NULL;
-       r_lightningbeamqmbtexture = NULL;
+       memset(&cl_beams_externaltexture, 0, sizeof(cl_beams_externaltexture));
+       memset(&cl_beams_builtintexture, 0, sizeof(cl_beams_builtintexture));
 }
 
 static void r_lightningbeams_newmap(void)
 {
-       if (r_lightningbeamtexture)
-               R_SkinFrame_MarkUsed(r_lightningbeamtexture);
-       if (r_lightningbeamqmbtexture)
-               R_SkinFrame_MarkUsed(r_lightningbeamqmbtexture);
+       if (cl_beams_externaltexture.currentskinframe)
+               R_SkinFrame_MarkUsed(cl_beams_externaltexture.currentskinframe);
+       if (cl_beams_builtintexture.currentskinframe)
+               R_SkinFrame_MarkUsed(cl_beams_builtintexture.currentskinframe);
 }
 
 void R_LightningBeams_Init(void)
@@ -177,151 +107,90 @@ void R_LightningBeams_Init(void)
        R_RegisterModule("R_LightningBeams", r_lightningbeams_start, r_lightningbeams_shutdown, r_lightningbeams_newmap, NULL, NULL);
 }
 
-static void R_CalcLightningBeamPolygonVertex3f(float *v, const float *start, const float *end, const float *offset)
-{
-       // near right corner
-       VectorAdd     (start, offset, (v + 0));
-       // near left corner
-       VectorSubtract(start, offset, (v + 3));
-       // far left corner
-       VectorSubtract(end  , offset, (v + 6));
-       // far right corner
-       VectorAdd     (end  , offset, (v + 9));
-}
-
-static void R_CalcLightningBeamPolygonTexCoord2f(float *tc, float t1, float t2)
+static void CL_Beam_AddQuad(dp_model_t *mod, msurface_t *surf, const vec3_t start, const vec3_t end, const vec3_t offset, float t1, float t2)
 {
-       if (r_lightningbeam_qmbtexture.integer)
-       {
-               // near right corner
-               tc[0] = t1;tc[1] = 0;
-               // near left corner
-               tc[2] = t1;tc[3] = 1;
-               // far left corner
-               tc[4] = t2;tc[5] = 1;
-               // far right corner
-               tc[6] = t2;tc[7] = 0;
-       }
-       else
-       {
-               // near right corner
-               tc[0] = 0;tc[1] = t1;
-               // near left corner
-               tc[2] = 1;tc[3] = t1;
-               // far left corner
-               tc[4] = 1;tc[5] = t2;
-               // far right corner
-               tc[6] = 0;tc[7] = t2;
-       }
-}
-
-float beamrepeatscale;
-
-static void R_DrawLightningBeam_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
-{
-       int surfacelistindex;
-       float vertex3f[12*3];
-       float texcoord2f[12*2];
-
-       RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, r_lightningbeam_color_red.value, r_lightningbeam_color_green.value, r_lightningbeam_color_blue.value, 1, 12, vertex3f, texcoord2f, NULL, NULL, NULL, NULL, 6, r_lightningbeamelement3i, r_lightningbeamelement3s, false, false);
-
-       if (r_lightningbeam_qmbtexture.integer && r_lightningbeamqmbtexture == NULL)
-               r_lightningbeams_setupqmbtexture();
-       if (!r_lightningbeam_qmbtexture.integer && r_lightningbeamtexture == NULL)
-               r_lightningbeams_setuptexture();
-
-       for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
-       {
-               const beam_t *b = cl.beams + surfacelist[surfacelistindex];
-               vec3_t beamdir, right, up, offset, start, end;
-               float length, t1, t2;
-
-               CL_Beam_CalculatePositions(b, start, end);
-
-               // calculate beam direction (beamdir) vector and beam length
-               // get difference vector
-               VectorSubtract(end, start, beamdir);
-               // find length of difference vector
-               length = sqrt(DotProduct(beamdir, beamdir));
-               // calculate scale to make beamdir a unit vector (normalized)
-               t1 = 1.0f / length;
-               // scale beamdir so it is now normalized
-               VectorScale(beamdir, t1, beamdir);
-
-               // calculate up vector such that it points toward viewer, and rotates around the beamdir
-               // get direction from start of beam to viewer
-               VectorSubtract(r_refdef.view.origin, start, up);
-               // remove the portion of the vector that moves along the beam
-               // (this leaves only a vector pointing directly away from the beam)
-               t1 = -DotProduct(up, beamdir);
-               VectorMA(up, t1, beamdir, up);
-               // generate right vector from forward and up, the result is unnormalized
-               CrossProduct(beamdir, up, right);
-               // now normalize the right vector and up vector
-               VectorNormalize(right);
-               VectorNormalize(up);
-
-               // calculate T coordinate scrolling (start and end texcoord along the beam)
-               t1 = r_refdef.scene.time * -r_lightningbeam_scroll.value;// + beamrepeatscale * DotProduct(start, beamdir);
-               t1 = t1 - (int) t1;
-               t2 = t1 + beamrepeatscale * length;
-
-               // the beam is 3 polygons in this configuration:
-               //  *   2
-               //   * *
-               // 1******
-               //   * *
-               //  *   3
-               // they are showing different portions of the beam texture, creating an
-               // illusion of a beam that appears to curl around in 3D space
-               // (and realize that the whole polygon assembly orients itself to face
-               //  the viewer)
-
-               // polygon 1, verts 0-3
-               VectorScale(right, r_lightningbeam_thickness.value, offset);
-               R_CalcLightningBeamPolygonVertex3f(vertex3f + 0, start, end, offset);
-               // polygon 2, verts 4-7
-               VectorAdd(right, up, offset);
-               VectorScale(offset, r_lightningbeam_thickness.value * 0.70710681f, offset);
-               R_CalcLightningBeamPolygonVertex3f(vertex3f + 12, start, end, offset);
-               // polygon 3, verts 8-11
-               VectorSubtract(right, up, offset);
-               VectorScale(offset, r_lightningbeam_thickness.value * 0.70710681f, offset);
-               R_CalcLightningBeamPolygonVertex3f(vertex3f + 24, start, end, offset);
-               R_CalcLightningBeamPolygonTexCoord2f(texcoord2f + 0, t1, t2);
-               R_CalcLightningBeamPolygonTexCoord2f(texcoord2f + 8, t1 + 0.33, t2 + 0.33);
-               R_CalcLightningBeamPolygonTexCoord2f(texcoord2f + 16, t1 + 0.66, t2 + 0.66);
-
-               // draw the 3 polygons as one batch of 6 triangles using the 12 vertices
-               R_DrawCustomSurface(r_lightningbeam_qmbtexture.integer ? r_lightningbeamqmbtexture : r_lightningbeamtexture, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 12, 0, 6, false, false);
-       }
+       int e0, e1, e2, e3;
+       vec3_t n;
+       vec3_t dir;
+       float c[4];
+
+       Vector4Set(c, r_lightningbeam_color_red.value, r_lightningbeam_color_green.value, r_lightningbeam_color_blue.value, 1.0f);
+
+       VectorSubtract(end, start, dir);
+       CrossProduct(dir, offset, n);
+       VectorNormalize(n);
+
+       e0 = Mod_Mesh_IndexForVertex(mod, surf, start[0] + offset[0], start[1] + offset[1], start[2] + offset[2], n[0], n[1], n[2], t1, 0, 0, 0, c[0], c[1], c[2], c[3]);
+       e1 = Mod_Mesh_IndexForVertex(mod, surf, start[0] - offset[0], start[1] - offset[1], start[2] - offset[2], n[0], n[1], n[2], t1, 1, 0, 0, c[0], c[1], c[2], c[3]);
+       e2 = Mod_Mesh_IndexForVertex(mod, surf, end[0] - offset[0], end[1] - offset[1], end[2] - offset[2], n[0], n[1], n[2], t2, 1, 0, 0, c[0], c[1], c[2], c[3]);
+       e3 = Mod_Mesh_IndexForVertex(mod, surf, end[0] + offset[0], end[1] + offset[1], end[2] + offset[2], n[0], n[1], n[2], t2, 0, 0, 0, c[0], c[1], c[2], c[3]);
+       Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
+       Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
 }
 
-extern cvar_t cl_beams_polygons;
-void R_DrawLightningBeams(void)
+void CL_Beam_AddPolygons(const beam_t *b)
 {
-       int i;
-       beam_t *b;
-
-       if (!cl_beams_polygons.integer)
-               return;
-
-       beamrepeatscale = 1.0f / r_lightningbeam_repeatdistance.value;
-       for (i = 0, b = cl.beams;i < cl.num_beams;i++, b++)
-       {
-               if (b->model && b->lightning)
-               {
-                       vec3_t org, start, end, dir;
-                       vec_t dist;
-                       CL_Beam_CalculatePositions(b, start, end);
-                       // calculate the nearest point on the line (beam) for depth sorting
-                       VectorSubtract(end, start, dir);
-                       dist = (DotProduct(r_refdef.view.origin, dir) - DotProduct(start, dir)) / (DotProduct(end, dir) - DotProduct(start, dir));
-                       dist = bound(0, dist, 1);
-                       VectorLerp(start, dist, end, org);
-                       // now we have the nearest point on the line, so sort with it
-                       R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, org, R_DrawLightningBeam_TransparentCallback, NULL, i, NULL);
-               }
-       }
+       vec3_t beamdir, right, up, offset, start, end;
+       vec_t beamscroll = r_refdef.scene.time * -r_lightningbeam_scroll.value;
+       vec_t beamrepeatscale = 1.0f / r_lightningbeam_repeatdistance.value;
+       float length, t1, t2;
+       dp_model_t *mod;
+       msurface_t *surf;
+
+       if (r_lightningbeam_qmbtexture.integer && cl_beams_externaltexture.currentskinframe == NULL)
+               CL_Beams_SetupExternalTexture();
+       if (!r_lightningbeam_qmbtexture.integer && cl_beams_builtintexture.currentskinframe == NULL)
+               CL_Beams_SetupBuiltinTexture();
+
+       // calculate beam direction (beamdir) vector and beam length
+       // get difference vector
+       CL_Beam_CalculatePositions(b, start, end);
+       VectorSubtract(end, start, beamdir);
+       // find length of difference vector
+       length = sqrt(DotProduct(beamdir, beamdir));
+       // calculate scale to make beamdir a unit vector (normalized)
+       t1 = 1.0f / length;
+       // scale beamdir so it is now normalized
+       VectorScale(beamdir, t1, beamdir);
+
+       // calculate up vector such that it points toward viewer, and rotates around the beamdir
+       // get direction from start of beam to viewer
+       VectorSubtract(r_refdef.view.origin, start, up);
+       // remove the portion of the vector that moves along the beam
+       // (this leaves only a vector pointing directly away from the beam)
+       t1 = -DotProduct(up, beamdir);
+       VectorMA(up, t1, beamdir, up);
+       // generate right vector from forward and up, the result is unnormalized
+       CrossProduct(beamdir, up, right);
+       // now normalize the right vector and up vector
+       VectorNormalize(right);
+       VectorNormalize(up);
+
+       // calculate T coordinate scrolling (start and end texcoord along the beam)
+       t1 = beamscroll;
+       t1 = t1 - (int)t1;
+       t2 = t1 + beamrepeatscale * length;
+
+       // the beam is 3 polygons in this configuration:
+       //  *   2
+       //   * *
+       // 1*****
+       //   * *
+       //  *   3
+       // they are showing different portions of the beam texture, creating an
+       // illusion of a beam that appears to curl around in 3D space
+       // (and realize that the whole polygon assembly orients itself to face
+       //  the viewer)
+
+       mod = &cl_meshentitymodels[MESH_PARTICLES];
+       surf = Mod_Mesh_AddSurface(mod, r_lightningbeam_qmbtexture.integer ? &cl_beams_externaltexture : &cl_beams_builtintexture);
+       // polygon 1
+       VectorM(r_lightningbeam_thickness.value, right, offset);
+       CL_Beam_AddQuad(mod, surf, start, end, offset, t1, t2);
+       // polygon 2
+       VectorMAM(r_lightningbeam_thickness.value * 0.70710681f, right, r_lightningbeam_thickness.value * 0.70710681f, up, offset);
+       CL_Beam_AddQuad(mod, surf, start, end, offset, t1 + 0.33f, t2 + 0.33f);
+       // polygon 3
+       VectorMAM(r_lightningbeam_thickness.value * 0.70710681f, right, r_lightningbeam_thickness.value * -0.70710681f, up, offset);
+       CL_Beam_AddQuad(mod, surf, start, end, offset, t1 + 0.66f, t2 + 0.66f);
 }
-
index 82761cb..7fcadb3 100644 (file)
--- a/render.h
+++ b/render.h
@@ -613,7 +613,6 @@ void SCR_DrawConsole(void);
 void R_Shadow_EditLights_DrawSelectedLightProperties(void);
 void R_DecalSystem_Reset(decalsystem_t *decalsystem);
 void R_Shadow_UpdateBounceGridTexture(void);
-void R_DrawLightningBeams(void);
 void VM_CL_AddPolygonsToMeshQueue(struct prvm_prog_s *prog);
 void R_DrawPortals(void);
 void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);