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