--- /dev/null
+
+src = $(wildcard src/*.cc)
+c_src = $(wildcard src/*.c)
+obj = $(src:.cc=.o) $(c_src:.c=.o)
+dep = $(obj:.o=.d)
+bin = faros
+
+dbg = -g
+opt = -O0
+inc = -Isrc -Isrc/shaders -Isrc/math
+
+CXX = g++
+CC = gcc
+CXXFLAGS = -pedantic -Wall $(dbg) $(opt) $(inc)
+CFLAGS = $(CXXFLAGS)
+LDFLAGS = -lGL -lGLU -lglut -lGLEW -limago -lassimp
+
+$(bin): $(obj)
+ $(CXX) -o $@ $(obj) $(LDFLAGS)
+
+-include $(dep)
+
+%.d: %.cc
+ @$(CPP) $(CXXFLAGS) $< -MM -MT $(@:.d=.o) >$@
+
+.PHONY: clean
+clean:
+ rm -f $(obj) $(bin) $(dep)
--- /dev/null
+Copyright (C) 2011 by Ashima Arts (Simplex noise)
+Copyright (C) 2011 by Stefan Gustavson (Classic noise)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
--- /dev/null
+# glsl-noise [![frozen](http://hughsk.github.io/stability-badges/dist/frozen.svg)](http://github.com/hughsk/stability-badges) #
+
+[webgl-noise](http://github.com/ashima/webgl-noise) ported to an NPM package
+so that you can require it from
+[glslify](http://github.com/chrisdickinson/glslify).
+
+[![glsl-noise](https://nodei.co/npm/glsl-noise.png?mini=true)](https://nodei.co/npm/glsl-noise)
+
+## Usage ##
+
+``` glsl
+// Require as many or as little as you need:
+#pragma glslify: snoise2 = require(glsl-noise/simplex/2d)
+#pragma glslify: snoise3 = require(glsl-noise/simplex/3d)
+#pragma glslify: snoise4 = require(glsl-noise/simplex/4d)
+#pragma glslify: cnoise2 = require(glsl-noise/classic/2d)
+#pragma glslify: cnoise3 = require(glsl-noise/classic/3d)
+#pragma glslify: cnoise4 = require(glsl-noise/classic/4d)
+#pragma glslify: pnoise2 = require(glsl-noise/periodic/2d)
+#pragma glslify: pnoise3 = require(glsl-noise/periodic/3d)
+#pragma glslify: pnoise4 = require(glsl-noise/periodic/4d)
+
+attribute vec3 position;
+
+// And just treat them as functions like
+// you normally would:
+void main() {
+ gl_FragColor = vec4(snoise3(position), 1.0);
+}
+```
--- /dev/null
+//
+// GLSL textureless classic 2D noise "cnoise",
+// with an RSL-style periodic variant "pnoise".
+// Author: Stefan Gustavson (stefan.gustavson@liu.se)
+// Version: 2011-08-22
+//
+// Many thanks to Ian McEwan of Ashima Arts for the
+// ideas for permutation and gradient selection.
+//
+// Copyright (c) 2011 Stefan Gustavson. All rights reserved.
+// Distributed under the MIT license. See LICENSE file.
+// https://github.com/ashima/webgl-noise
+//
+
+vec4 mod289(vec4 x)
+{
+ return x - floor(x * (1.0 / 289.0)) * 289.0;
+}
+
+vec4 permute(vec4 x)
+{
+ return mod289(((x*34.0)+1.0)*x);
+}
+
+vec4 taylorInvSqrt(vec4 r)
+{
+ return 1.79284291400159 - 0.85373472095314 * r;
+}
+
+vec2 fade(vec2 t) {
+ return t*t*t*(t*(t*6.0-15.0)+10.0);
+}
+
+// Classic Perlin noise
+float cnoise(vec2 P)
+{
+ vec4 Pi = floor(P.xyxy) + vec4(0.0, 0.0, 1.0, 1.0);
+ vec4 Pf = fract(P.xyxy) - vec4(0.0, 0.0, 1.0, 1.0);
+ Pi = mod289(Pi); // To avoid truncation effects in permutation
+ vec4 ix = Pi.xzxz;
+ vec4 iy = Pi.yyww;
+ vec4 fx = Pf.xzxz;
+ vec4 fy = Pf.yyww;
+
+ vec4 i = permute(permute(ix) + iy);
+
+ vec4 gx = fract(i * (1.0 / 41.0)) * 2.0 - 1.0 ;
+ vec4 gy = abs(gx) - 0.5 ;
+ vec4 tx = floor(gx + 0.5);
+ gx = gx - tx;
+
+ vec2 g00 = vec2(gx.x,gy.x);
+ vec2 g10 = vec2(gx.y,gy.y);
+ vec2 g01 = vec2(gx.z,gy.z);
+ vec2 g11 = vec2(gx.w,gy.w);
+
+ vec4 norm = taylorInvSqrt(vec4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11)));
+ g00 *= norm.x;
+ g01 *= norm.y;
+ g10 *= norm.z;
+ g11 *= norm.w;
+
+ float n00 = dot(g00, vec2(fx.x, fy.x));
+ float n10 = dot(g10, vec2(fx.y, fy.y));
+ float n01 = dot(g01, vec2(fx.z, fy.z));
+ float n11 = dot(g11, vec2(fx.w, fy.w));
+
+ vec2 fade_xy = fade(Pf.xy);
+ vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade_xy.x);
+ float n_xy = mix(n_x.x, n_x.y, fade_xy.y);
+ return 2.3 * n_xy;
+}
+
+#pragma glslify: export(cnoise)
--- /dev/null
+//
+// GLSL textureless classic 3D noise "cnoise",
+// with an RSL-style periodic variant "pnoise".
+// Author: Stefan Gustavson (stefan.gustavson@liu.se)
+// Version: 2011-10-11
+//
+// Many thanks to Ian McEwan of Ashima Arts for the
+// ideas for permutation and gradient selection.
+//
+// Copyright (c) 2011 Stefan Gustavson. All rights reserved.
+// Distributed under the MIT license. See LICENSE file.
+// https://github.com/ashima/webgl-noise
+//
+
+vec3 mod289(vec3 x)
+{
+ return x - floor(x * (1.0 / 289.0)) * 289.0;
+}
+
+vec4 mod289(vec4 x)
+{
+ return x - floor(x * (1.0 / 289.0)) * 289.0;
+}
+
+vec4 permute(vec4 x)
+{
+ return mod289(((x*34.0)+1.0)*x);
+}
+
+vec4 taylorInvSqrt(vec4 r)
+{
+ return 1.79284291400159 - 0.85373472095314 * r;
+}
+
+vec3 fade(vec3 t) {
+ return t*t*t*(t*(t*6.0-15.0)+10.0);
+}
+
+// Classic Perlin noise
+float cnoise(vec3 P)
+{
+ vec3 Pi0 = floor(P); // Integer part for indexing
+ vec3 Pi1 = Pi0 + vec3(1.0); // Integer part + 1
+ Pi0 = mod289(Pi0);
+ Pi1 = mod289(Pi1);
+ vec3 Pf0 = fract(P); // Fractional part for interpolation
+ vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0
+ vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
+ vec4 iy = vec4(Pi0.yy, Pi1.yy);
+ vec4 iz0 = Pi0.zzzz;
+ vec4 iz1 = Pi1.zzzz;
+
+ vec4 ixy = permute(permute(ix) + iy);
+ vec4 ixy0 = permute(ixy + iz0);
+ vec4 ixy1 = permute(ixy + iz1);
+
+ vec4 gx0 = ixy0 * (1.0 / 7.0);
+ vec4 gy0 = fract(floor(gx0) * (1.0 / 7.0)) - 0.5;
+ gx0 = fract(gx0);
+ vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0);
+ vec4 sz0 = step(gz0, vec4(0.0));
+ gx0 -= sz0 * (step(0.0, gx0) - 0.5);
+ gy0 -= sz0 * (step(0.0, gy0) - 0.5);
+
+ vec4 gx1 = ixy1 * (1.0 / 7.0);
+ vec4 gy1 = fract(floor(gx1) * (1.0 / 7.0)) - 0.5;
+ gx1 = fract(gx1);
+ vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1);
+ vec4 sz1 = step(gz1, vec4(0.0));
+ gx1 -= sz1 * (step(0.0, gx1) - 0.5);
+ gy1 -= sz1 * (step(0.0, gy1) - 0.5);
+
+ vec3 g000 = vec3(gx0.x,gy0.x,gz0.x);
+ vec3 g100 = vec3(gx0.y,gy0.y,gz0.y);
+ vec3 g010 = vec3(gx0.z,gy0.z,gz0.z);
+ vec3 g110 = vec3(gx0.w,gy0.w,gz0.w);
+ vec3 g001 = vec3(gx1.x,gy1.x,gz1.x);
+ vec3 g101 = vec3(gx1.y,gy1.y,gz1.y);
+ vec3 g011 = vec3(gx1.z,gy1.z,gz1.z);
+ vec3 g111 = vec3(gx1.w,gy1.w,gz1.w);
+
+ vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));
+ g000 *= norm0.x;
+ g010 *= norm0.y;
+ g100 *= norm0.z;
+ g110 *= norm0.w;
+ vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));
+ g001 *= norm1.x;
+ g011 *= norm1.y;
+ g101 *= norm1.z;
+ g111 *= norm1.w;
+
+ float n000 = dot(g000, Pf0);
+ float n100 = dot(g100, vec3(Pf1.x, Pf0.yz));
+ float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z));
+ float n110 = dot(g110, vec3(Pf1.xy, Pf0.z));
+ float n001 = dot(g001, vec3(Pf0.xy, Pf1.z));
+ float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z));
+ float n011 = dot(g011, vec3(Pf0.x, Pf1.yz));
+ float n111 = dot(g111, Pf1);
+
+ vec3 fade_xyz = fade(Pf0);
+ vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z);
+ vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y);
+ float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x);
+ return 2.2 * n_xyz;
+}
+
+#pragma glslify: export(cnoise)
--- /dev/null
+//
+// GLSL textureless classic 4D noise "cnoise",
+// with an RSL-style periodic variant "pnoise".
+// Author: Stefan Gustavson (stefan.gustavson@liu.se)
+// Version: 2011-08-22
+//
+// Many thanks to Ian McEwan of Ashima Arts for the
+// ideas for permutation and gradient selection.
+//
+// Copyright (c) 2011 Stefan Gustavson. All rights reserved.
+// Distributed under the MIT license. See LICENSE file.
+// https://github.com/ashima/webgl-noise
+//
+
+vec4 mod289(vec4 x)
+{
+ return x - floor(x * (1.0 / 289.0)) * 289.0;
+}
+
+vec4 permute(vec4 x)
+{
+ return mod289(((x*34.0)+1.0)*x);
+}
+
+vec4 taylorInvSqrt(vec4 r)
+{
+ return 1.79284291400159 - 0.85373472095314 * r;
+}
+
+vec4 fade(vec4 t) {
+ return t*t*t*(t*(t*6.0-15.0)+10.0);
+}
+
+// Classic Perlin noise
+float cnoise(vec4 P)
+{
+ vec4 Pi0 = floor(P); // Integer part for indexing
+ vec4 Pi1 = Pi0 + 1.0; // Integer part + 1
+ Pi0 = mod289(Pi0);
+ Pi1 = mod289(Pi1);
+ vec4 Pf0 = fract(P); // Fractional part for interpolation
+ vec4 Pf1 = Pf0 - 1.0; // Fractional part - 1.0
+ vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
+ vec4 iy = vec4(Pi0.yy, Pi1.yy);
+ vec4 iz0 = vec4(Pi0.zzzz);
+ vec4 iz1 = vec4(Pi1.zzzz);
+ vec4 iw0 = vec4(Pi0.wwww);
+ vec4 iw1 = vec4(Pi1.wwww);
+
+ vec4 ixy = permute(permute(ix) + iy);
+ vec4 ixy0 = permute(ixy + iz0);
+ vec4 ixy1 = permute(ixy + iz1);
+ vec4 ixy00 = permute(ixy0 + iw0);
+ vec4 ixy01 = permute(ixy0 + iw1);
+ vec4 ixy10 = permute(ixy1 + iw0);
+ vec4 ixy11 = permute(ixy1 + iw1);
+
+ vec4 gx00 = ixy00 * (1.0 / 7.0);
+ vec4 gy00 = floor(gx00) * (1.0 / 7.0);
+ vec4 gz00 = floor(gy00) * (1.0 / 6.0);
+ gx00 = fract(gx00) - 0.5;
+ gy00 = fract(gy00) - 0.5;
+ gz00 = fract(gz00) - 0.5;
+ vec4 gw00 = vec4(0.75) - abs(gx00) - abs(gy00) - abs(gz00);
+ vec4 sw00 = step(gw00, vec4(0.0));
+ gx00 -= sw00 * (step(0.0, gx00) - 0.5);
+ gy00 -= sw00 * (step(0.0, gy00) - 0.5);
+
+ vec4 gx01 = ixy01 * (1.0 / 7.0);
+ vec4 gy01 = floor(gx01) * (1.0 / 7.0);
+ vec4 gz01 = floor(gy01) * (1.0 / 6.0);
+ gx01 = fract(gx01) - 0.5;
+ gy01 = fract(gy01) - 0.5;
+ gz01 = fract(gz01) - 0.5;
+ vec4 gw01 = vec4(0.75) - abs(gx01) - abs(gy01) - abs(gz01);
+ vec4 sw01 = step(gw01, vec4(0.0));
+ gx01 -= sw01 * (step(0.0, gx01) - 0.5);
+ gy01 -= sw01 * (step(0.0, gy01) - 0.5);
+
+ vec4 gx10 = ixy10 * (1.0 / 7.0);
+ vec4 gy10 = floor(gx10) * (1.0 / 7.0);
+ vec4 gz10 = floor(gy10) * (1.0 / 6.0);
+ gx10 = fract(gx10) - 0.5;
+ gy10 = fract(gy10) - 0.5;
+ gz10 = fract(gz10) - 0.5;
+ vec4 gw10 = vec4(0.75) - abs(gx10) - abs(gy10) - abs(gz10);
+ vec4 sw10 = step(gw10, vec4(0.0));
+ gx10 -= sw10 * (step(0.0, gx10) - 0.5);
+ gy10 -= sw10 * (step(0.0, gy10) - 0.5);
+
+ vec4 gx11 = ixy11 * (1.0 / 7.0);
+ vec4 gy11 = floor(gx11) * (1.0 / 7.0);
+ vec4 gz11 = floor(gy11) * (1.0 / 6.0);
+ gx11 = fract(gx11) - 0.5;
+ gy11 = fract(gy11) - 0.5;
+ gz11 = fract(gz11) - 0.5;
+ vec4 gw11 = vec4(0.75) - abs(gx11) - abs(gy11) - abs(gz11);
+ vec4 sw11 = step(gw11, vec4(0.0));
+ gx11 -= sw11 * (step(0.0, gx11) - 0.5);
+ gy11 -= sw11 * (step(0.0, gy11) - 0.5);
+
+ vec4 g0000 = vec4(gx00.x,gy00.x,gz00.x,gw00.x);
+ vec4 g1000 = vec4(gx00.y,gy00.y,gz00.y,gw00.y);
+ vec4 g0100 = vec4(gx00.z,gy00.z,gz00.z,gw00.z);
+ vec4 g1100 = vec4(gx00.w,gy00.w,gz00.w,gw00.w);
+ vec4 g0010 = vec4(gx10.x,gy10.x,gz10.x,gw10.x);
+ vec4 g1010 = vec4(gx10.y,gy10.y,gz10.y,gw10.y);
+ vec4 g0110 = vec4(gx10.z,gy10.z,gz10.z,gw10.z);
+ vec4 g1110 = vec4(gx10.w,gy10.w,gz10.w,gw10.w);
+ vec4 g0001 = vec4(gx01.x,gy01.x,gz01.x,gw01.x);
+ vec4 g1001 = vec4(gx01.y,gy01.y,gz01.y,gw01.y);
+ vec4 g0101 = vec4(gx01.z,gy01.z,gz01.z,gw01.z);
+ vec4 g1101 = vec4(gx01.w,gy01.w,gz01.w,gw01.w);
+ vec4 g0011 = vec4(gx11.x,gy11.x,gz11.x,gw11.x);
+ vec4 g1011 = vec4(gx11.y,gy11.y,gz11.y,gw11.y);
+ vec4 g0111 = vec4(gx11.z,gy11.z,gz11.z,gw11.z);
+ vec4 g1111 = vec4(gx11.w,gy11.w,gz11.w,gw11.w);
+
+ vec4 norm00 = taylorInvSqrt(vec4(dot(g0000, g0000), dot(g0100, g0100), dot(g1000, g1000), dot(g1100, g1100)));
+ g0000 *= norm00.x;
+ g0100 *= norm00.y;
+ g1000 *= norm00.z;
+ g1100 *= norm00.w;
+
+ vec4 norm01 = taylorInvSqrt(vec4(dot(g0001, g0001), dot(g0101, g0101), dot(g1001, g1001), dot(g1101, g1101)));
+ g0001 *= norm01.x;
+ g0101 *= norm01.y;
+ g1001 *= norm01.z;
+ g1101 *= norm01.w;
+
+ vec4 norm10 = taylorInvSqrt(vec4(dot(g0010, g0010), dot(g0110, g0110), dot(g1010, g1010), dot(g1110, g1110)));
+ g0010 *= norm10.x;
+ g0110 *= norm10.y;
+ g1010 *= norm10.z;
+ g1110 *= norm10.w;
+
+ vec4 norm11 = taylorInvSqrt(vec4(dot(g0011, g0011), dot(g0111, g0111), dot(g1011, g1011), dot(g1111, g1111)));
+ g0011 *= norm11.x;
+ g0111 *= norm11.y;
+ g1011 *= norm11.z;
+ g1111 *= norm11.w;
+
+ float n0000 = dot(g0000, Pf0);
+ float n1000 = dot(g1000, vec4(Pf1.x, Pf0.yzw));
+ float n0100 = dot(g0100, vec4(Pf0.x, Pf1.y, Pf0.zw));
+ float n1100 = dot(g1100, vec4(Pf1.xy, Pf0.zw));
+ float n0010 = dot(g0010, vec4(Pf0.xy, Pf1.z, Pf0.w));
+ float n1010 = dot(g1010, vec4(Pf1.x, Pf0.y, Pf1.z, Pf0.w));
+ float n0110 = dot(g0110, vec4(Pf0.x, Pf1.yz, Pf0.w));
+ float n1110 = dot(g1110, vec4(Pf1.xyz, Pf0.w));
+ float n0001 = dot(g0001, vec4(Pf0.xyz, Pf1.w));
+ float n1001 = dot(g1001, vec4(Pf1.x, Pf0.yz, Pf1.w));
+ float n0101 = dot(g0101, vec4(Pf0.x, Pf1.y, Pf0.z, Pf1.w));
+ float n1101 = dot(g1101, vec4(Pf1.xy, Pf0.z, Pf1.w));
+ float n0011 = dot(g0011, vec4(Pf0.xy, Pf1.zw));
+ float n1011 = dot(g1011, vec4(Pf1.x, Pf0.y, Pf1.zw));
+ float n0111 = dot(g0111, vec4(Pf0.x, Pf1.yzw));
+ float n1111 = dot(g1111, Pf1);
+
+ vec4 fade_xyzw = fade(Pf0);
+ vec4 n_0w = mix(vec4(n0000, n1000, n0100, n1100), vec4(n0001, n1001, n0101, n1101), fade_xyzw.w);
+ vec4 n_1w = mix(vec4(n0010, n1010, n0110, n1110), vec4(n0011, n1011, n0111, n1111), fade_xyzw.w);
+ vec4 n_zw = mix(n_0w, n_1w, fade_xyzw.z);
+ vec2 n_yzw = mix(n_zw.xy, n_zw.zw, fade_xyzw.y);
+ float n_xyzw = mix(n_yzw.x, n_yzw.y, fade_xyzw.x);
+ return 2.2 * n_xyzw;
+}
+
+#pragma glslify: export(cnoise)
--- /dev/null
+{
+ "name": "glsl-noise",
+ "version": "0.0.0",
+ "description": "webgl-noise shaders ported to work with glslify",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/hughsk/glsl-noise.git"
+ },
+ "keywords": [
+ "glsl",
+ "noise",
+ "shader",
+ "perlin",
+ "simplex",
+ "webgl",
+ "glslify"
+ ],
+ "author": "Ian McEwan, Ashima Arts, Stefan Gustavson",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/hughsk/glsl-noise/issues"
+ }
+}
--- /dev/null
+//
+// GLSL textureless classic 2D noise "cnoise",
+// with an RSL-style periodic variant "pnoise".
+// Author: Stefan Gustavson (stefan.gustavson@liu.se)
+// Version: 2011-08-22
+//
+// Many thanks to Ian McEwan of Ashima Arts for the
+// ideas for permutation and gradient selection.
+//
+// Copyright (c) 2011 Stefan Gustavson. All rights reserved.
+// Distributed under the MIT license. See LICENSE file.
+// https://github.com/ashima/webgl-noise
+//
+
+vec4 mod289(vec4 x)
+{
+ return x - floor(x * (1.0 / 289.0)) * 289.0;
+}
+
+vec4 permute(vec4 x)
+{
+ return mod289(((x*34.0)+1.0)*x);
+}
+
+vec4 taylorInvSqrt(vec4 r)
+{
+ return 1.79284291400159 - 0.85373472095314 * r;
+}
+
+vec2 fade(vec2 t) {
+ return t*t*t*(t*(t*6.0-15.0)+10.0);
+}
+
+// Classic Perlin noise, periodic variant
+float pnoise(vec2 P, vec2 rep)
+{
+ vec4 Pi = floor(P.xyxy) + vec4(0.0, 0.0, 1.0, 1.0);
+ vec4 Pf = fract(P.xyxy) - vec4(0.0, 0.0, 1.0, 1.0);
+ Pi = mod(Pi, rep.xyxy); // To create noise with explicit period
+ Pi = mod289(Pi); // To avoid truncation effects in permutation
+ vec4 ix = Pi.xzxz;
+ vec4 iy = Pi.yyww;
+ vec4 fx = Pf.xzxz;
+ vec4 fy = Pf.yyww;
+
+ vec4 i = permute(permute(ix) + iy);
+
+ vec4 gx = fract(i * (1.0 / 41.0)) * 2.0 - 1.0 ;
+ vec4 gy = abs(gx) - 0.5 ;
+ vec4 tx = floor(gx + 0.5);
+ gx = gx - tx;
+
+ vec2 g00 = vec2(gx.x,gy.x);
+ vec2 g10 = vec2(gx.y,gy.y);
+ vec2 g01 = vec2(gx.z,gy.z);
+ vec2 g11 = vec2(gx.w,gy.w);
+
+ vec4 norm = taylorInvSqrt(vec4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11)));
+ g00 *= norm.x;
+ g01 *= norm.y;
+ g10 *= norm.z;
+ g11 *= norm.w;
+
+ float n00 = dot(g00, vec2(fx.x, fy.x));
+ float n10 = dot(g10, vec2(fx.y, fy.y));
+ float n01 = dot(g01, vec2(fx.z, fy.z));
+ float n11 = dot(g11, vec2(fx.w, fy.w));
+
+ vec2 fade_xy = fade(Pf.xy);
+ vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade_xy.x);
+ float n_xy = mix(n_x.x, n_x.y, fade_xy.y);
+ return 2.3 * n_xy;
+}
+
+#pragma glslify: export(pnoise)
--- /dev/null
+//
+// GLSL textureless classic 3D noise "cnoise",
+// with an RSL-style periodic variant "pnoise".
+// Author: Stefan Gustavson (stefan.gustavson@liu.se)
+// Version: 2011-10-11
+//
+// Many thanks to Ian McEwan of Ashima Arts for the
+// ideas for permutation and gradient selection.
+//
+// Copyright (c) 2011 Stefan Gustavson. All rights reserved.
+// Distributed under the MIT license. See LICENSE file.
+// https://github.com/ashima/webgl-noise
+//
+
+vec3 mod289(vec3 x)
+{
+ return x - floor(x * (1.0 / 289.0)) * 289.0;
+}
+
+vec4 mod289(vec4 x)
+{
+ return x - floor(x * (1.0 / 289.0)) * 289.0;
+}
+
+vec4 permute(vec4 x)
+{
+ return mod289(((x*34.0)+1.0)*x);
+}
+
+vec4 taylorInvSqrt(vec4 r)
+{
+ return 1.79284291400159 - 0.85373472095314 * r;
+}
+
+vec3 fade(vec3 t) {
+ return t*t*t*(t*(t*6.0-15.0)+10.0);
+}
+
+// Classic Perlin noise, periodic variant
+float pnoise(vec3 P, vec3 rep)
+{
+ vec3 Pi0 = mod(floor(P), rep); // Integer part, modulo period
+ vec3 Pi1 = mod(Pi0 + vec3(1.0), rep); // Integer part + 1, mod period
+ Pi0 = mod289(Pi0);
+ Pi1 = mod289(Pi1);
+ vec3 Pf0 = fract(P); // Fractional part for interpolation
+ vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0
+ vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
+ vec4 iy = vec4(Pi0.yy, Pi1.yy);
+ vec4 iz0 = Pi0.zzzz;
+ vec4 iz1 = Pi1.zzzz;
+
+ vec4 ixy = permute(permute(ix) + iy);
+ vec4 ixy0 = permute(ixy + iz0);
+ vec4 ixy1 = permute(ixy + iz1);
+
+ vec4 gx0 = ixy0 * (1.0 / 7.0);
+ vec4 gy0 = fract(floor(gx0) * (1.0 / 7.0)) - 0.5;
+ gx0 = fract(gx0);
+ vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0);
+ vec4 sz0 = step(gz0, vec4(0.0));
+ gx0 -= sz0 * (step(0.0, gx0) - 0.5);
+ gy0 -= sz0 * (step(0.0, gy0) - 0.5);
+
+ vec4 gx1 = ixy1 * (1.0 / 7.0);
+ vec4 gy1 = fract(floor(gx1) * (1.0 / 7.0)) - 0.5;
+ gx1 = fract(gx1);
+ vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1);
+ vec4 sz1 = step(gz1, vec4(0.0));
+ gx1 -= sz1 * (step(0.0, gx1) - 0.5);
+ gy1 -= sz1 * (step(0.0, gy1) - 0.5);
+
+ vec3 g000 = vec3(gx0.x,gy0.x,gz0.x);
+ vec3 g100 = vec3(gx0.y,gy0.y,gz0.y);
+ vec3 g010 = vec3(gx0.z,gy0.z,gz0.z);
+ vec3 g110 = vec3(gx0.w,gy0.w,gz0.w);
+ vec3 g001 = vec3(gx1.x,gy1.x,gz1.x);
+ vec3 g101 = vec3(gx1.y,gy1.y,gz1.y);
+ vec3 g011 = vec3(gx1.z,gy1.z,gz1.z);
+ vec3 g111 = vec3(gx1.w,gy1.w,gz1.w);
+
+ vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));
+ g000 *= norm0.x;
+ g010 *= norm0.y;
+ g100 *= norm0.z;
+ g110 *= norm0.w;
+ vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));
+ g001 *= norm1.x;
+ g011 *= norm1.y;
+ g101 *= norm1.z;
+ g111 *= norm1.w;
+
+ float n000 = dot(g000, Pf0);
+ float n100 = dot(g100, vec3(Pf1.x, Pf0.yz));
+ float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z));
+ float n110 = dot(g110, vec3(Pf1.xy, Pf0.z));
+ float n001 = dot(g001, vec3(Pf0.xy, Pf1.z));
+ float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z));
+ float n011 = dot(g011, vec3(Pf0.x, Pf1.yz));
+ float n111 = dot(g111, Pf1);
+
+ vec3 fade_xyz = fade(Pf0);
+ vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z);
+ vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y);
+ float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x);
+ return 2.2 * n_xyz;
+}
+
+#pragma glslify: export(pnoise)
--- /dev/null
+//
+// GLSL textureless classic 4D noise "cnoise",
+// with an RSL-style periodic variant "pnoise".
+// Author: Stefan Gustavson (stefan.gustavson@liu.se)
+// Version: 2011-08-22
+//
+// Many thanks to Ian McEwan of Ashima Arts for the
+// ideas for permutation and gradient selection.
+//
+// Copyright (c) 2011 Stefan Gustavson. All rights reserved.
+// Distributed under the MIT license. See LICENSE file.
+// https://github.com/ashima/webgl-noise
+//
+
+vec4 mod289(vec4 x)
+{
+ return x - floor(x * (1.0 / 289.0)) * 289.0;
+}
+
+vec4 permute(vec4 x)
+{
+ return mod289(((x*34.0)+1.0)*x);
+}
+
+vec4 taylorInvSqrt(vec4 r)
+{
+ return 1.79284291400159 - 0.85373472095314 * r;
+}
+
+vec4 fade(vec4 t) {
+ return t*t*t*(t*(t*6.0-15.0)+10.0);
+}
+
+// Classic Perlin noise, periodic version
+float pnoise(vec4 P, vec4 rep)
+{
+ vec4 Pi0 = mod(floor(P), rep); // Integer part modulo rep
+ vec4 Pi1 = mod(Pi0 + 1.0, rep); // Integer part + 1 mod rep
+ Pi0 = mod289(Pi0);
+ Pi1 = mod289(Pi1);
+ vec4 Pf0 = fract(P); // Fractional part for interpolation
+ vec4 Pf1 = Pf0 - 1.0; // Fractional part - 1.0
+ vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
+ vec4 iy = vec4(Pi0.yy, Pi1.yy);
+ vec4 iz0 = vec4(Pi0.zzzz);
+ vec4 iz1 = vec4(Pi1.zzzz);
+ vec4 iw0 = vec4(Pi0.wwww);
+ vec4 iw1 = vec4(Pi1.wwww);
+
+ vec4 ixy = permute(permute(ix) + iy);
+ vec4 ixy0 = permute(ixy + iz0);
+ vec4 ixy1 = permute(ixy + iz1);
+ vec4 ixy00 = permute(ixy0 + iw0);
+ vec4 ixy01 = permute(ixy0 + iw1);
+ vec4 ixy10 = permute(ixy1 + iw0);
+ vec4 ixy11 = permute(ixy1 + iw1);
+
+ vec4 gx00 = ixy00 * (1.0 / 7.0);
+ vec4 gy00 = floor(gx00) * (1.0 / 7.0);
+ vec4 gz00 = floor(gy00) * (1.0 / 6.0);
+ gx00 = fract(gx00) - 0.5;
+ gy00 = fract(gy00) - 0.5;
+ gz00 = fract(gz00) - 0.5;
+ vec4 gw00 = vec4(0.75) - abs(gx00) - abs(gy00) - abs(gz00);
+ vec4 sw00 = step(gw00, vec4(0.0));
+ gx00 -= sw00 * (step(0.0, gx00) - 0.5);
+ gy00 -= sw00 * (step(0.0, gy00) - 0.5);
+
+ vec4 gx01 = ixy01 * (1.0 / 7.0);
+ vec4 gy01 = floor(gx01) * (1.0 / 7.0);
+ vec4 gz01 = floor(gy01) * (1.0 / 6.0);
+ gx01 = fract(gx01) - 0.5;
+ gy01 = fract(gy01) - 0.5;
+ gz01 = fract(gz01) - 0.5;
+ vec4 gw01 = vec4(0.75) - abs(gx01) - abs(gy01) - abs(gz01);
+ vec4 sw01 = step(gw01, vec4(0.0));
+ gx01 -= sw01 * (step(0.0, gx01) - 0.5);
+ gy01 -= sw01 * (step(0.0, gy01) - 0.5);
+
+ vec4 gx10 = ixy10 * (1.0 / 7.0);
+ vec4 gy10 = floor(gx10) * (1.0 / 7.0);
+ vec4 gz10 = floor(gy10) * (1.0 / 6.0);
+ gx10 = fract(gx10) - 0.5;
+ gy10 = fract(gy10) - 0.5;
+ gz10 = fract(gz10) - 0.5;
+ vec4 gw10 = vec4(0.75) - abs(gx10) - abs(gy10) - abs(gz10);
+ vec4 sw10 = step(gw10, vec4(0.0));
+ gx10 -= sw10 * (step(0.0, gx10) - 0.5);
+ gy10 -= sw10 * (step(0.0, gy10) - 0.5);
+
+ vec4 gx11 = ixy11 * (1.0 / 7.0);
+ vec4 gy11 = floor(gx11) * (1.0 / 7.0);
+ vec4 gz11 = floor(gy11) * (1.0 / 6.0);
+ gx11 = fract(gx11) - 0.5;
+ gy11 = fract(gy11) - 0.5;
+ gz11 = fract(gz11) - 0.5;
+ vec4 gw11 = vec4(0.75) - abs(gx11) - abs(gy11) - abs(gz11);
+ vec4 sw11 = step(gw11, vec4(0.0));
+ gx11 -= sw11 * (step(0.0, gx11) - 0.5);
+ gy11 -= sw11 * (step(0.0, gy11) - 0.5);
+
+ vec4 g0000 = vec4(gx00.x,gy00.x,gz00.x,gw00.x);
+ vec4 g1000 = vec4(gx00.y,gy00.y,gz00.y,gw00.y);
+ vec4 g0100 = vec4(gx00.z,gy00.z,gz00.z,gw00.z);
+ vec4 g1100 = vec4(gx00.w,gy00.w,gz00.w,gw00.w);
+ vec4 g0010 = vec4(gx10.x,gy10.x,gz10.x,gw10.x);
+ vec4 g1010 = vec4(gx10.y,gy10.y,gz10.y,gw10.y);
+ vec4 g0110 = vec4(gx10.z,gy10.z,gz10.z,gw10.z);
+ vec4 g1110 = vec4(gx10.w,gy10.w,gz10.w,gw10.w);
+ vec4 g0001 = vec4(gx01.x,gy01.x,gz01.x,gw01.x);
+ vec4 g1001 = vec4(gx01.y,gy01.y,gz01.y,gw01.y);
+ vec4 g0101 = vec4(gx01.z,gy01.z,gz01.z,gw01.z);
+ vec4 g1101 = vec4(gx01.w,gy01.w,gz01.w,gw01.w);
+ vec4 g0011 = vec4(gx11.x,gy11.x,gz11.x,gw11.x);
+ vec4 g1011 = vec4(gx11.y,gy11.y,gz11.y,gw11.y);
+ vec4 g0111 = vec4(gx11.z,gy11.z,gz11.z,gw11.z);
+ vec4 g1111 = vec4(gx11.w,gy11.w,gz11.w,gw11.w);
+
+ vec4 norm00 = taylorInvSqrt(vec4(dot(g0000, g0000), dot(g0100, g0100), dot(g1000, g1000), dot(g1100, g1100)));
+ g0000 *= norm00.x;
+ g0100 *= norm00.y;
+ g1000 *= norm00.z;
+ g1100 *= norm00.w;
+
+ vec4 norm01 = taylorInvSqrt(vec4(dot(g0001, g0001), dot(g0101, g0101), dot(g1001, g1001), dot(g1101, g1101)));
+ g0001 *= norm01.x;
+ g0101 *= norm01.y;
+ g1001 *= norm01.z;
+ g1101 *= norm01.w;
+
+ vec4 norm10 = taylorInvSqrt(vec4(dot(g0010, g0010), dot(g0110, g0110), dot(g1010, g1010), dot(g1110, g1110)));
+ g0010 *= norm10.x;
+ g0110 *= norm10.y;
+ g1010 *= norm10.z;
+ g1110 *= norm10.w;
+
+ vec4 norm11 = taylorInvSqrt(vec4(dot(g0011, g0011), dot(g0111, g0111), dot(g1011, g1011), dot(g1111, g1111)));
+ g0011 *= norm11.x;
+ g0111 *= norm11.y;
+ g1011 *= norm11.z;
+ g1111 *= norm11.w;
+
+ float n0000 = dot(g0000, Pf0);
+ float n1000 = dot(g1000, vec4(Pf1.x, Pf0.yzw));
+ float n0100 = dot(g0100, vec4(Pf0.x, Pf1.y, Pf0.zw));
+ float n1100 = dot(g1100, vec4(Pf1.xy, Pf0.zw));
+ float n0010 = dot(g0010, vec4(Pf0.xy, Pf1.z, Pf0.w));
+ float n1010 = dot(g1010, vec4(Pf1.x, Pf0.y, Pf1.z, Pf0.w));
+ float n0110 = dot(g0110, vec4(Pf0.x, Pf1.yz, Pf0.w));
+ float n1110 = dot(g1110, vec4(Pf1.xyz, Pf0.w));
+ float n0001 = dot(g0001, vec4(Pf0.xyz, Pf1.w));
+ float n1001 = dot(g1001, vec4(Pf1.x, Pf0.yz, Pf1.w));
+ float n0101 = dot(g0101, vec4(Pf0.x, Pf1.y, Pf0.z, Pf1.w));
+ float n1101 = dot(g1101, vec4(Pf1.xy, Pf0.z, Pf1.w));
+ float n0011 = dot(g0011, vec4(Pf0.xy, Pf1.zw));
+ float n1011 = dot(g1011, vec4(Pf1.x, Pf0.y, Pf1.zw));
+ float n0111 = dot(g0111, vec4(Pf0.x, Pf1.yzw));
+ float n1111 = dot(g1111, Pf1);
+
+ vec4 fade_xyzw = fade(Pf0);
+ vec4 n_0w = mix(vec4(n0000, n1000, n0100, n1100), vec4(n0001, n1001, n0101, n1101), fade_xyzw.w);
+ vec4 n_1w = mix(vec4(n0010, n1010, n0110, n1110), vec4(n0011, n1011, n0111, n1111), fade_xyzw.w);
+ vec4 n_zw = mix(n_0w, n_1w, fade_xyzw.z);
+ vec2 n_yzw = mix(n_zw.xy, n_zw.zw, fade_xyzw.y);
+ float n_xyzw = mix(n_yzw.x, n_yzw.y, fade_xyzw.x);
+ return 2.2 * n_xyzw;
+}
+
+#pragma glslify: export(pnoise)
--- /dev/null
+//
+// Description : Array and textureless GLSL 2D simplex noise function.
+// Author : Ian McEwan, Ashima Arts.
+// Maintainer : ijm
+// Lastmod : 20110822 (ijm)
+// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
+// Distributed under the MIT License. See LICENSE file.
+// https://github.com/ashima/webgl-noise
+//
+
+vec3 mod289(vec3 x) {
+ return x - floor(x * (1.0 / 289.0)) * 289.0;
+}
+
+vec2 mod289(vec2 x) {
+ return x - floor(x * (1.0 / 289.0)) * 289.0;
+}
+
+vec3 permute(vec3 x) {
+ return mod289(((x*34.0)+1.0)*x);
+}
+
+float snoise(vec2 v)
+ {
+ const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0
+ 0.366025403784439, // 0.5*(sqrt(3.0)-1.0)
+ -0.577350269189626, // -1.0 + 2.0 * C.x
+ 0.024390243902439); // 1.0 / 41.0
+// First corner
+ vec2 i = floor(v + dot(v, C.yy) );
+ vec2 x0 = v - i + dot(i, C.xx);
+
+// Other corners
+ vec2 i1;
+ //i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0
+ //i1.y = 1.0 - i1.x;
+ i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
+ // x0 = x0 - 0.0 + 0.0 * C.xx ;
+ // x1 = x0 - i1 + 1.0 * C.xx ;
+ // x2 = x0 - 1.0 + 2.0 * C.xx ;
+ vec4 x12 = x0.xyxy + C.xxzz;
+ x12.xy -= i1;
+
+// Permutations
+ i = mod289(i); // Avoid truncation effects in permutation
+ vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))
+ + i.x + vec3(0.0, i1.x, 1.0 ));
+
+ vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0);
+ m = m*m ;
+ m = m*m ;
+
+// Gradients: 41 points uniformly over a line, mapped onto a diamond.
+// The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287)
+
+ vec3 x = 2.0 * fract(p * C.www) - 1.0;
+ vec3 h = abs(x) - 0.5;
+ vec3 ox = floor(x + 0.5);
+ vec3 a0 = x - ox;
+
+// Normalise gradients implicitly by scaling m
+// Approximation of: m *= inversesqrt( a0*a0 + h*h );
+ m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
+
+// Compute final noise value at P
+ vec3 g;
+ g.x = a0.x * x0.x + h.x * x0.y;
+ g.yz = a0.yz * x12.xz + h.yz * x12.yw;
+ return 130.0 * dot(m, g);
+}
+
+#pragma glslify: export(snoise)
--- /dev/null
+//
+// Description : Array and textureless GLSL 2D/3D/4D simplex
+// noise functions.
+// Author : Ian McEwan, Ashima Arts.
+// Maintainer : ijm
+// Lastmod : 20110822 (ijm)
+// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
+// Distributed under the MIT License. See LICENSE file.
+// https://github.com/ashima/webgl-noise
+//
+
+vec3 mod289(vec3 x) {
+ return x - floor(x * (1.0 / 289.0)) * 289.0;
+}
+
+vec4 mod289(vec4 x) {
+ return x - floor(x * (1.0 / 289.0)) * 289.0;
+}
+
+vec4 permute(vec4 x) {
+ return mod289(((x*34.0)+1.0)*x);
+}
+
+vec4 taylorInvSqrt(vec4 r)
+{
+ return 1.79284291400159 - 0.85373472095314 * r;
+}
+
+float snoise(vec3 v)
+ {
+ const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;
+ const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
+
+// First corner
+ vec3 i = floor(v + dot(v, C.yyy) );
+ vec3 x0 = v - i + dot(i, C.xxx) ;
+
+// Other corners
+ vec3 g = step(x0.yzx, x0.xyz);
+ vec3 l = 1.0 - g;
+ vec3 i1 = min( g.xyz, l.zxy );
+ vec3 i2 = max( g.xyz, l.zxy );
+
+ // x0 = x0 - 0.0 + 0.0 * C.xxx;
+ // x1 = x0 - i1 + 1.0 * C.xxx;
+ // x2 = x0 - i2 + 2.0 * C.xxx;
+ // x3 = x0 - 1.0 + 3.0 * C.xxx;
+ vec3 x1 = x0 - i1 + C.xxx;
+ vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
+ vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
+
+// Permutations
+ i = mod289(i);
+ vec4 p = permute( permute( permute(
+ i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
+ + i.y + vec4(0.0, i1.y, i2.y, 1.0 ))
+ + i.x + vec4(0.0, i1.x, i2.x, 1.0 ));
+
+// Gradients: 7x7 points over a square, mapped onto an octahedron.
+// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
+ float n_ = 0.142857142857; // 1.0/7.0
+ vec3 ns = n_ * D.wyz - D.xzx;
+
+ vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)
+
+ vec4 x_ = floor(j * ns.z);
+ vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N)
+
+ vec4 x = x_ *ns.x + ns.yyyy;
+ vec4 y = y_ *ns.x + ns.yyyy;
+ vec4 h = 1.0 - abs(x) - abs(y);
+
+ vec4 b0 = vec4( x.xy, y.xy );
+ vec4 b1 = vec4( x.zw, y.zw );
+
+ //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
+ //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
+ vec4 s0 = floor(b0)*2.0 + 1.0;
+ vec4 s1 = floor(b1)*2.0 + 1.0;
+ vec4 sh = -step(h, vec4(0.0));
+
+ vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
+ vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;
+
+ vec3 p0 = vec3(a0.xy,h.x);
+ vec3 p1 = vec3(a0.zw,h.y);
+ vec3 p2 = vec3(a1.xy,h.z);
+ vec3 p3 = vec3(a1.zw,h.w);
+
+//Normalise gradients
+ vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
+ p0 *= norm.x;
+ p1 *= norm.y;
+ p2 *= norm.z;
+ p3 *= norm.w;
+
+// Mix final noise value
+ vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
+ m = m * m;
+ return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1),
+ dot(p2,x2), dot(p3,x3) ) );
+ }
+
+#pragma glslify: export(snoise)
--- /dev/null
+//
+// Description : Array and textureless GLSL 2D/3D/4D simplex
+// noise functions.
+// Author : Ian McEwan, Ashima Arts.
+// Maintainer : ijm
+// Lastmod : 20110822 (ijm)
+// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
+// Distributed under the MIT License. See LICENSE file.
+// https://github.com/ashima/webgl-noise
+//
+
+vec4 mod289(vec4 x) {
+ return x - floor(x * (1.0 / 289.0)) * 289.0; }
+
+float mod289(float x) {
+ return x - floor(x * (1.0 / 289.0)) * 289.0; }
+
+vec4 permute(vec4 x) {
+ return mod289(((x*34.0)+1.0)*x);
+}
+
+float permute(float x) {
+ return mod289(((x*34.0)+1.0)*x);
+}
+
+vec4 taylorInvSqrt(vec4 r)
+{
+ return 1.79284291400159 - 0.85373472095314 * r;
+}
+
+float taylorInvSqrt(float r)
+{
+ return 1.79284291400159 - 0.85373472095314 * r;
+}
+
+vec4 grad4(float j, vec4 ip)
+ {
+ const vec4 ones = vec4(1.0, 1.0, 1.0, -1.0);
+ vec4 p,s;
+
+ p.xyz = floor( fract (vec3(j) * ip.xyz) * 7.0) * ip.z - 1.0;
+ p.w = 1.5 - dot(abs(p.xyz), ones.xyz);
+ s = vec4(lessThan(p, vec4(0.0)));
+ p.xyz = p.xyz + (s.xyz*2.0 - 1.0) * s.www;
+
+ return p;
+ }
+
+// (sqrt(5) - 1)/4 = F4, used once below
+#define F4 0.309016994374947451
+
+float snoise(vec4 v)
+ {
+ const vec4 C = vec4( 0.138196601125011, // (5 - sqrt(5))/20 G4
+ 0.276393202250021, // 2 * G4
+ 0.414589803375032, // 3 * G4
+ -0.447213595499958); // -1 + 4 * G4
+
+// First corner
+ vec4 i = floor(v + dot(v, vec4(F4)) );
+ vec4 x0 = v - i + dot(i, C.xxxx);
+
+// Other corners
+
+// Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI)
+ vec4 i0;
+ vec3 isX = step( x0.yzw, x0.xxx );
+ vec3 isYZ = step( x0.zww, x0.yyz );
+// i0.x = dot( isX, vec3( 1.0 ) );
+ i0.x = isX.x + isX.y + isX.z;
+ i0.yzw = 1.0 - isX;
+// i0.y += dot( isYZ.xy, vec2( 1.0 ) );
+ i0.y += isYZ.x + isYZ.y;
+ i0.zw += 1.0 - isYZ.xy;
+ i0.z += isYZ.z;
+ i0.w += 1.0 - isYZ.z;
+
+ // i0 now contains the unique values 0,1,2,3 in each channel
+ vec4 i3 = clamp( i0, 0.0, 1.0 );
+ vec4 i2 = clamp( i0-1.0, 0.0, 1.0 );
+ vec4 i1 = clamp( i0-2.0, 0.0, 1.0 );
+
+ // x0 = x0 - 0.0 + 0.0 * C.xxxx
+ // x1 = x0 - i1 + 1.0 * C.xxxx
+ // x2 = x0 - i2 + 2.0 * C.xxxx
+ // x3 = x0 - i3 + 3.0 * C.xxxx
+ // x4 = x0 - 1.0 + 4.0 * C.xxxx
+ vec4 x1 = x0 - i1 + C.xxxx;
+ vec4 x2 = x0 - i2 + C.yyyy;
+ vec4 x3 = x0 - i3 + C.zzzz;
+ vec4 x4 = x0 + C.wwww;
+
+// Permutations
+ i = mod289(i);
+ float j0 = permute( permute( permute( permute(i.w) + i.z) + i.y) + i.x);
+ vec4 j1 = permute( permute( permute( permute (
+ i.w + vec4(i1.w, i2.w, i3.w, 1.0 ))
+ + i.z + vec4(i1.z, i2.z, i3.z, 1.0 ))
+ + i.y + vec4(i1.y, i2.y, i3.y, 1.0 ))
+ + i.x + vec4(i1.x, i2.x, i3.x, 1.0 ));
+
+// Gradients: 7x7x6 points over a cube, mapped onto a 4-cross polytope
+// 7*7*6 = 294, which is close to the ring size 17*17 = 289.
+ vec4 ip = vec4(1.0/294.0, 1.0/49.0, 1.0/7.0, 0.0) ;
+
+ vec4 p0 = grad4(j0, ip);
+ vec4 p1 = grad4(j1.x, ip);
+ vec4 p2 = grad4(j1.y, ip);
+ vec4 p3 = grad4(j1.z, ip);
+ vec4 p4 = grad4(j1.w, ip);
+
+// Normalise gradients
+ vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
+ p0 *= norm.x;
+ p1 *= norm.y;
+ p2 *= norm.z;
+ p3 *= norm.w;
+ p4 *= taylorInvSqrt(dot(p4,p4));
+
+// Mix contributions from the five corners
+ vec3 m0 = max(0.6 - vec3(dot(x0,x0), dot(x1,x1), dot(x2,x2)), 0.0);
+ vec2 m1 = max(0.6 - vec2(dot(x3,x3), dot(x4,x4) ), 0.0);
+ m0 = m0 * m0;
+ m1 = m1 * m1;
+ return 49.0 * ( dot(m0*m0, vec3( dot( p0, x0 ), dot( p1, x1 ), dot( p2, x2 )))
+ + dot(m1*m1, vec2( dot( p3, x3 ), dot( p4, x4 ) ) ) ) ;
+
+ }
+
+#pragma glslify: export(snoise)
--- /dev/null
+void main()
+{
+ gl_FragColor = gl_Color;
+}
--- /dev/null
+void main()
+{
+ float s = gl_Vertex.z + 1.0;
+
+ vec4 pos = gl_Vertex * vec4(s, s, 1.0, 1.0);
+
+ gl_Position = gl_ModelViewProjectionMatrix * pos;
+ gl_FrontColor = gl_Color;
+}
--- /dev/null
+void main()
+{
+ gl_FragColor = gl_Color;
+}
--- /dev/null
+#define PI 3.141592653589793
+void main()
+{
+ float s = 0.55 * cos(gl_Vertex.z * PI / 2.0 + PI / 2.0) + 1.02;
+ vec4 pos = gl_Vertex * vec4(s, s, 1.0, 1.0);
+
+ gl_Position = gl_ModelViewProjectionMatrix * pos;
+ gl_FrontColor = gl_Color;
+}
--- /dev/null
+float pnoise(vec2 P, vec2 rep);
+float pnoise_octaves();
+
+void main()
+{
+ float alt = min((gl_TexCoord[0].y + 0.29)* 2.0, 1.0);
+ float cloud_dens = 0.5;
+
+ //const vec3 col_hor = vec3(0.96, 0.55, 0.98);
+ const vec3 col_hor = vec3(0.95, 0.38, 0.54);
+ const vec3 col_zen = vec3(0.05, 0.15, 0.32);
+
+ gl_FragColor.rgb = mix(col_hor, col_zen, alt);
+ gl_FragColor.a = 1.0;
+}
+
+
+//
+// GLSL textureless classic 2D noise "cnoise",
+// with an RSL-style periodic variant "pnoise".
+// Author: Stefan Gustavson (stefan.gustavson@liu.se)
+// Version: 2011-08-22
+//
+// Many thanks to Ian McEwan of Ashima Arts for the
+// ideas for permutation and gradient selection.
+//
+// Copyright (c) 2011 Stefan Gustavson. All rights reserved.
+// Distributed under the MIT license. See LICENSE file.
+// https://github.com/ashima/webgl-noise
+//
+
+vec4 mod289(vec4 x)
+{
+ return x - floor(x * (1.0 / 289.0)) * 289.0;
+}
+
+vec4 permute(vec4 x)
+{
+ return mod289(((x*34.0)+1.0)*x);
+}
+
+vec4 taylorInvSqrt(vec4 r)
+{
+ return 1.79284291400159 - 0.85373472095314 * r;
+}
+
+vec2 fade(vec2 t) {
+ return t*t*t*(t*(t*6.0-15.0)+10.0);
+}
+
+// Classic Perlin noise, periodic variant
+float pnoise(vec2 P, vec2 rep)
+{
+ vec4 Pi = floor(P.xyxy) + vec4(0.0, 0.0, 1.0, 1.0);
+ vec4 Pf = fract(P.xyxy) - vec4(0.0, 0.0, 1.0, 1.0);
+ Pi = mod(Pi, rep.xyxy); // To create noise with explicit period
+ Pi = mod289(Pi); // To avoid truncation effects in permutation
+ vec4 ix = Pi.xzxz;
+ vec4 iy = Pi.yyww;
+ vec4 fx = Pf.xzxz;
+ vec4 fy = Pf.yyww;
+
+ vec4 i = permute(permute(ix) + iy);
+
+ vec4 gx = fract(i * (1.0 / 41.0)) * 2.0 - 1.0 ;
+ vec4 gy = abs(gx) - 0.5 ;
+ vec4 tx = floor(gx + 0.5);
+ gx = gx - tx;
+
+ vec2 g00 = vec2(gx.x,gy.x);
+ vec2 g10 = vec2(gx.y,gy.y);
+ vec2 g01 = vec2(gx.z,gy.z);
+ vec2 g11 = vec2(gx.w,gy.w);
+
+ vec4 norm = taylorInvSqrt(vec4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11)));
+ g00 *= norm.x;
+ g01 *= norm.y;
+ g10 *= norm.z;
+ g11 *= norm.w;
+
+ float n00 = dot(g00, vec2(fx.x, fy.x));
+ float n10 = dot(g10, vec2(fx.y, fy.y));
+ float n01 = dot(g01, vec2(fx.z, fy.z));
+ float n11 = dot(g11, vec2(fx.w, fy.w));
+
+ vec2 fade_xy = fade(Pf.xy);
+ vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade_xy.x);
+ float n_xy = mix(n_x.x, n_x.y, fade_xy.y);
+ return 2.3 * n_xy;
+}
+
+#pragma glslify: export(pnoise)
--- /dev/null
+void main()
+{
+ gl_Position = ftransform();
+
+ vec3 p = normalize(gl_Vertex.xyz);
+ vec2 uv = vec2(atan(p.z, p.x), asin(p.y));
+
+ gl_TexCoord[0] = vec4(uv, 0.0, 0.0);
+}
--- /dev/null
+#include <GL/glew.h>
+#include <GL/freeglut.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "sdr.h"
+
+#define CURVE_VS "sdr/curve_top.v.glsl"
+#define CURVE_FS "sdr/curve_top.f.glsl"
+#define BEAM_VS "sdr/beam.v.glsl"
+#define BEAM_FS "sdr/beam.f.glsl"
+
+#define BEAM_SHELLS 40
+#define BEAM_RMIN 0.01
+#define BEAM_RMAX 0.125
+#define BEAM_ENERGY 0.02
+
+static bool init();
+static void cleanup();
+
+static void faros();
+static void light();
+static void ground();
+static void backdrop();
+
+static void display();
+static void idle();
+static void reshape(int x, int y);
+static void keyboard(unsigned char c, int x, int y);
+static void mbutton(int bn, int state, int x, int y);
+static void mmotion(int x, int y);
+
+static float cam_theta = 45, cam_phi, cam_dist = 10;
+static unsigned int sdr_curve_top, sdr_beam, sdr_sky;
+static unsigned int start_time;
+static float beam_rot_speed = 0.1;
+
+int main(int argc, char **argv)
+{
+ glutInit(&argc, argv);
+ glutInitWindowSize(800, 600);
+ glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
+
+ glutCreateWindow("Faros");
+
+ glutDisplayFunc(display);
+ glutIdleFunc(idle);
+ glutReshapeFunc(reshape);
+ glutKeyboardFunc(keyboard);
+ glutMouseFunc(mbutton);
+ glutMotionFunc(mmotion);
+
+ if(!init()) {
+ return 1;
+ }
+
+ atexit(cleanup);
+ glutMainLoop();
+
+ return 0;
+}
+
+static bool init()
+{
+ glewInit();
+
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_MULTISAMPLE);
+
+// glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+
+ glEnable(GL_NORMALIZE);
+
+ if(!(sdr_curve_top = create_program_load(CURVE_VS, CURVE_FS)))
+ return false;
+
+ if(!(sdr_beam = create_program_load(BEAM_VS, BEAM_FS)))
+ return false;
+
+ if(!(sdr_sky = create_program_load("sdr/sky.v.glsl", "sdr/sky.f.glsl"))) {
+ return false;
+ }
+
+ start_time = glutGet(GLUT_ELAPSED_TIME);
+ return true;
+}
+
+static void cleanup()
+{
+}
+
+static void faros()
+{
+ glColor3f(0, 0, 0);
+
+ // kormos
+ glPushMatrix();
+ glScalef(1.1, 3, 1.1);
+ glTranslatef(0, 0.5, 0);
+ glutSolidCube(1.0);
+ glPopMatrix();
+
+ glShadeModel(GL_FLAT);
+
+ // base
+ glPushMatrix();
+ glRotatef(90, 1, 0, 0);
+ glTranslatef(0, -0.15, 0);
+ glutSolidCylinder(2, 0.3, 16, 1);
+ glPopMatrix();
+
+ // middle cylinder
+ glPushMatrix();
+ glTranslatef(0, 3, 0);
+ glRotatef(22.5, 0, 1, 0);
+ glRotatef(-90, 1, 0, 0);
+ glutSolidCylinder(0.5, 1.0, 8, 1);
+ glPopMatrix();
+
+ // trim middle cylinder (mporntoura)
+ glPushMatrix();
+ glTranslatef(0, 3.9, 0);
+ glRotatef(22.5, 0, 1, 0);
+ glRotatef(-90, 1, 0, 0);
+ glutSolidCylinder(0.55, 0.02, 8, 1);
+ glPopMatrix();
+
+ // top smaller cylinder
+ glPushMatrix();
+ glTranslatef(0, 4, 0);
+ glRotatef(22.5, 0, 1, 0);
+ glRotatef(-90, 1, 0, 0);
+ glutSolidCylinder(0.28, 0.5, 8, 1);
+ glPopMatrix();
+
+ // top wire even smaller cylinder
+ glPushMatrix();
+ glTranslatef(0, 4.5, 0);
+ glRotatef(22.5, 0, 1, 0);
+ glRotatef(-90, 1, 0, 0);
+ glutWireCylinder(0.18, 0.3, 9, 3);
+ glPopMatrix();
+
+ glShadeModel(GL_SMOOTH);
+
+ // top troulos
+ glPushMatrix();
+ glTranslatef(0, 4.8, 0);
+ glRotatef(22.5, 0, 1, 0);
+ glRotatef(-90, 1, 0, 0);
+ glutSolidCone(0.18, 0.2, 9, 1);
+ glPopMatrix();
+
+ // tsamploukano
+ glPushMatrix();
+ glTranslatef(-0.28, 4, 0);
+ glScalef(1, 13, 1);
+ glutSolidSphere(0.1, 16, 16);
+ glPopMatrix();
+
+ //pyramid on top of kormos
+ bind_program(sdr_curve_top);
+
+ glPushMatrix();
+ glTranslatef(0, 3, 0);
+ glRotatef(45, 0, 1, 0);
+ glRotatef(-90, 1, 0, 0);
+ glScalef(1, 1, 0.45);
+ glutSolidCylinder(1, 1, 4, 16);
+ glPopMatrix();
+
+ bind_program(0);
+}
+
+static void light()
+{
+ glPushAttrib(GL_ENABLE_BIT);
+ glDisable(GL_CULL_FACE);
+
+ glPushMatrix();
+
+ glTranslatef(0, 4.65, 0.2);
+ bind_program(sdr_beam);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+
+ for(int i=0; i<BEAM_SHELLS; i++) {
+ float t = (float)i / (float)(BEAM_SHELLS - 1);
+ float rad = BEAM_RMIN + (BEAM_RMAX - BEAM_RMIN) * t;
+ float alpha = BEAM_ENERGY / t;
+
+ glColor4f(0.8, 0.8, 0.2, alpha);
+
+ glutSolidCylinder(rad, 6, 10, 1);
+ }
+
+ bind_program(0);
+
+ glPopMatrix();
+
+ glPopAttrib();
+}
+
+static void ground()
+{
+ glPushMatrix();
+
+ glTranslatef(0, -1.25, 0);
+ glScalef(1, 0.1, 1);
+
+ glColor3f(0, 0, 0);
+ glutSolidSphere(10, 32, 32);
+
+ glPopMatrix();
+}
+
+static void backdrop()
+{
+ glFrontFace(GL_CW);
+ bind_program(sdr_sky);
+ glutSolidSphere(200, 16, 32);
+ bind_program(0);
+ glFrontFace(GL_CCW);
+}
+
+static void display()
+{
+ unsigned int tmsec = glutGet(GLUT_ELAPSED_TIME) - start_time;
+ float tsec = (float)tmsec / 1000.0;
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ backdrop();
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glTranslatef(0, -2, -cam_dist);
+ glRotatef(cam_phi, 1, 0, 0);
+ glRotatef(cam_theta, 0, 1, 0);
+
+ ground();
+ faros();
+
+ glPushMatrix();
+
+ float beam_angle = tsec * beam_rot_speed * 360;
+
+ glRotatef(beam_angle, 0, 1, 0);
+ light();
+
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+static void idle()
+{
+ glutPostRedisplay();
+}
+
+static void reshape(int x, int y)
+{
+ glViewport(0, 0, x, y);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+
+ gluPerspective(50, (float)x / (float)y, 0.5, 500);
+}
+
+static void keyboard(unsigned char c, int x, int y)
+{
+ switch(c) {
+ case 27:
+ exit(0);
+ default:
+ break;
+ }
+}
+
+static int prev_x, prev_y;
+static bool bst[8];
+static void mbutton(int bn, int state, int x, int y)
+{
+ int button = bn - GLUT_LEFT_BUTTON;
+ bst[button] = state == GLUT_DOWN;
+
+ prev_x = x;
+ prev_y = y;
+}
+
+static void mmotion(int x, int y)
+{
+ int dx = x - prev_x;
+ int dy = y - prev_y;
+
+ prev_x = x;
+ prev_y = y;
+
+ if (dx == 0 && dy == 0)
+ return;
+
+ if (bst[0]) {
+ cam_theta += dx * 0.5;
+ cam_phi += dy * 0.5;
+
+ if (cam_phi < -90)
+ cam_phi = -90;
+
+ if (cam_phi > 90)
+ cam_phi = 90;
+ }
+
+ if (bst[2]) {
+ cam_dist += dy * 0.1;
+
+ if (cam_dist < 0)
+ cam_dist = 0;
+ }
+}
--- /dev/null
+#include <GL/glew.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#if defined(unix) || defined(__unix__)
+#include <unistd.h>
+#include <sys/stat.h>
+#endif /* unix */
+
+#include "sdr.h"
+
+static const char *sdrtypestr(unsigned int sdrtype);
+static int sdrtypeidx(unsigned int sdrtype);
+
+
+unsigned int create_vertex_shader(const char *src)
+{
+ return create_shader(src, GL_VERTEX_SHADER);
+}
+
+unsigned int create_pixel_shader(const char *src)
+{
+ return create_shader(src, GL_FRAGMENT_SHADER);
+}
+
+unsigned int create_tessctl_shader(const char *src)
+{
+#ifdef GL_TESS_CONTROL_SHADER
+ return create_shader(src, GL_TESS_CONTROL_SHADER);
+#else
+ return 0;
+#endif
+}
+
+unsigned int create_tesseval_shader(const char *src)
+{
+#ifdef GL_TESS_EVALUATION_SHADER
+ return create_shader(src, GL_TESS_EVALUATION_SHADER);
+#else
+ return 0;
+#endif
+}
+
+unsigned int create_geometry_shader(const char *src)
+{
+#ifdef GL_GEOMETRY_SHADER
+ return create_shader(src, GL_GEOMETRY_SHADER);
+#else
+ return 0;
+#endif
+}
+
+unsigned int create_shader(const char *src, unsigned int sdr_type)
+{
+ unsigned int sdr;
+ int success, info_len;
+ char *info_str = 0;
+ const char *src_str[3], *header, *footer;
+ int src_str_count = 0;
+ GLenum err;
+
+ if((header = get_shader_header(sdr_type))) {
+ src_str[src_str_count++] = header;
+ }
+ src_str[src_str_count++] = src;
+ if((footer = get_shader_footer(sdr_type))) {
+ src_str[src_str_count++] = footer;
+ }
+
+ sdr = glCreateShader(sdr_type);
+ assert(glGetError() == GL_NO_ERROR);
+ glShaderSource(sdr, src_str_count, src_str, 0);
+ err = glGetError();
+ assert(err == GL_NO_ERROR);
+ glCompileShader(sdr);
+ assert(glGetError() == GL_NO_ERROR);
+
+ glGetShaderiv(sdr, GL_COMPILE_STATUS, &success);
+ assert(glGetError() == GL_NO_ERROR);
+ glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len);
+ assert(glGetError() == GL_NO_ERROR);
+
+ if(info_len) {
+ if((info_str = malloc(info_len + 1))) {
+ glGetShaderInfoLog(sdr, info_len, 0, info_str);
+ assert(glGetError() == GL_NO_ERROR);
+ info_str[info_len] = 0;
+ }
+ }
+
+ if(success) {
+ fprintf(stderr, info_str ? "done: %s\n" : "done\n", info_str);
+ } else {
+ fprintf(stderr, info_str ? "failed: %s\n" : "failed\n", info_str);
+ glDeleteShader(sdr);
+ sdr = 0;
+ }
+
+ free(info_str);
+ return sdr;
+}
+
+void free_shader(unsigned int sdr)
+{
+ glDeleteShader(sdr);
+}
+
+unsigned int load_vertex_shader(const char *fname)
+{
+ return load_shader(fname, GL_VERTEX_SHADER);
+}
+
+unsigned int load_pixel_shader(const char *fname)
+{
+ return load_shader(fname, GL_FRAGMENT_SHADER);
+}
+
+unsigned int load_tessctl_shader(const char *fname)
+{
+#ifdef GL_TESS_CONTROL_SHADER
+ return load_shader(fname, GL_TESS_CONTROL_SHADER);
+#else
+ return 0;
+#endif
+}
+
+unsigned int load_tesseval_shader(const char *fname)
+{
+#ifdef GL_TESS_EVALUATION_SHADER
+ return load_shader(fname, GL_TESS_EVALUATION_SHADER);
+#else
+ return 0;
+#endif
+}
+
+unsigned int load_geometry_shader(const char *fname)
+{
+#ifdef GL_GEOMETRY_SHADER
+ return load_shader(fname, GL_GEOMETRY_SHADER);
+#else
+ return 0;
+#endif
+}
+
+unsigned int load_shader(const char *fname, unsigned int sdr_type)
+{
+ unsigned int sdr;
+ size_t filesize;
+ FILE *fp;
+ char *src;
+
+ if(!(fp = fopen(fname, "rb"))) {
+ fprintf(stderr, "failed to open shader %s: %s\n", fname, strerror(errno));
+ return 0;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ filesize = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ if(!(src = malloc(filesize + 1))) {
+ fclose(fp);
+ return 0;
+ }
+ fread(src, 1, filesize, fp);
+ src[filesize] = 0;
+ fclose(fp);
+
+ fprintf(stderr, "compiling %s shader: %s... ", sdrtypestr(sdr_type), fname);
+ sdr = create_shader(src, sdr_type);
+
+ free(src);
+ return sdr;
+}
+
+
+/* ---- gpu programs ---- */
+
+unsigned int create_program(void)
+{
+ unsigned int prog = glCreateProgram();
+ assert(glGetError() == GL_NO_ERROR);
+ return prog;
+}
+
+unsigned int create_program_link(unsigned int sdr0, ...)
+{
+ unsigned int prog, sdr;
+ va_list ap;
+
+ if(!(prog = create_program())) {
+ return 0;
+ }
+
+ attach_shader(prog, sdr0);
+ if(glGetError()) {
+ return 0;
+ }
+
+ va_start(ap, sdr0);
+ while((sdr = va_arg(ap, unsigned int))) {
+ attach_shader(prog, sdr);
+ if(glGetError()) {
+ return 0;
+ }
+ }
+ va_end(ap);
+
+ if(link_program(prog) == -1) {
+ free_program(prog);
+ return 0;
+ }
+ return prog;
+}
+
+unsigned int create_program_load(const char *vfile, const char *pfile)
+{
+ unsigned int vs = 0, ps = 0;
+
+ if(vfile && *vfile && !(vs = load_vertex_shader(vfile))) {
+ return 0;
+ }
+ if(pfile && *pfile && !(ps = load_pixel_shader(pfile))) {
+ return 0;
+ }
+ return create_program_link(vs, ps, 0);
+}
+
+void free_program(unsigned int sdr)
+{
+ glDeleteProgram(sdr);
+}
+
+void attach_shader(unsigned int prog, unsigned int sdr)
+{
+ int err;
+
+ if(prog && sdr) {
+ assert(glGetError() == GL_NO_ERROR);
+ glAttachShader(prog, sdr);
+ if((err = glGetError()) != GL_NO_ERROR) {
+ fprintf(stderr, "failed to attach shader %u to program %u (err: 0x%x)\n", sdr, prog, err);
+ abort();
+ }
+ }
+}
+
+int link_program(unsigned int prog)
+{
+ int linked, info_len, retval = 0;
+ char *info_str = 0;
+
+ glLinkProgram(prog);
+ assert(glGetError() == GL_NO_ERROR);
+ glGetProgramiv(prog, GL_LINK_STATUS, &linked);
+ assert(glGetError() == GL_NO_ERROR);
+ glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len);
+ assert(glGetError() == GL_NO_ERROR);
+
+ if(info_len) {
+ if((info_str = malloc(info_len + 1))) {
+ glGetProgramInfoLog(prog, info_len, 0, info_str);
+ assert(glGetError() == GL_NO_ERROR);
+ info_str[info_len] = 0;
+ }
+ }
+
+ if(linked) {
+ fprintf(stderr, info_str ? "linking done: %s\n" : "linking done\n", info_str);
+ } else {
+ fprintf(stderr, info_str ? "linking failed: %s\n" : "linking failed\n", info_str);
+ retval = -1;
+ }
+
+ free(info_str);
+ return retval;
+}
+
+int bind_program(unsigned int prog)
+{
+ GLenum err;
+
+ glUseProgram(prog);
+ if(prog && (err = glGetError()) != GL_NO_ERROR) {
+ /* maybe the program is not linked, try linking first */
+ if(err == GL_INVALID_OPERATION) {
+ if(link_program(prog) == -1) {
+ return -1;
+ }
+ glUseProgram(prog);
+ return glGetError() == GL_NO_ERROR ? 0 : -1;
+ }
+ return -1;
+ }
+ return 0;
+}
+
+/* ugly but I'm not going to write the same bloody code over and over */
+#define BEGIN_UNIFORM_CODE \
+ int loc, curr_prog; \
+ glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); \
+ if((unsigned int)curr_prog != prog && bind_program(prog) == -1) { \
+ return -1; \
+ } \
+ if((loc = glGetUniformLocation(prog, name)) != -1)
+
+#define END_UNIFORM_CODE \
+ if((unsigned int)curr_prog != prog) { \
+ bind_program(curr_prog); \
+ } \
+ return loc == -1 ? -1 : 0
+
+int get_uniform_loc(unsigned int prog, const char *name)
+{
+ int loc, curr_prog;
+ glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog);
+ if((unsigned int)curr_prog != prog && bind_program(prog) == -1) {
+ return -1;
+ }
+ loc = glGetUniformLocation(prog, name);
+ if((unsigned int)curr_prog != prog) {
+ bind_program(curr_prog);
+ }
+ return loc;
+}
+
+int set_uniform_int(unsigned int prog, const char *name, int val)
+{
+ BEGIN_UNIFORM_CODE {
+ glUniform1i(loc, val);
+ }
+ END_UNIFORM_CODE;
+}
+
+int set_uniform_float(unsigned int prog, const char *name, float val)
+{
+ BEGIN_UNIFORM_CODE {
+ glUniform1f(loc, val);
+ }
+ END_UNIFORM_CODE;
+}
+
+int set_uniform_float2(unsigned int prog, const char *name, float x, float y)
+{
+ BEGIN_UNIFORM_CODE {
+ glUniform2f(loc, x, y);
+ }
+ END_UNIFORM_CODE;
+}
+
+int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z)
+{
+ BEGIN_UNIFORM_CODE {
+ glUniform3f(loc, x, y, z);
+ }
+ END_UNIFORM_CODE;
+}
+
+int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w)
+{
+ BEGIN_UNIFORM_CODE {
+ glUniform4f(loc, x, y, z, w);
+ }
+ END_UNIFORM_CODE;
+}
+
+int set_uniform_matrix4(unsigned int prog, const char *name, const float *mat)
+{
+ BEGIN_UNIFORM_CODE {
+ glUniformMatrix4fv(loc, 1, GL_FALSE, mat);
+ }
+ END_UNIFORM_CODE;
+}
+
+int set_uniform_matrix4_transposed(unsigned int prog, const char *name, const float *mat)
+{
+ BEGIN_UNIFORM_CODE {
+ glUniformMatrix4fv(loc, 1, GL_TRUE, mat);
+ }
+ END_UNIFORM_CODE;
+}
+
+int get_attrib_loc(unsigned int prog, const char *name)
+{
+ int loc, curr_prog;
+
+ glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog);
+ if((unsigned int)curr_prog != prog && bind_program(prog) == -1) {
+ return -1;
+ }
+
+ loc = glGetAttribLocation(prog, (char*)name);
+
+ if((unsigned int)curr_prog != prog) {
+ bind_program(curr_prog);
+ }
+ return loc;
+}
+
+void set_attrib_float3(int attr_loc, float x, float y, float z)
+{
+ glVertexAttrib3f(attr_loc, x, y, z);
+}
+
+/* ---- shader composition ---- */
+struct string {
+ char *text;
+ int len;
+};
+
+#define NUM_SHADER_TYPES 5
+static struct string header[NUM_SHADER_TYPES];
+static struct string footer[NUM_SHADER_TYPES];
+
+static void clear_string(struct string *str)
+{
+ free(str->text);
+ str->text = 0;
+ str->len = 0;
+}
+
+static void append_string(struct string *str, const char *s)
+{
+ int len, newlen;
+ char *newstr;
+
+ if(!s || !*s) return;
+
+ len = strlen(s);
+ newlen = str->len + len;
+ if(!(newstr = malloc(newlen + 2))) { /* leave space for a possible newline */
+ fprintf(stderr, "shader composition: failed to append string of size %d\n", len);
+ abort();
+ }
+
+ if(str->text) {
+ memcpy(newstr, str->text, str->len);
+ }
+ memcpy(newstr + str->len, s, len + 1);
+
+ if(s[len - 1] != '\n') {
+ newstr[newlen] = '\n';
+ newstr[newlen + 1] = 0;
+ }
+
+ free(str->text);
+ str->text = newstr;
+ str->len = newlen;
+}
+
+void clear_shader_header(unsigned int type)
+{
+ if(type) {
+ int idx = sdrtypeidx(type);
+ clear_string(&header[idx]);
+ } else {
+ int i;
+ for(i=0; i<NUM_SHADER_TYPES; i++) {
+ clear_string(&header[i]);
+ }
+ }
+}
+
+void clear_shader_footer(unsigned int type)
+{
+ if(type) {
+ int idx = sdrtypeidx(type);
+ clear_string(&footer[idx]);
+ } else {
+ int i;
+ for(i=0; i<NUM_SHADER_TYPES; i++) {
+ clear_string(&footer[i]);
+ }
+ }
+}
+
+void add_shader_header(unsigned int type, const char *s)
+{
+ if(type) {
+ int idx = sdrtypeidx(type);
+ append_string(&header[idx], s);
+ } else {
+ int i;
+ for(i=0; i<NUM_SHADER_TYPES; i++) {
+ append_string(&header[i], s);
+ }
+ }
+}
+
+void add_shader_footer(unsigned int type, const char *s)
+{
+ if(type) {
+ int idx = sdrtypeidx(type);
+ append_string(&footer[idx], s);
+ } else {
+ int i;
+ for(i=0; i<NUM_SHADER_TYPES; i++) {
+ append_string(&footer[i], s);
+ }
+ }
+}
+
+const char *get_shader_header(unsigned int type)
+{
+ int idx = sdrtypeidx(type);
+ return header[idx].text;
+}
+
+const char *get_shader_footer(unsigned int type)
+{
+ int idx = sdrtypeidx(type);
+ return footer[idx].text;
+}
+
+static const char *sdrtypestr(unsigned int sdrtype)
+{
+ switch(sdrtype) {
+ case GL_VERTEX_SHADER:
+ return "vertex";
+ case GL_FRAGMENT_SHADER:
+ return "pixel";
+#ifdef GL_TESS_CONTROL_SHADER
+ case GL_TESS_CONTROL_SHADER:
+ return "tessellation control";
+#endif
+#ifdef GL_TESS_EVALUATION_SHADER
+ case GL_TESS_EVALUATION_SHADER:
+ return "tessellation evaluation";
+#endif
+#ifdef GL_GEOMETRY_SHADER
+ case GL_GEOMETRY_SHADER:
+ return "geometry";
+#endif
+
+ default:
+ break;
+ }
+ return "<unknown>";
+}
+
+static int sdrtypeidx(unsigned int sdrtype)
+{
+ switch(sdrtype) {
+ case GL_VERTEX_SHADER:
+ return 0;
+ case GL_FRAGMENT_SHADER:
+ return 1;
+ case GL_TESS_CONTROL_SHADER:
+ return 2;
+ case GL_TESS_EVALUATION_SHADER:
+ return 3;
+ case GL_GEOMETRY_SHADER:
+ return 4;
+ default:
+ break;
+ }
+ return 0;
+}
--- /dev/null
+#ifndef SDR_H_
+#define SDR_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* ---- shaders ---- */
+unsigned int create_vertex_shader(const char *src);
+unsigned int create_pixel_shader(const char *src);
+unsigned int create_tessctl_shader(const char *src);
+unsigned int create_tesseval_shader(const char *src);
+unsigned int create_geometry_shader(const char *src);
+unsigned int create_shader(const char *src, unsigned int sdr_type);
+void free_shader(unsigned int sdr);
+
+unsigned int load_vertex_shader(const char *fname);
+unsigned int load_pixel_shader(const char *fname);
+unsigned int load_tessctl_shader(const char *fname);
+unsigned int load_tesseval_shader(const char *fname);
+unsigned int load_geometry_shader(const char *fname);
+unsigned int load_shader(const char *src, unsigned int sdr_type);
+
+int add_shader(const char *fname, unsigned int sdr);
+int remove_shader(const char *fname);
+
+/* ---- gpu programs ---- */
+unsigned int create_program(void);
+unsigned int create_program_link(unsigned int sdr0, ...);
+unsigned int create_program_load(const char *vfile, const char *pfile);
+void free_program(unsigned int sdr);
+
+void attach_shader(unsigned int prog, unsigned int sdr);
+int link_program(unsigned int prog);
+int bind_program(unsigned int prog);
+
+int get_uniform_loc(unsigned int prog, const char *name);
+
+int set_uniform_int(unsigned int prog, const char *name, int val);
+int set_uniform_float(unsigned int prog, const char *name, float val);
+int set_uniform_float2(unsigned int prog, const char *name, float x, float y);
+int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z);
+int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w);
+int set_uniform_matrix4(unsigned int prog, const char *name, const float *mat);
+int set_uniform_matrix4_transposed(unsigned int prog, const char *name, const float *mat);
+
+int get_attrib_loc(unsigned int prog, const char *name);
+void set_attrib_float3(int attr_loc, float x, float y, float z);
+
+/* ---- shader composition ---- */
+
+/* clear shader header/footer text.
+ * pass the shader type to clear, or 0 to clear all types */
+void clear_shader_header(unsigned int type);
+void clear_shader_footer(unsigned int type);
+/* append text to the header/footer of a specific shader type
+ * or use type 0 to add it to all shade types */
+void add_shader_header(unsigned int type, const char *s);
+void add_shader_footer(unsigned int type, const char *s);
+/* get the current header/footer text for a specific shader type */
+const char *get_shader_header(unsigned int type);
+const char *get_shader_footer(unsigned int type);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* SDR_H_ */