aboutsummaryrefslogtreecommitdiff
path: root/libs/moonshine/fog.lua
blob: 9c90f9a39297375f5cc9b1b83fb5aa838dc36462 (plain)
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
124
125
126
127
128
129
--[[
Animated 2D Fog (procedural)
Originally for Godot Engine by Gonkee https://www.youtube.com/watch?v=QEaTsz_0o44&t=6s

Translated for löve by Brandon Blanker Lim-it @flamendless
]]--

--[[
SAMPLE USAGE:
local moonshine = require("moonshine")
local effect

local image, bg
local image_data
local shader_fog
local time = 0

function love.load()
	image_data = love.image.newImageData(love.graphics.getWidth(), love.graphics.getHeight())
	image = love.graphics.newImage(image_data)
	bg = love.graphics.newImage("bg.png")
	effect = moonshine(moonshine.effects.fog)
	effect.fog.fog_color = {0.1, 0.0, 0.0}
	effect.fog.speed = {0.2, 0.9}
end

function love.update(dt)
	time = time + dt
	effect.fog.time = time
end

function love.draw()
	love.graphics.draw(bg)
	effect(function()
		love.graphics.draw(image)
	end)
end
]]

return function(moonshine)
	local fog_color
	local octaves
	local speed
	local time

	local shader = love.graphics.newShader([[
		extern vec3 fog_color = vec3(0.35, 0.48, 0.95);
		extern int octaves = 4;
		extern vec2 speed = vec2(0.0, 1.0);
		extern float time;

		float rand(vec2 coord)
		{
			return fract(sin(dot(coord, vec2(56, 78)) * 1000.0) * 1000.0);
		}

		float noise(vec2 coord)
		{
			vec2 i = floor(coord); //get the whole number
			vec2 f = fract(coord); //get the fraction number
			float a = rand(i); //top-left
			float b = rand(i + vec2(1.0, 0.0)); //top-right
			float c = rand(i + vec2(0.0, 1.0)); //bottom-left
			float d = rand(i + vec2(1.0, 1.0)); //bottom-right
			vec2 cubic = f * f * (3.0 - 2.0 * f);
			return mix(a, b, cubic.x) + (c - a) * cubic.y * (1.0 - cubic.x) + (d - b) * cubic.x * cubic.y; //interpolate
		}

		float fbm(vec2 coord) //fractal brownian motion
		{
			float value = 0.0;
			float scale = 0.5;
			for (int i = 0; i < octaves; i++)
			{
				value += noise(coord) * scale;
				coord *= 2.0;
				scale *= 0.5;
			}
			return value;
		}

		vec4 effect(vec4 color, Image texture, vec2 tc, vec2 sc)
		{
			vec2 coord = tc * 20.0;
			vec2 motion = vec2(fbm(coord + vec2(time * speed.x, time * speed.y)));
			float final = fbm(coord + motion);
			return vec4(fog_color, final * 0.5);
		}
	]])

	local setters = {}

	setters.fog_color = function(t)
		assert(type(t) == "table", "Passed argument to fog_color must be a table containing 3 color values")
		fog_color = t
		shader:send("fog_color", fog_color)
	end

	setters.octaves = function(i)
		assert(type(i) == "number", "Passed argument to octaves must be an integer")
		octaves = i
		shader:send("octaves", octaves)
	end

	setters.speed = function(t)
		assert(type(t) == "table", "Passed argument to speed must be a table containing 2 values")
		speed = t
		shader:send("speed", speed)
	end

	setters.time = function(n)
		assert(type(n) == "number", "Passed argument to time must be a number")
		time = n
		shader:send("time", time)
	end

	local defaults = {
		fog_color = {0.35, 0.48, 0.95},
		octaves = 4,
		speed = {0.5, 0.5},
	}

	return moonshine.Effect({
		name = "fog",
		shader = shader,
		setters = setters,
		defaults = defaults,
	})
end