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