1 #define MAXLIGHTNINGSTEPS 64
2 #define LIGHTNINGSTEP 8
3 int lnjitterx[2][MAXLIGHTNINGSTEPS], lnjittery[2][MAXLIGHTNINGSTEPS];
4 int lnjitterframe = 0, lastlnjitter = 0;
5 
6 VAR(IDF_PERSIST, lnjittermillis, 0, 100, 1000);
7 VAR(IDF_PERSIST, lnjitterradius, 0, 4, 100);
8 FVAR(IDF_PERSIST, lnjitterscale, 0, 0.5f, 10);
9 VAR(IDF_PERSIST, lnscrollmillis, 1, 300, 5000);
10 FVAR(IDF_PERSIST, lnscrollscale, 0, 0.125f, 10);
11 FVAR(IDF_PERSIST, lnblendpower, 0, 0.25f, 1000);
12 
calclightningjitter(int frame)13 static void calclightningjitter(int frame)
14 {
15     loopi(MAXLIGHTNINGSTEPS)
16     {
17         lnjitterx[lnjitterframe][i] = -lnjitterradius + rnd(2*lnjitterradius + 1);
18         lnjittery[lnjitterframe][i] = -lnjitterradius + rnd(2*lnjitterradius + 1);
19     }
20 }
21 
setuplightning()22 static void setuplightning()
23 {
24     if(!lastlnjitter || lastmillis-lastlnjitter > lnjittermillis)
25     {
26         if(!lastlnjitter) calclightningjitter(lnjitterframe);
27         lastlnjitter = lastmillis - (lastmillis%lnjittermillis);
28         calclightningjitter(lnjitterframe ^= 1);
29     }
30 }
31 
renderlightning(Texture * tex,const vec & o,const vec & d,float sz,const bvec4 & midcol,const bvec4 & endcol)32 static void renderlightning(Texture *tex, const vec &o, const vec &d, float sz, const bvec4 &midcol, const bvec4 &endcol)
33 {
34     vec step(d);
35     step.sub(o);
36     float len = step.magnitude();
37     int numsteps = clamp(int(ceil(len/LIGHTNINGSTEP)), 2, MAXLIGHTNINGSTEPS);
38     step.div(numsteps+1);
39     int jitteroffset = detrnd(int(d.x+d.y+d.z), MAXLIGHTNINGSTEPS);
40     vec cur(o), up, right;
41     up.orthogonal(step);
42     up.normalize();
43     right.cross(up, step);
44     right.normalize();
45     float scroll = -float(lastmillis%lnscrollmillis)/lnscrollmillis,
46           scrollscale = lnscrollscale*(LIGHTNINGSTEP*tex->ys)/(sz*tex->xs),
47           blend = pow(clamp(float(lastmillis - lastlnjitter)/lnjittermillis, 0.0f, 1.0f), lnblendpower),
48           jitter0 = (1-blend)*lnjitterscale*sz/lnjitterradius, jitter1 = blend*lnjitterscale*sz/lnjitterradius,
49           fadescale = sz/step.magnitude();
50     gle::begin(GL_TRIANGLE_STRIP);
51     loopj(numsteps)
52     {
53         vec next(cur);
54         next.add(step);
55         if(j+1==numsteps) next = d;
56         else
57         {
58             int lj = (j+jitteroffset)%MAXLIGHTNINGSTEPS;
59             next.add(vec(right).mul((jitter1*lnjitterx[lnjitterframe][lj] + jitter0*lnjitterx[lnjitterframe^1][lj])));
60             next.add(vec(up).mul((jitter1*lnjittery[lnjitterframe][lj] + jitter0*lnjittery[lnjitterframe^1][lj])));
61         }
62         vec dir1 = next, dir2 = next, across;
63         dir1.sub(cur);
64         dir2.sub(camera1->o);
65         across.cross(dir2, dir1).normalize().mul(sz);
66         if(!j)
67         {
68             vec start = vec(cur).sub(vec(step).mul(fadescale));
69             float startscroll = scroll - scrollscale*fadescale;
70             gle::attribf(start.x-across.x, start.y-across.y, start.z-across.z);
71                 gle::attribf(startscroll, 1); gle::attrib(endcol);
72             gle::attribf(start.x+across.x, start.y+across.y, start.z+across.z);
73                 gle::attribf(startscroll, 0); gle::attrib(endcol);
74         }
75         gle::attribf(cur.x-across.x, cur.y-across.y, cur.z-across.z);
76             gle::attribf(scroll, 1); gle::attrib(midcol);
77         gle::attribf(cur.x+across.x, cur.y+across.y, cur.z+across.z);
78             gle::attribf(scroll, 0); gle::attrib(midcol);
79         scroll += scrollscale;
80         if(j+1==numsteps)
81         {
82             gle::attribf(next.x-across.x, next.y-across.y, next.z-across.z);
83                 gle::attribf(scroll, 1); gle::attrib(midcol);
84             gle::attribf(next.x+across.x, next.y+across.y, next.z+across.z);
85                 gle::attribf(scroll, 0); gle::attrib(midcol);
86             vec end = vec(next).add(vec(step).mul(fadescale));
87             float endscroll = scroll + scrollscale*fadescale;
88             gle::attribf(end.x-across.x, end.y-across.y, end.z-across.z);
89                 gle::attribf(endscroll, 1); gle::attrib(endcol);
90             gle::attribf(end.x+across.x, end.y+across.y, end.z+across.z);
91                 gle::attribf(endscroll, 0); gle::attrib(endcol);
92         }
93         cur = next;
94     }
95     gle::end();
96 }
97 
98 struct lightningrenderer : sharedlistrenderer
99 {
lightningrendererlightningrenderer100     lightningrenderer(const char *texname)
101         : sharedlistrenderer(texname, 2, PT_LIGHTNING|PT_GLARE)
102     {}
103 
startrenderlightningrenderer104     void startrender()
105     {
106         glDisable(GL_CULL_FACE);
107         gle::defattrib(gle::ATTRIB_VERTEX, 3, GL_FLOAT);
108         gle::defattrib(gle::ATTRIB_TEXCOORD0, 2, GL_FLOAT);
109         gle::defattrib(gle::ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE);
110     }
111 
endrenderlightningrenderer112     void endrender()
113     {
114         glEnable(GL_CULL_FACE);
115     }
116 
updatelightningrenderer117     void update()
118     {
119         setuplightning();
120     }
121 
renderpartlightningrenderer122     void renderpart(sharedlistparticle *p, int blend, int ts, float size)
123     {
124         blend = int(min(blend<<2, 255)*p->blend);
125         bvec4 midcol, endcol;
126         if(type&PT_MOD) //multiply alpha into color
127         {
128             midcol = bvec4((p->color.r*blend)>>8, (p->color.g*blend)>>8, (p->color.b*blend)>>8, 0xFF);
129             endcol = bvec4(0, 0, 0, 0xFF);
130         }
131         else
132         {
133             midcol = bvec4(p->color, blend);
134             endcol = bvec4(p->color, 0);
135         }
136         renderlightning(tex, p->o, p->d, size, midcol, endcol);
137     }
138 };
139 static lightningrenderer lightnings("<grey>particles/lightning"), lightzaps("<grey>particles/lightzap");
140