// BlockyFroggy
// Copyright © 2017 John Ryland.
// All rights reserved.
#include "Shaders.h"
//! @todomake these resources too that the resource loader loads. (or optionally overridable by loaded ones)
//! @todo overall project file, something which contains list of models, cameras, lights, scenes / levels etc.
//! @todo different loading schemes, streaming, portal based, procedurally generated
const char* s_vertexShader = R"(
//
// Vertex Shader
// HighwayDash
//
// Created by John Ryland on 8/02/2016.
// Copyright © 2016 John Ryland. All rights reserved.
//
attribute vec4 position;
attribute vec4 delta;
attribute vec4 animParams;
attribute vec4 barycentric;
attribute vec3 normal;
attribute vec4 color; // almost deprecated as will come from textures
varying lowp vec4 colorVarying;
varying highp vec4 shadowCoordVarying;
varying highp vec4 positionVarying;
varying highp float positionVaryingX;
varying highp vec2 noisePosition;
varying highp float lightVarying;
varying vec4 barycentricVarying;
varying vec3 normalVarying; // doing vertex lighting now as more efficient
// On higher end spec devices, could do per-pixel lighting instead
varying highp vec2 textureCoordVarying;
/*
varying lowp vec2 textureCoordVarying1;
varying lowp vec2 textureCoordVarying2;
varying lowp vec2 textureCoordVarying3;
varying lowp vec2 textureCoordVarying4;
*/
uniform mat4 modelViewProjectionMatrix;
uniform mat4 shadowMapMVP;
uniform float time;
uniform vec4 translation;
//const vec4 lightPosition = vec4(530.0, -430.0, 650.0, 0.0);
const vec4 lightPosition = vec4(700.0, -330.0, 150.0, 0.0);
void main()
{
if (debugTriangles) {
barycentricVarying = barycentric;
}
highp mat4 mvp = modelViewProjectionMatrix;
highp mat3 mvp3 = mat3(mvp[0][0], mvp[0][1], mvp[0][2],
mvp[1][0], mvp[1][1], mvp[1][2],
mvp[2][0], mvp[2][1], mvp[2][2]);
normalVarying = normalize(mvp3 * normal);
highp float off = animParams.x * animParams.y;
highp float modulus = mod(position.x + translation.x + delta.x * time - off, 1000.0 + animParams.y);
highp float x = modulus + off;// - animParams.y;
positionVarying = position + translation;//[gl_InstanceID];// + vec4(delta.xyz * t, 0.0);
positionVarying.x = x;
if (enableDarkenedSides)
{
positionVaryingX = x;
}
noisePosition = vec2(
((position.x + translation.x) / 10.0) * 4.,
mod((position.y + translation.y) / (3.0), 15.0) * 4.
);
if (enableShadows) {
shadowCoordVarying = shadowMapMVP * positionVarying + vec4( 2.5/1024.0, 12.5/1024.0, 0., 0. );
}
//vec4 lightPos = modelViewProjectionMatrix * lightPosition;
vec4 lightPos = lightPosition;
colorVarying = color;
// using textureCoordVarying.yx gives a nice effect for background blocks
highp float texIdx = color.z;
highp float u = mod(texIdx,8.0);
highp float v = floor(texIdx/8.0);
textureCoordVarying = (color.xy + vec2(u, v)) * vec2(256.0/2048.0, 256.0/2048.0);
/*
if (enableBevels)
{
textureCoordVarying1 = textureCoordVarying + vec2( 0.00000, 0.00012 );
textureCoordVarying2 = textureCoordVarying + vec2( 0.00012, 0.00000 );
textureCoordVarying3 = textureCoordVarying + vec2( 0.00000, -0.00012 );
textureCoordVarying4 = textureCoordVarying + vec2(-0.00012, 0.00000 );
}
*/
positionVarying = modelViewProjectionMatrix * positionVarying;
gl_Position = positionVarying;
lightVarying = dot(normalVarying, normalize(lightPosition.xyz - positionVarying.xyz));
/*
if (enableLighting && !enableBevels)
{
lightVarying = max(0.2, 0.3* dot(normalVarying, normalize(lightPosition.xyz - positionVarying.xyz)) + 0.68);
}
*/
}
)";
const char* s_fragmentShader = R"(
//
// Fragment Shader
// HighwayDash
//
// Created by John Ryland on 8/02/2016.
// Copyright © 2016 John Ryland. All rights reserved.
//
varying lowp vec4 colorVarying;
varying highp float lightVarying;
varying highp vec4 shadowCoordVarying;
varying highp vec4 positionVarying;
varying highp float positionVaryingX;
varying highp vec2 noisePosition;
varying vec4 barycentricVarying;
varying vec3 normalVarying;
varying highp vec2 textureCoordVarying;
/*
varying lowp vec2 textureCoordVarying1;
varying lowp vec2 textureCoordVarying2;
varying lowp vec2 textureCoordVarying3;
varying lowp vec2 textureCoordVarying4;
*/
uniform sampler2D shadowMap;
uniform sampler2D texture;
uniform float shadowStrength;
uniform bool mixNoise;
uniform float time;
//const vec4 lightPosition = vec4(0.0, -330.0, 650.0, 0.0);
const vec4 lightPosition = vec4(700.0, -330.0, 150.0, 0.0);
// From noise tutorial here:
// https://www.raywenderlich.com/70208/opengl-es-pixel-shaders-tutorial
float randomNoise(vec2 p)
{
/*
float n = p.x + p.y * 57.0;
n = pow((n*8192.0), n);
return 1.0 - mod( (n * (n * n * 15731.0 + 789221.0) + 1376312589.0), 2147483648.0) / 1073741824.0;
*/
//return fract(6791.*sin(47.*p.x+p.y*9973.));
return fract(6791.*sin(47.*p.x+p.y*73.));
}
float smoothNoise(vec2 p)
{
vec2 nn = vec2(p.x, p.y+1.);
vec2 ee = vec2(p.x+1., p.y);
vec2 ss = vec2(p.x, p.y-1.);
vec2 ww = vec2(p.x-1., p.y);
vec2 cc = vec2(p.x, p.y);
float sum = 0.;
sum += randomNoise(nn)/8.;
sum += randomNoise(ee)/8.;
sum += randomNoise(ss)/8.;
sum += randomNoise(ww)/8.;
sum += randomNoise(cc)/2.;
return sum;
}
float interpolatedNoise(vec2 p)
{
vec2 s = smoothstep(0., 1., fract(p));
float q11 = smoothNoise(vec2(floor(p.x), floor(p.y)));
float q12 = smoothNoise(vec2(floor(p.x), ceil(p.y)));
float q21 = smoothNoise(vec2(ceil(p.x), floor(p.y)));
float q22 = smoothNoise(vec2(ceil(p.x), ceil(p.y)));
float r1 = mix(q11, q21, s.x);
float r2 = mix(q12, q22, s.x);
return mix(r1, r2, s.y);
}
void main()
{
// Distance
float dist = 0.0;
if (enableShadowAttenuation || enableDistanceFog)
{
dist = gl_FragCoord.z / gl_FragCoord.w;
}
// Gamma
// float visibility = 1.8;
float visibility = 1.3;
float inShadow = 0.0;
// Calc if in shadow
if (enableShadows)
{
vec2 shCo = shadowCoordVarying.xy;
/*
float shadowZ = texture2D(shadowMap, shCo).z * 0.30;
shadowZ = shadowZ + texture2D(shadowMap, shCo + vec2( 0.000, 0.001)).z * 0.10;
shadowZ = shadowZ + texture2D(shadowMap, shCo + vec2( 0.000,-0.001)).z * 0.10;
shadowZ = shadowZ + texture2D(shadowMap, shCo + vec2( 0.001, 0.000)).z * 0.10;
shadowZ = shadowZ + texture2D(shadowMap, shCo + vec2(-0.001, 0.000)).z * 0.10;
shadowZ = shadowZ + texture2D(shadowMap, shCo + vec2( 0.001, 0.001)).z * 0.075;
shadowZ = shadowZ + texture2D(shadowMap, shCo + vec2(-0.001, 0.001)).z * 0.075;
shadowZ = shadowZ + texture2D(shadowMap, shCo + vec2( 0.001,-0.001)).z * 0.075;
shadowZ = shadowZ + texture2D(shadowMap, shCo + vec2(-0.001,-0.001)).z * 0.075;
*/
float shadowZ1 = texture2D(shadowMap, shCo).z;
/*
bool softShadows = false;
if (softShadows)
{
inShadow = 5.0;//20.0 / clamp((shadowCoordVaryingZ - shadowZ1) * 2000.0, 1.0, 20.0);
float shadowZ = shadowZ1;
shadowZ = shadowZ + texture2D(shadowMap, shCo + inShadow * vec2( 0.001, 0.001)).z;
shadowZ = shadowZ + texture2D(shadowMap, shCo + inShadow * vec2( 0.001,-0.001)).z;
shadowZ = shadowZ + texture2D(shadowMap, shCo + inShadow * vec2(-0.001, 0.001)).z;
shadowZ = shadowZ + texture2D(shadowMap, shCo + inShadow * vec2(-0.001,-0.001)).z;
shadowZ = shadowZ / 5.0;
float radius = clamp((shadowCoordVarying.z - shadowZ) * 15000.0, 1.0, 2.0);
inShadow = clamp((shadowCoordVarying.z - shadowZ1) * 1000.0, 0.0, 0.2) * 0.5;
inShadow = inShadow + clamp((shadowCoordVarying.z - texture2D(shadowMap, shCo + radius * vec2( 0.0012, 0.0015)).z) * 1000.0, 0.0, 0.2) * 0.125;
inShadow = inShadow + clamp((shadowCoordVarying.z - texture2D(shadowMap, shCo + radius * vec2(-0.0014, 0.0019)).z) * 1000.0, 0.0, 0.2) * 0.125;
inShadow = inShadow + clamp((shadowCoordVarying.z - texture2D(shadowMap, shCo + radius * vec2( 0.0013,-0.0016)).z) * 1000.0, 0.0, 0.2) * 0.125;
inShadow = inShadow + clamp((shadowCoordVarying.z - texture2D(shadowMap, shCo + radius * vec2(-0.0017,-0.0011)).z) * 1000.0, 0.0, 0.2) * 0.125;
} else
*/
{
inShadow = clamp((shadowCoordVarying.z - shadowZ1) * 1000.0, 0.0, 0.2);
//inShadow = 20.0 / clamp((shadowCoordVarying.z - shadowZ1) * 2000.0, 1.0, 20.0);
}
//shadowZ += 0.1;
// Reduce shadow effect in distance
if (enableShadowAttenuation)
{
float shadowDist = clamp(dist - 3.0, 0.0, 1.0);
inShadow = inShadow * (1.0 - shadowDist);
}
// Apply shadow
//visibility = visibility * (1.0 - inShadow * shadowStrength);
visibility = visibility * (1.5 - inShadow);
}
if (enableDarkenedSides)
{
// Darken sides (out of playing bounds)
float dx = 0.0;
dx = max(0.0, 520.0 - positionVaryingX);
dx = max(dx, positionVaryingX - 680.0);
visibility = visibility * ((180.0-dx)/150.0);
}
vec4 col;
if (enableTextures)
{
lowp vec4 tcol = texture2D(texture, textureCoordVarying);
if (mixNoise)
{
//tcol = (0.30 + 0.75*fract(sin(noisePosition.y*0.7 + noisePosition.x*0.05 + time*1.2) + sin(noisePosition.x + noisePosition.y*0.02 + time*1.))) * tcol;
//tcol = smoothNoise(noisePosition + vec2(time/10.0, time/10.0)) * tcol;
tcol = interpolatedNoise(noisePosition + vec2(time/10.0, time/10.0)) * tcol;
}
/*
if (enableLighting && !enableBevels)
{
// If has provided color and texture color is blank, use the provided color
col = mix(colorVarying, tcol, tcol.w); // mix with even amounts
if (enableRampShading)
{
// Assumes ramp loaded in to texture slot 2
//col = col * texture2D(texture, vec2(0.25 + min(light, 1.0)*0.125, max(0.0,min(visibility/2.0,1.0))*0.125));//0.05));
col = col * texture2D(texture, vec2(0.25 + min(lightVarying, 1.0)*0.125, mod(textureCoordVarying.x+textureCoordVarying.y, 0.125) ));
}
else
{
col = col * vec4(lightVarying);
}
}
else
*/
if (enableLighting)
{
lowp vec3 n3 = normalVarying;//vec3(0.0);
lowp vec3 nr = n3;
//vec3 lightDirection = lightPosition.xyz - positionVarying.xyz;
float n_dot_l = lightVarying;
if (false && enableBevels)
{
lowp vec2 n1 = vec2(0.0);
lowp vec2 n2 = vec2(0.0);
lowp vec2 textureCoordVarying1 = textureCoordVarying + vec2( 0.00000, 0.00012 );
lowp vec2 textureCoordVarying2 = textureCoordVarying + vec2( 0.00012, 0.00000 );
lowp vec2 textureCoordVarying3 = textureCoordVarying + vec2( 0.00000, -0.00012 );
lowp vec2 textureCoordVarying4 = textureCoordVarying + vec2(-0.00012, 0.00000 );
n1.x = (1.0 - texture2D(texture, textureCoordVarying1).a);
n1.y = (1.0 - texture2D(texture, textureCoordVarying2).a);
n2.x = (1.0 - texture2D(texture, textureCoordVarying3).a);
n2.y = (1.0 - texture2D(texture, textureCoordVarying4).a);
n1 = n1 - n2;
nr.x = n3.x - n3.z * n1.x + n3.y * n1.x;
nr.y = n3.y + n3.x * n1.x - n3.z * n1.y;
nr.z = n3.z + n3.x * n1.y + n3.y * n1.y;
nr = normalize(nr);
vec3 lightDirection = lightPosition.xyz - positionVarying.xyz;
n_dot_l = max(n_dot_l, dot(nr, normalize(lightDirection)));
}
// If has provided color and texture color is blank, use the provided color
col = mix(colorVarying, tcol, tcol.w); // mix with even amounts
//highp vec4 col = vec4(tcol.xyz + colorVarying.xyz, tcol.a * colorVarying.a); // blend using alpha
if (enableRampShading)
{
// Assumes ramp loaded in to texture slot 2
float rampIndex = min(max(0.3, 0.3 * n_dot_l + 0.7), 1.0);
//col = col * texture2D(texture, vec2(0.25 + rampIndex*0.125, max(0.0,min(visibility/2.0,1.0))*0.125));//0.05));
col = (1.0 - inShadow) * col * texture2D(texture, vec2(0.25 + rampIndex*0.125, 0.5*0.125));//0.05));
//col = col * texture2D(texture, vec2(0.25 + min(light, 1.0)*0.125, mod(textureCoordVarying.x+textureCoordVarying.y, 0.125) ));
}
else
{
float light = max(0.5, (0.8 - inShadow) * n_dot_l + 0.3);
col = col * vec4(light);
//col = mix(col, lightCol, 0.05);
}
}
else
{
col = mix(colorVarying, tcol, tcol.w);
}
/*
// cube texturing idea - kind of could make something like minecraft blocks with this approach
vec2 tileMapPos = vec2(3.0 * 0.125 + floor(tcol.r*(255.0/16.0))/16.0 * 0.125, fract(tcol.r*(255.0/16.0)) * 0.125);
tileMapPos = tileMapPos + vec2(fract(textureCoordVarying.x*2047.5)/16.0 * 0.125, fract(textureCoordVarying.y*2047.5)/16.0 * 0.125);
col = mix(col, texture2D(texture, tileMapPos), 0.3);
*/
}
else
{
//col = interpolatedNoise(noisePosition) * colorVarying; // ignore texture colors
col = colorVarying; // ignore texture colors
}
col = col * visibility;
// Distance fog
if (enableDistanceFog)
{
col = mix(vec4(0.3, 0.3, 0.3, 1.0) * visibility, col, clamp((5.0 - dist)/(5.0 - 3.0), 0.0, 1.0 ));
}
gl_FragColor = col;
// Debugging showing the triangle edges
if (debugTriangles) {
const float threshold = 0.125;
if (barycentricVarying.x < threshold || barycentricVarying.y < threshold || barycentricVarying.z < threshold)
{
gl_FragColor = vec4(0.8, 0.8, 0.9, 1.0) * col;
}
}
}
)";
const char* s_simpleVertexShader = R"(
attribute vec4 position;
attribute vec4 delta;
attribute vec4 animParams;
attribute vec4 color;
varying lowp vec4 colorVarying;
uniform mat4 modelViewProjectionMatrix;
uniform float time;
void main()
{
vec4 pos = position;
float off = animParams.x * animParams.y;
float modulus = mod(position.x + delta.x * time - off, 1000.0 + animParams.y);
pos.x = modulus + off;
colorVarying = color;
gl_Position = modelViewProjectionMatrix * pos;
}
)";
const char* s_simpleFragmentShader = R"(
varying lowp vec4 colorVarying;
void main()
{
gl_FragColor = colorVarying;
}
)";
const char* s_quadVertexShader = R"(
const lowp vec2 madd = vec2(0.5,0.5);
attribute vec2 vertexIn;
varying vec2 textureCoord;
uniform lowp float screenW;
uniform lowp float screenH;
uniform lowp float t;
void main()
{
textureCoord = vertexIn.xy * madd + madd;
textureCoord.x = textureCoord.x * screenW;
textureCoord.y = textureCoord.y * screenH;
gl_Position = vec4(vertexIn.xy, 0.0, 1.0);
}
)";
const char* s_quadFragmentShader = R"(
uniform sampler2D texture;
varying lowp vec2 textureCoord;
void main()
{
gl_FragColor = texture2D(texture, textureCoord);
}
)";
const char* s_shadowVertexShader = R"(
attribute vec4 position;
attribute vec4 delta;
attribute vec4 animParams;
attribute vec4 barycentric;
attribute vec3 normal;
attribute vec4 color; // almost deprecated as will come from textures
uniform highp mat4 modelViewProjectionMatrix;
uniform float time;
uniform vec4 translation;
void main()
{
float off = animParams.x * animParams.y;
float modulus = mod(position.x + translation.x + delta.x * time - off, 1000.0 + animParams.y);
float x = modulus + off;
highp vec4 pos = position + translation;
pos.x = x;
gl_Position = modelViewProjectionMatrix * pos;
}
)";
const char* s_shadowFragmentShader = "void main(){}";
const char* s_hudVertexShader = R"(
attribute vec2 position;
attribute vec3 textureCoords;
attribute vec4 color;
attribute vec4 barycentric;
attribute vec3 normal;
varying lowp vec2 textureCoord;
varying lowp vec4 col2;
uniform vec2 invScreen;
uniform float t;
void main()
{
vec2 tmp;
float m = 0.0;
float f = 0.0;
// Perhaps could move this out and on to CPU and make textureCoords 4 values, u,v,xIdx,yIdx
m = mod(textureCoords.z,8.0);
f = floor(textureCoords.z/8.0);
tmp = vec2(m*256.0, f*256.0);
textureCoord = (textureCoords.xy+tmp) * vec2(1.0/2048.0, 1.0/2048.0);
col2 = color;
gl_Position = vec4(position * invScreen + vec2(-1.0,1.0), 0.0, 1.0);
}
)";
const char* s_hudFragmentShader = R"(
uniform sampler2D texture;
varying lowp vec2 textureCoord;
varying lowp vec4 col2;
void main()
{
lowp vec4 tcol = texture2D(texture, textureCoord);
gl_FragColor = vec4(tcol.xyz + col2.xyz, tcol.a * col2.a);
// gl_FragColor = vec4(col2.xyz, tcol.a);
}
)";