summaryrefslogtreecommitdiff
path: root/src/engine/lightning.h
blob: cec993ab6cdade33bc760e49de9800f5fdaa8814 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#define MAXLIGHTNINGSTEPS 64
#define LIGHTNINGSTEP 8
int lnjitterx[2][MAXLIGHTNINGSTEPS], lnjittery[2][MAXLIGHTNINGSTEPS];
int lnjitterframe = 0, lastlnjitter = 0;

VAR(lnjittermillis, 0, 100, 1000);
VAR(lnjitterradius, 0, 4, 100);
FVAR(lnjitterscale, 0, 0.5f, 10);
VAR(lnscrollmillis, 1, 300, 5000);
FVAR(lnscrollscale, 0, 0.125f, 10);
FVAR(lnblendpower, 0, 0.25f, 1000);

static void calclightningjitter(int frame)
{
	loopi(MAXLIGHTNINGSTEPS)
	{
		lnjitterx[lnjitterframe][i] = -lnjitterradius + rnd(2*lnjitterradius + 1);
		lnjittery[lnjitterframe][i] = -lnjitterradius + rnd(2*lnjitterradius + 1);
	}
}

static void setuplightning()
{
	if(!lastlnjitter || lastmillis-lastlnjitter > lnjittermillis)
	{
		if(!lastlnjitter) calclightningjitter(lnjitterframe);
		lastlnjitter = lastmillis - (lastmillis%lnjittermillis);
		calclightningjitter(lnjitterframe ^= 1);
	}
}

static void renderlightning(Texture *tex, const vec &o, const vec &d, float sz)
{
	vec step(d);
	step.sub(o);
	float len = step.magnitude();
	int numsteps = clamp(int(ceil(len/LIGHTNINGSTEP)), 2, MAXLIGHTNINGSTEPS);
	step.div(numsteps+1);
	int jitteroffset = detrnd(int(d.x+d.y+d.z), MAXLIGHTNINGSTEPS);
	vec cur(o), up, right;
	up.orthogonal(step);
	up.normalize();
	right.cross(up, step);
	right.normalize();
	float scroll = -float(lastmillis%lnscrollmillis)/lnscrollmillis,
		  scrollscale = lnscrollscale*(LIGHTNINGSTEP*tex->ys)/(sz*tex->xs),
		  blend = pow(clamp(float(lastmillis - lastlnjitter)/lnjittermillis, 0.0f, 1.0f), lnblendpower),
		  jitter0 = (1-blend)*lnjitterscale*sz/lnjitterradius, jitter1 = blend*lnjitterscale*sz/lnjitterradius;
	gle::begin(GL_TRIANGLE_STRIP);
	loopj(numsteps)
	{
		vec next(cur);
		next.add(step);
		if(j+1==numsteps) next = d;
		else
		{
			int lj = (j+jitteroffset)%MAXLIGHTNINGSTEPS;
			next.add(vec(right).mul((jitter1*lnjitterx[lnjitterframe][lj] + jitter0*lnjitterx[lnjitterframe^1][lj])));
			next.add(vec(up).mul((jitter1*lnjittery[lnjitterframe][lj] + jitter0*lnjittery[lnjitterframe^1][lj])));
		}
		vec dir1 = next, dir2 = next, across;
		dir1.sub(cur);
		dir2.sub(camera1->o);
		across.cross(dir2, dir1).normalize().mul(sz);
		gle::attribf(cur.x-across.x, cur.y-across.y, cur.z-across.z);
			gle::attribf(scroll, 1);
		gle::attribf(cur.x+across.x, cur.y+across.y, cur.z+across.z);
			gle::attribf(scroll, 0);
		scroll += scrollscale;
		if(j+1==numsteps)
		{
			gle::attribf(next.x-across.x, next.y-across.y, next.z-across.z);
				gle::attribf(scroll, 1);
			gle::attribf(next.x+across.x, next.y+across.y, next.z+across.z);
				gle::attribf(scroll, 0);
		}
		cur = next;
	}
	gle::end();
}

struct lightningrenderer : listrenderer
{
	lightningrenderer()
		: listrenderer("packages/particles/lightning.png", 2, PT_LIGHTNING|PT_TRACK|PT_GLARE)
	{}

	void startrender()
	{
		glDisable(GL_CULL_FACE);
		gle::defattrib(gle::ATTRIB_VERTEX, 3, GL_FLOAT);
		gle::defattrib(gle::ATTRIB_TEXCOORD0, 2, GL_FLOAT);
	}

	void endrender()
	{
		glEnable(GL_CULL_FACE);
	}

	void update()
	{
		setuplightning();
	}

	void seedemitter(particleemitter &pe, const vec &o, const vec &d, int fade, float size, int gravity)
	{
		pe.maxfade = max(pe.maxfade, fade);
		pe.extendbb(o, size);
		pe.extendbb(d, size);
	}

	void renderpart(listparticle *p, const vec &o, const vec &d, int blend, int ts)
	{
		blend = min(blend<<2, 255);
		if(type&PT_MOD) //multiply alpha into color
			gle::colorub((p->color.r*blend)>>8, (p->color.g*blend)>>8, (p->color.b*blend)>>8);
		else
			gle::color(p->color, blend);
		renderlightning(tex, o, d, p->size);
	}
};
static lightningrenderer lightnings;