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(lnjittermillis, 0, 100, 1000);
7 VAR(lnjitterradius, 0, 4, 100);
8 FVAR(lnjitterscale, 0, 0.5f, 10);
9 VAR(lnscrollmillis, 1, 300, 5000);
10 FVAR(lnscrollscale, 0, 0.125f, 10);
11 FVAR(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)32 static void renderlightning(Texture *tex, const vec &o, const vec &d, float sz)
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     gle::begin(GL_TRIANGLE_STRIP);
50     loopj(numsteps)
51     {
52         vec next(cur);
53         next.add(step);
54         if(j+1==numsteps) next = d;
55         else
56         {
57             int lj = (j+jitteroffset)%MAXLIGHTNINGSTEPS;
58             next.add(vec(right).mul((jitter1*lnjitterx[lnjitterframe][lj] + jitter0*lnjitterx[lnjitterframe^1][lj])));
59             next.add(vec(up).mul((jitter1*lnjittery[lnjitterframe][lj] + jitter0*lnjittery[lnjitterframe^1][lj])));
60         }
61         vec dir1 = next, dir2 = next, across;
62         dir1.sub(cur);
63         dir2.sub(camera1->o);
64         across.cross(dir2, dir1).normalize().mul(sz);
65         gle::attribf(cur.x-across.x, cur.y-across.y, cur.z-across.z);
66             gle::attribf(scroll, 1);
67         gle::attribf(cur.x+across.x, cur.y+across.y, cur.z+across.z);
68             gle::attribf(scroll, 0);
69         scroll += scrollscale;
70         if(j+1==numsteps)
71         {
72             gle::attribf(next.x-across.x, next.y-across.y, next.z-across.z);
73                 gle::attribf(scroll, 1);
74             gle::attribf(next.x+across.x, next.y+across.y, next.z+across.z);
75                 gle::attribf(scroll, 0);
76         }
77         cur = next;
78     }
79     gle::end();
80 }
81 
82 struct lightningrenderer : listrenderer
83 {
lightningrendererlightningrenderer84     lightningrenderer()
85         : listrenderer("packages/particles/lightning.jpg", 2, PT_LIGHTNING|PT_TRACK|PT_GLARE)
86     {}
87 
startrenderlightningrenderer88     void startrender()
89     {
90         glDisable(GL_CULL_FACE);
91         gle::defattrib(gle::ATTRIB_VERTEX, 3, GL_FLOAT);
92         gle::defattrib(gle::ATTRIB_TEXCOORD0, 2, GL_FLOAT);
93     }
94 
endrenderlightningrenderer95     void endrender()
96     {
97         glEnable(GL_CULL_FACE);
98     }
99 
updatelightningrenderer100     void update()
101     {
102         setuplightning();
103     }
104 
seedemitterlightningrenderer105     void seedemitter(particleemitter &pe, const vec &o, const vec &d, int fade, float size, int gravity)
106     {
107         pe.maxfade = max(pe.maxfade, fade);
108         pe.extendbb(o, size);
109         pe.extendbb(d, size);
110     }
111 
renderpartlightningrenderer112     void renderpart(listparticle *p, const vec &o, const vec &d, int blend, int ts)
113     {
114         blend = min(blend<<2, 255);
115         if(type&PT_MOD) //multiply alpha into color
116             gle::colorub((p->color.r*blend)>>8, (p->color.g*blend)>>8, (p->color.b*blend)>>8);
117         else
118             gle::color(p->color, blend);
119         renderlightning(tex, o, d, p->size);
120     }
121 };
122 static lightningrenderer lightnings;
123 
124