OpenGL ES 2.0 support (#187)
* WIP gles2 compat * More gles2 compat. Playable with ANGLE now, with some rendering bugs. * fix matrix mult. order in generic laser shader * gles20: fix indexed rendering * Update docs about gles20 status * fix formatting
This commit is contained in:
parent
44bd09bada
commit
7474ff3a25
34 changed files with 304 additions and 94 deletions
15
README.rst
15
README.rst
|
@ -15,7 +15,7 @@ Installation
|
|||
Dependencies
|
||||
^^^^^^^^^^^^
|
||||
|
||||
- OpenGL >= 3.3 or OpenGL ES >= 3.0
|
||||
- OpenGL >= 3.3 or OpenGL ES >= 3.0 or OpenGL ES >= 2.0 (with some extensions)
|
||||
- SDL2 >= 2.0.6
|
||||
- SDL2_mixer >= 2.0.4
|
||||
- freetype2
|
||||
|
@ -108,8 +108,17 @@ Alternatively, do this to make GLES 3.0 the default backend:
|
|||
|
||||
meson configure -Dr_default=gles30
|
||||
|
||||
Note that while it's also possible to enable a GLES 2.0 backend, it's currently
|
||||
not functional.
|
||||
The OpenGL ES 2.0 backend can be enabled similarly, using ``gles20`` instead of
|
||||
``gles30``. However, it requires a few extensions to function correctly, most
|
||||
notably:
|
||||
|
||||
- ``OES_depth_texture`` or ``GL_ANGLE_depth_texture``
|
||||
- ``OES_standard_derivatives``
|
||||
- ``OES_vertex_array_object``
|
||||
- ``EXT_frag_depth``
|
||||
- ``EXT_instanced_arrays`` or ``ANGLE_instanced_arrays`` or
|
||||
``NV_instanced_arrays``
|
||||
|
||||
|
||||
Where are my replays, screenshots and settings?
|
||||
-----------------------------------------------
|
||||
|
|
|
@ -117,10 +117,11 @@ Video and OpenGL
|
|||
|
||||
- ``gl33``: the OpenGL 3.3 Core renderer
|
||||
- ``gles30``: the OpenGL ES 3.0 renderer
|
||||
- ``gles20``: the OpenGL ES 2.0 renderer
|
||||
- ``null``: the no-op renderer (nothing is displayed)
|
||||
|
||||
Note that the actual subset of usable backends, as well as the default
|
||||
choice, can be controlled by build options. The ``gles30`` backend is not
|
||||
choice, can be controlled by build options. The ``gles`` backends are not
|
||||
built by default.
|
||||
|
||||
**TAISEI_LIBGL**
|
||||
|
|
|
@ -10,10 +10,14 @@ UNIFORM(3) vec2 clear_origin;
|
|||
UNIFORM(4) int frames;
|
||||
UNIFORM(5) float progress;
|
||||
UNIFORM(6) sampler2D noise_tex;
|
||||
UNIFORM(7) float size;
|
||||
|
||||
ivec3 in_circle(vec2 pos, vec2 ofs, float a, vec2 origin, vec3 radius) {
|
||||
mat2 m = mat2(cos(a), -sin(a), sin(a), cos(a));
|
||||
return ivec3(lessThan(vec3(length(pos + m * ofs - origin)), radius));
|
||||
vec3 xor(vec3 a, vec3 b) {
|
||||
return abs(a - b);
|
||||
}
|
||||
|
||||
vec3 in_circle(vec2 pos, vec2 ofs, float a, vec2 origin, vec3 radius) {
|
||||
return step(vec3(length(pos + rot(a) * ofs - origin)), radius);
|
||||
}
|
||||
|
||||
vec3 f(float x, vec3 s) {
|
||||
|
@ -40,25 +44,24 @@ void main(void) {
|
|||
nclr.rgb = max(colormod * vec3(0.1, 0.1, 0.3), nclr.rgb);
|
||||
|
||||
vec2 p = texCoord * viewport;
|
||||
float s = sqrt(pow(viewport.x, 2) + pow(viewport.y, 2));
|
||||
float o = 32 * (1 + progress);
|
||||
ivec3 mask = ivec3(0);
|
||||
vec3 mask = vec3(0);
|
||||
float a = frames / 30.0;
|
||||
|
||||
ivec3 i = ivec3(1,2,3);
|
||||
vec3 q = 1.0 + 0.01 * i * progress;
|
||||
|
||||
mask = mask ^ in_circle(p, vec2(0, 0), 1*a, origin, s * f(pow(progress * 1.5, 1.5), 1.0*q));
|
||||
mask = mask ^ in_circle(p, vec2(o, 0), 1*a, origin, s * f(pow(progress * 1.5, 2.0), 1.0*q));
|
||||
mask = mask ^ in_circle(p, vec2(0, o), 1*a, origin, s * f(pow(progress * 1.5, 2.0), 1.0*q));
|
||||
mask = mask ^ in_circle(p, -vec2(o, 0), 1*a, origin, s * f(pow(progress * 1.5, 2.0), 1.0*q));
|
||||
mask = mask ^ in_circle(p, -vec2(0, o), 1*a, origin, s * f(pow(progress * 1.5, 2.0), 1.0*q));
|
||||
mask = xor(mask, in_circle(p, vec2(0, 0), 1*a, origin, size * f(pow(progress * 1.5, 1.5), 1.0*q)));
|
||||
mask = xor(mask, in_circle(p, vec2(o, 0), 1*a, origin, size * f(pow(progress * 1.5, 2.0), 1.0*q)));
|
||||
mask = xor(mask, in_circle(p, vec2(0, o), 1*a, origin, size * f(pow(progress * 1.5, 2.0), 1.0*q)));
|
||||
mask = xor(mask, in_circle(p, -vec2(o, 0), 1*a, origin, size * f(pow(progress * 1.5, 2.0), 1.0*q)));
|
||||
mask = xor(mask, in_circle(p, -vec2(0, o), 1*a, origin, size * f(pow(progress * 1.5, 2.0), 1.0*q)));
|
||||
|
||||
mask = mask ^ in_circle(p, vec2(0, 0), -2*a, origin, s * f(pow(progress * 1.5, 1.5/1.5), 1.0*q));
|
||||
mask = mask ^ in_circle(p, vec2(o, 0), -2*a, origin, s * f(pow(progress * 1.5, 1.5/2.0), 1.0*q));
|
||||
mask = mask ^ in_circle(p, vec2(0, o), -2*a, origin, s * f(pow(progress * 1.5, 1.5/2.0), 1.0*q));
|
||||
mask = mask ^ in_circle(p, -vec2(o, 0), -2*a, origin, s * f(pow(progress * 1.5, 1.5/2.0), 1.0*q));
|
||||
mask = mask ^ in_circle(p, -vec2(0, o), -2*a, origin, s * f(pow(progress * 1.5, 1.5/2.0), 1.0*q));
|
||||
mask = xor(mask, in_circle(p, vec2(0, 0), -2*a, origin, size * f(pow(progress * 1.5, 1.5/1.5), 1.0*q)));
|
||||
mask = xor(mask, in_circle(p, vec2(o, 0), -2*a, origin, size * f(pow(progress * 1.5, 1.5/2.0), 1.0*q)));
|
||||
mask = xor(mask, in_circle(p, vec2(0, o), -2*a, origin, size * f(pow(progress * 1.5, 1.5/2.0), 1.0*q)));
|
||||
mask = xor(mask, in_circle(p, -vec2(o, 0), -2*a, origin, size * f(pow(progress * 1.5, 1.5/2.0), 1.0*q)));
|
||||
mask = xor(mask, in_circle(p, -vec2(0, o), -2*a, origin, size * f(pow(progress * 1.5, 1.5/2.0), 1.0*q)));
|
||||
|
||||
fragColor = mix(pclr, nclr, vec4(mask, 0));
|
||||
}
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
#version 330 core
|
||||
|
||||
#include "lib/fxaa.glslh"
|
||||
#include "interface/standard.glslh"
|
||||
|
||||
UNIFORM(1) sampler2D depth;
|
||||
VARYING(3) vec4 fxaa_tc;
|
||||
#include "interface/fxaa.glslh"
|
||||
|
||||
void main(void) {
|
||||
fragColor = vec4(fxaa(tex, fxaa_tc), 1);
|
||||
gl_FragDepth = texture(depth, fxaa_tc.xy).r;
|
||||
fragColor = vec4(fxaa(
|
||||
tex,
|
||||
v_rcpFrame,
|
||||
v_coordNW,
|
||||
v_coordNE,
|
||||
v_coordSW,
|
||||
v_coordSE,
|
||||
v_coordM
|
||||
), 1);
|
||||
gl_FragDepth = texture(depth, v_coordM).r;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
#version 330 core
|
||||
|
||||
#include "lib/fxaa.glslh"
|
||||
#include "interface/standard.glslh"
|
||||
#include "interface/fxaa.glslh"
|
||||
#include "lib/render_context.glslh"
|
||||
|
||||
VARYING(3) vec4 fxaa_tc;
|
||||
|
||||
void main(void) {
|
||||
gl_Position = r_projectionMatrix * r_modelViewMatrix * vec4(position, 1.0);
|
||||
fxaa_tc = fxaaCoords(tex, texCoordRawIn);
|
||||
v_rcpFrame = 1.0 / tex_SIZE;
|
||||
fxaaCoords(
|
||||
texCoordRawIn,
|
||||
v_rcpFrame,
|
||||
v_coordNW,
|
||||
v_coordNE,
|
||||
v_coordSW,
|
||||
v_coordSE,
|
||||
v_coordM
|
||||
);
|
||||
}
|
||||
|
|
29
resources/00-taisei.pkgdir/shader/interface/fxaa.glslh
Normal file
29
resources/00-taisei.pkgdir/shader/interface/fxaa.glslh
Normal file
|
@ -0,0 +1,29 @@
|
|||
|
||||
#ifndef I_FXAA_H
|
||||
#define I_FXAA_H
|
||||
|
||||
#include "../lib/defs.glslh"
|
||||
|
||||
#ifdef VERT_STAGE
|
||||
ATTRIBUTE(0) vec3 position;
|
||||
// ATTRIBUTE(1) vec3 normalIn;
|
||||
ATTRIBUTE(2) vec2 texCoordRawIn;
|
||||
#endif
|
||||
|
||||
#ifdef FRAG_STAGE
|
||||
OUT(0) vec4 fragColor;
|
||||
#endif
|
||||
|
||||
UNIFORM(0) sampler2D tex;
|
||||
UNIFORM(1) vec2 tex_SIZE;
|
||||
UNIFORM(2) sampler2D depth;
|
||||
|
||||
VARYING(0) vec2 v_coordNW;
|
||||
VARYING(1) vec2 v_coordNE;
|
||||
VARYING(2) vec2 v_coordSW;
|
||||
VARYING(3) vec2 v_coordSE;
|
||||
VARYING(4) vec2 v_coordM;
|
||||
VARYING(5) vec2 v_coordRaw;
|
||||
VARYING(6) vec2 v_rcpFrame;
|
||||
|
||||
#endif
|
|
@ -5,6 +5,7 @@
|
|||
#include "interface/standard.glslh"
|
||||
|
||||
ATTRIBUTE(3) vec4 instance_pos_delta;
|
||||
ATTRIBUTE(4) float instance_width;
|
||||
|
||||
UNIFORM(1) float timeshift;
|
||||
UNIFORM(2) float width;
|
||||
|
@ -14,8 +15,8 @@ UNIFORM(4) int span;
|
|||
#include "lasers/vertex_pos.glslh"
|
||||
|
||||
void main(void) {
|
||||
vec2 pos = laser_vertex_pos(instance_pos_delta.xy, instance_pos_delta.zw);
|
||||
gl_Position = r_modelViewMatrix * r_projectionMatrix * vec4(pos, 0.0, 1.0);
|
||||
vec2 pos = laser_vertex_pos(instance_pos_delta.xy, instance_pos_delta.zw, instance_width);
|
||||
gl_Position = r_projectionMatrix * r_modelViewMatrix * vec4(pos, 0.0, 1.0);
|
||||
texCoord = (r_textureMatrix * vec4(texCoordRawIn, 0.0, 1.0)).xy;
|
||||
texCoordRaw = texCoordRawIn;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,12 @@ void main(void) {
|
|||
vec2 p = pos_rule(gl_InstanceID * 0.5 + timeshift);
|
||||
vec2 d = p - pos_rule(gl_InstanceID * 0.5 + timeshift - 0.1);
|
||||
|
||||
vec2 pos = laser_vertex_pos(p, d);
|
||||
float t1 = gl_InstanceID - span / 2;
|
||||
float tail = span / 1.9;
|
||||
float s = -0.75 / pow(tail, 2) * (t1 - tail) * (t1 + tail);
|
||||
s = pow(s, width_exponent);
|
||||
|
||||
vec2 pos = laser_vertex_pos(p, d, s);
|
||||
gl_Position = r_projectionMatrix * r_modelViewMatrix * vec4(pos, 0.0, 1.0);
|
||||
texCoord = (r_textureMatrix * vec4(texCoordRawIn, 0.0, 1.0)).xy;
|
||||
texCoordRaw = texCoordRawIn;
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
|
||||
vec2 laser_vertex_pos(vec2 origin, vec2 delta) {
|
||||
vec2 laser_vertex_pos(vec2 origin, vec2 delta, float fragment_width) {
|
||||
vec2 v = position.xy;
|
||||
float t1 = gl_InstanceID - span / 2;
|
||||
float tail = span / 1.9;
|
||||
float s = -0.75 / pow(tail, 2) * (t1 - tail) * (t1 + tail);
|
||||
float a = -angle(delta);
|
||||
mat2 m = mat2(cos(a), -sin(a), sin(a), cos(a));
|
||||
|
||||
v.x *= width * 1.5 * length(delta);
|
||||
v.y *= width * pow(s, width_exponent);
|
||||
v.y *= width * fragment_width;;
|
||||
|
||||
return m * v + origin;
|
||||
}
|
||||
|
|
|
@ -37,4 +37,8 @@
|
|||
#define NATIVE_ORIGIN_BOTTOMLEFT
|
||||
#endif
|
||||
|
||||
#if defined(BACKEND_GLES20)
|
||||
#include "legacy_compat.glslh"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,14 +24,20 @@
|
|||
|
||||
#ifdef FRAG_STAGE
|
||||
|
||||
vec3 fxaa(sampler2D tex, vec4 posPos) {
|
||||
vec2 rcpFrame = vec2(1.0) / textureSize(tex, 0);
|
||||
|
||||
vec3 rgbNW = textureLod(tex, posPos.zw, 0).rgb;
|
||||
vec3 rgbNE = textureLodOffset(tex, posPos.zw, 0, ivec2(1, 0)).rgb;
|
||||
vec3 rgbSW = textureLodOffset(tex, posPos.zw, 0, ivec2(0, 1)).rgb;
|
||||
vec3 rgbSE = textureLodOffset(tex, posPos.zw, 0, ivec2(1, 1)).rgb;
|
||||
vec3 rgbM = textureLod(tex, posPos.xy, 0).rgb;
|
||||
vec3 fxaa(
|
||||
sampler2D tex,
|
||||
vec2 rcpFrame,
|
||||
vec2 coordNW,
|
||||
vec2 coordNE,
|
||||
vec2 coordSW,
|
||||
vec2 coordSE,
|
||||
vec2 coordM
|
||||
) {
|
||||
vec3 rgbNW = textureLod(tex, coordNW, 0).rgb;
|
||||
vec3 rgbNE = textureLod(tex, coordNE, 0).rgb;
|
||||
vec3 rgbSW = textureLod(tex, coordSW, 0).rgb;
|
||||
vec3 rgbSE = textureLod(tex, coordSE, 0).rgb;
|
||||
vec3 rgbM = textureLod(tex, coordM, 0).rgb;
|
||||
|
||||
vec3 luma = vec3(0.299, 0.587, 0.114);
|
||||
float lumaNW = dot(rgbNW, luma);
|
||||
|
@ -56,13 +62,13 @@ vec3 fxaa(sampler2D tex, vec4 posPos) {
|
|||
dir = min(vec2(FXAA_SPAN_MAX), max(vec2(-FXAA_SPAN_MAX), dir * rcpDirMin)) * rcpFrame.xy;
|
||||
|
||||
vec3 rgbA = 0.5 * (
|
||||
textureLod(tex, posPos.xy + dir * (1.0/3.0 - 0.5), 0).rgb +
|
||||
textureLod(tex, posPos.xy + dir * (2.0/3.0 - 0.5), 0).rgb
|
||||
textureLod(tex, coordM + dir * (1.0/3.0 - 0.5), 0).rgb +
|
||||
textureLod(tex, coordM + dir * (2.0/3.0 - 0.5), 0).rgb
|
||||
);
|
||||
|
||||
vec3 rgbB = rgbA * 0.5 + 0.25 * (
|
||||
textureLod(tex, posPos.xy + dir * (0.0/3.0 - 0.5), 0).rgb +
|
||||
textureLod(tex, posPos.xy + dir * (3.0/3.0 - 0.5), 0).rgb
|
||||
textureLod(tex, coordM + dir * (0.0/3.0 - 0.5), 0).rgb +
|
||||
textureLod(tex, coordM + dir * (3.0/3.0 - 0.5), 0).rgb
|
||||
);
|
||||
|
||||
float lumaB = dot(rgbB, luma);
|
||||
|
@ -78,9 +84,21 @@ vec3 fxaa(sampler2D tex, vec4 posPos) {
|
|||
|
||||
#ifdef VERT_STAGE
|
||||
|
||||
vec4 fxaaCoords(sampler2D tex, vec2 tc) {
|
||||
vec2 rcpFrame = vec2(1.0) / textureSize(tex, 0);
|
||||
return vec4(tc, tc - (rcpFrame * (0.5 + FXAA_SUBPIX_SHIFT)));
|
||||
void fxaaCoords(
|
||||
in vec2 texCoord,
|
||||
in vec2 rcpFrame,
|
||||
out vec2 o_coordNW,
|
||||
out vec2 o_coordNE,
|
||||
out vec2 o_coordSW,
|
||||
out vec2 o_coordSE,
|
||||
out vec2 o_coordM
|
||||
) {
|
||||
vec2 texCoordShifted = texCoord - (rcpFrame * (0.5 + FXAA_SUBPIX_SHIFT));
|
||||
o_coordNW = texCoordShifted + vec2( 0.0, 0.0) * rcpFrame;
|
||||
o_coordNE = texCoordShifted + vec2( 1.0, 0.0) * rcpFrame;
|
||||
o_coordSW = texCoordShifted + vec2( 0.0, 1.0) * rcpFrame;
|
||||
o_coordSE = texCoordShifted + vec2( 1.0, 1.0) * rcpFrame;
|
||||
o_coordM = texCoord;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
17
resources/00-taisei.pkgdir/shader/lib/legacy_compat.glslh
Normal file
17
resources/00-taisei.pkgdir/shader/lib/legacy_compat.glslh
Normal file
|
@ -0,0 +1,17 @@
|
|||
|
||||
#ifndef LEGACY_COMPAT_H
|
||||
#define LEGACY_COMPAT_H
|
||||
|
||||
#define LEGACY
|
||||
|
||||
#define textureLod(sampler, uv, lod) texture(sampler, uv)
|
||||
// #define textureLodOffset(sampler, uv, lod) texture(sampler, uv)
|
||||
#define textureGrad(sampler, uv, dx, dy) texture(sampler, uv)
|
||||
|
||||
#define tanh _tanh_compat
|
||||
float tanh(float x) {
|
||||
float e2x = exp(2.0 * x);
|
||||
return (e2x - 1.0) / (e2x + 1.0);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -10,10 +10,14 @@ UNIFORM(3) vec2 clear_origin;
|
|||
UNIFORM(4) int frames;
|
||||
UNIFORM(5) float progress;
|
||||
UNIFORM(6) sampler2D noise_tex;
|
||||
UNIFORM(7) float size;
|
||||
|
||||
ivec3 in_circle(vec2 pos, vec2 ofs, float a, vec2 origin, vec3 radius) {
|
||||
mat2 m = mat2(cos(a), -sin(a), sin(a), cos(a));
|
||||
return ivec3(lessThan(vec3(length(pos + m * ofs - origin)), radius));
|
||||
vec3 xor(vec3 a, vec3 b) {
|
||||
return abs(a - b);
|
||||
}
|
||||
|
||||
vec3 in_circle(vec2 pos, vec2 ofs, float a, vec2 origin, vec3 radius) {
|
||||
return step(vec3(length(pos + rot(a) * ofs - origin)), radius);
|
||||
}
|
||||
|
||||
vec3 f(float x, vec3 s) {
|
||||
|
@ -40,25 +44,24 @@ void main(void) {
|
|||
nclr.rgb = max(colormod * vec3(0.1, 0.1, 0.3), nclr.rgb);
|
||||
|
||||
vec2 p = texCoord * viewport;
|
||||
float s = sqrt(pow(viewport.x, 2) + pow(viewport.y, 2));
|
||||
float o = 32 * (1 + progress);
|
||||
ivec3 mask = ivec3(0);
|
||||
vec3 mask = vec3(0);
|
||||
float a = frames / 30.0;
|
||||
|
||||
vec3 i = vec3(1, 2, 3);
|
||||
vec3 q = 1.0 + 0.01 * i * progress;
|
||||
|
||||
mask = mask ^ in_circle(p, vec2(0, 0), 1*a, origin, s * f(pow(progress * 1.5, 1.5), 1.0*q));
|
||||
mask = mask ^ in_circle(p, vec2(o, 0), 1*a, origin, s * f(pow(progress * 1.5, 2.0), 1.0*q));
|
||||
mask = mask ^ in_circle(p, vec2(0, o), 1*a, origin, s * f(pow(progress * 1.5, 2.0), 1.0*q));
|
||||
mask = mask ^ in_circle(p, -vec2(o, 0), 1*a, origin, s * f(pow(progress * 1.5, 2.0), 1.0*q));
|
||||
mask = mask ^ in_circle(p, -vec2(0, o), 1*a, origin, s * f(pow(progress * 1.5, 2.0), 1.0*q));
|
||||
mask = xor(mask, in_circle(p, vec2(0, 0), 1*a, origin, size * f(pow(progress * 1.5, 1.5), 1.0*q)));
|
||||
mask = xor(mask, in_circle(p, vec2(o, 0), 1*a, origin, size * f(pow(progress * 1.5, 2.0), 1.0*q)));
|
||||
mask = xor(mask, in_circle(p, vec2(0, o), 1*a, origin, size * f(pow(progress * 1.5, 2.0), 1.0*q)));
|
||||
mask = xor(mask, in_circle(p, -vec2(o, 0), 1*a, origin, size * f(pow(progress * 1.5, 2.0), 1.0*q)));
|
||||
mask = xor(mask, in_circle(p, -vec2(0, o), 1*a, origin, size * f(pow(progress * 1.5, 2.0), 1.0*q)));
|
||||
|
||||
mask = xor(mask, in_circle(p, vec2(0, 0), -2*a, clear_origin, size * (1 - pow(vec3(2 - 2 * progress), 4+0.10*i))));
|
||||
mask = xor(mask, in_circle(p, vec2(o, 0), -2*a, clear_origin, size * (1 - pow(vec3(2 - 2 * progress), 2+0.05*i))));
|
||||
mask = xor(mask, in_circle(p, -vec2(o, 0), -2*a, clear_origin, size * (1 - pow(vec3(2 - 2 * progress), 2+0.05*i))));
|
||||
mask = xor(mask, in_circle(p, vec2(0, o), -2*a, clear_origin, size * (1 - pow(vec3(2 - 2 * progress), 2+0.05*i))));
|
||||
mask = xor(mask, in_circle(p, -vec2(0, o), -2*a, clear_origin, size * (1 - pow(vec3(2 - 2 * progress), 2+0.05*i))));
|
||||
|
||||
mask = mask ^ in_circle(p, vec2(0, 0), -2*a, clear_origin, s * (1 - pow(vec3(2 - 2 * progress), 4+0.10*i)));
|
||||
mask = mask ^ in_circle(p, vec2(o, 0), -2*a, clear_origin, s * (1 - pow(vec3(2 - 2 * progress), 2+0.05*i)));
|
||||
mask = mask ^ in_circle(p, -vec2(o, 0), -2*a, clear_origin, s * (1 - pow(vec3(2 - 2 * progress), 2+0.05*i)));
|
||||
mask = mask ^ in_circle(p, vec2(0, o), -2*a, clear_origin, s * (1 - pow(vec3(2 - 2 * progress), 2+0.05*i)));
|
||||
mask = mask ^ in_circle(p, -vec2(0, o), -2*a, clear_origin, s * (1 - pow(vec3(2 - 2 * progress), 2+0.05*i)));
|
||||
|
||||
fragColor = mix(pclr, nclr, vec4(mask, 0));
|
||||
}
|
||||
|
|
|
@ -1221,6 +1221,7 @@ static void boss_death_effect_draw_overlay(Projectile *p, int t) {
|
|||
r_uniform_vec2("origin", creal(p->pos), VIEWPORT_H - cimag(p->pos));
|
||||
r_uniform_vec2("clear_origin", creal(p->pos), VIEWPORT_H - cimag(p->pos));
|
||||
r_uniform_vec2("viewport", VIEWPORT_W, VIEWPORT_H);
|
||||
r_uniform_float("size", hypotf(VIEWPORT_W, VIEWPORT_H));
|
||||
draw_framebuffer_tex(framebuffers->back, VIEWPORT_W, VIEWPORT_H);
|
||||
fbpair_swap(framebuffers);
|
||||
|
||||
|
|
13
src/laser.c
13
src/laser.c
|
@ -32,6 +32,7 @@ static struct {
|
|||
typedef struct LaserInstancedAttribs {
|
||||
float pos[2];
|
||||
float delta[2];
|
||||
float fragment_width;
|
||||
} LaserInstancedAttribs;
|
||||
|
||||
static void lasers_ent_predraw_hook(EntityInterface *ent, void *arg);
|
||||
|
@ -78,7 +79,8 @@ void lasers_preload(void) {
|
|||
|
||||
// Per-instance attributes (for our own buffer, bound at 1)
|
||||
// pos and delta packed into a single attribute
|
||||
{ { 4, VA_FLOAT, VA_CONVERT_FLOAT, 1 }, sz_attr, INSTANCE_OFS(pos), 1 },
|
||||
{ { 4, VA_FLOAT, VA_CONVERT_FLOAT, 1 }, sz_attr, INSTANCE_OFS(pos), 1 },
|
||||
{ { 1, VA_FLOAT, VA_CONVERT_FLOAT, 1 }, sz_attr, INSTANCE_OFS(fragment_width), 1 },
|
||||
};
|
||||
|
||||
#undef VERTEX_OFS
|
||||
|
@ -222,7 +224,6 @@ static void draw_laser_curve_specialized(Laser *l) {
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
r_shader_ptr(l->shader);
|
||||
r_color(&l->color);
|
||||
r_uniform_sampler("tex", "part/lasercurve");
|
||||
|
@ -271,15 +272,23 @@ static void draw_laser_curve_generic(Laser *l) {
|
|||
SDL_RWops *stream = r_vertex_buffer_get_stream(lasers.vbuf);
|
||||
r_vertex_buffer_invalidate(lasers.vbuf);
|
||||
|
||||
float tail = instances / 1.9;
|
||||
float tail_factor = -0.75 / (tail * tail);
|
||||
|
||||
for(uint i = 0; i < instances; ++i) {
|
||||
cmplx pos = l->prule(l, i * 0.5 + timeshift);
|
||||
cmplx delta = pos - l->prule(l, i * 0.5 + timeshift - 0.1);
|
||||
|
||||
float t1 = i - instances / 2.0;
|
||||
float s = powf(tail_factor * (t1 - tail) * (t1 + tail), l->width_exponent);
|
||||
|
||||
LaserInstancedAttribs attr;
|
||||
attr.pos[0] = creal(pos);
|
||||
attr.pos[1] = cimag(pos);
|
||||
attr.delta[0] = creal(delta);
|
||||
attr.delta[1] = cimag(delta);
|
||||
attr.fragment_width = s;
|
||||
|
||||
SDL_RWwrite(stream, &attr, sizeof(attr), 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -858,6 +858,7 @@ static void player_death_effect_draw_overlay(Projectile *p, int t) {
|
|||
r_uniform_vec2("origin", creal(p->pos), VIEWPORT_H - cimag(p->pos));
|
||||
r_uniform_vec2("clear_origin", creal(global.plr.pos), VIEWPORT_H - cimag(global.plr.pos));
|
||||
r_uniform_vec2("viewport", VIEWPORT_W, VIEWPORT_H);
|
||||
r_uniform_float("size", hypotf(VIEWPORT_W, VIEWPORT_H));
|
||||
draw_framebuffer_tex(framebuffers->back, VIEWPORT_W, VIEWPORT_H);
|
||||
fbpair_swap(framebuffers);
|
||||
|
||||
|
|
|
@ -75,6 +75,10 @@ void r_shutdown(void) {
|
|||
B.shutdown();
|
||||
}
|
||||
|
||||
const char *r_backend_name(void) {
|
||||
return _r_backend.name;
|
||||
}
|
||||
|
||||
void r_shader_standard(void) {
|
||||
r_shader_ptr(R.progs.standard);
|
||||
}
|
||||
|
|
|
@ -432,6 +432,7 @@ SDL_Window* r_create_window(const char *title, int x, int y, int w, int h, uint3
|
|||
void r_init(void);
|
||||
void r_post_init(void);
|
||||
void r_shutdown(void);
|
||||
const char *r_backend_name(void);
|
||||
|
||||
r_feature_bits_t r_features(void);
|
||||
|
||||
|
@ -806,13 +807,7 @@ ShaderProgram* r_shader_get(const char *name) {
|
|||
|
||||
INLINE
|
||||
ShaderProgram* r_shader_get_optional(const char *name) {
|
||||
ShaderProgram *prog = get_resource_data(RES_SHADER_PROGRAM, name, RESF_OPTIONAL | RESF_UNSAFE);
|
||||
|
||||
if(!prog) {
|
||||
log_warn("shader program %s could not be loaded", name);
|
||||
}
|
||||
|
||||
return prog;
|
||||
return get_resource_data(RES_SHADER_PROGRAM, name, RESF_OPTIONAL | RESF_UNSAFE);
|
||||
}
|
||||
|
||||
INLINE
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "util/sha256.h"
|
||||
#include "rwops/all.h"
|
||||
|
||||
#define CACHE_VERSION 2
|
||||
#define CACHE_VERSION 3
|
||||
#define CRC_INIT 0
|
||||
|
||||
static uint8_t* shader_cache_construct_entry(const ShaderSource *src, size_t *out_size) {
|
||||
|
|
|
@ -258,7 +258,16 @@ bool _spirv_decompile(const ShaderSource *in, ShaderSource *out, const SPIRVDeco
|
|||
}
|
||||
|
||||
if(!glsl_version_supports_instanced_rendering(options->lang->glsl.version)) {
|
||||
SPVCCALL(spvc_compiler_require_extension(compiler, "GL_ARB_draw_instanced"));
|
||||
SPVCCALL(spvc_compiler_add_header_line(compiler,
|
||||
"#ifdef GL_ARB_draw_instanced\n"
|
||||
"#extension GL_ARB_draw_instanced : enable\n"
|
||||
"#endif\n"
|
||||
|
||||
"#ifdef GL_EXT_frag_depth\n"
|
||||
"#extension GL_EXT_frag_depth : enable\n"
|
||||
"#define gl_FragDepth gl_FragDepthEXT\n"
|
||||
"#endif\n"
|
||||
));
|
||||
}
|
||||
|
||||
SPVCCALL(spvc_compiler_create_compiler_options(compiler, &spvc_options));
|
||||
|
|
|
@ -110,7 +110,7 @@ bool spirv_transpile(const ShaderSource *in, ShaderSource *out, const SPIRVTrans
|
|||
|
||||
if(
|
||||
!shader_lang_supports_uniform_locations(&_in.lang) &&
|
||||
shader_lang_supports_uniform_locations(options->lang) &&
|
||||
// shader_lang_supports_uniform_locations(options->lang) &&
|
||||
_in.lang.lang == SHLANG_GLSL
|
||||
) {
|
||||
// HACK: This is annoying... shaderc/glslang does not support GL_ARB_explicit_uniform_location
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
static Uniform *sampler_uniforms;
|
||||
|
||||
Uniform* gl33_shader_uniform(ShaderProgram *prog, const char *uniform_name) {
|
||||
Uniform *gl33_shader_uniform(ShaderProgram *prog, const char *uniform_name) {
|
||||
return ht_get(&prog->uniforms, uniform_name, NULL);
|
||||
}
|
||||
|
||||
|
@ -212,11 +212,13 @@ static void gl33_commit_uniform(Uniform *uniform) {
|
|||
uniform->cache.update_last_idx = 0;
|
||||
}
|
||||
|
||||
static void* gl33_sync_uniform(const char *key, void *value, void *arg) {
|
||||
static void *gl33_sync_uniform(const char *key, void *value, void *arg) {
|
||||
Uniform *uniform = value;
|
||||
|
||||
// special case: for sampler uniforms, we have to construct the actual data from the texture pointers array.
|
||||
if(uniform->type == UNIFORM_SAMPLER) {
|
||||
Uniform *size_uniform = uniform->size_uniform;
|
||||
|
||||
for(uint i = 0; i < uniform->array_size; ++i) {
|
||||
Texture *tex = uniform->textures[i];
|
||||
|
||||
|
@ -226,6 +228,14 @@ static void* gl33_sync_uniform(const char *key, void *value, void *arg) {
|
|||
|
||||
GLuint unit = gl33_bind_texture(tex, true);
|
||||
gl33_update_uniform(uniform, i, 1, &unit);
|
||||
|
||||
if(size_uniform) {
|
||||
uint w, h;
|
||||
r_texture_get_size(tex, 0, &w, &h);
|
||||
vec2_noalign size = { w, h };
|
||||
gl33_update_uniform(size_uniform, i, 1, &size);
|
||||
gl33_commit_uniform(size_uniform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -358,6 +368,39 @@ static bool cache_uniforms(ShaderProgram *prog) {
|
|||
log_debug("%s = %i [array elements: %i; size: %zi bytes]", name, loc, uni.array_size, uni.array_size * uni.elem_size);
|
||||
}
|
||||
|
||||
ht_str2ptr_iter_t iter;
|
||||
ht_iter_begin(&prog->uniforms, &iter);
|
||||
while(iter.has_data) {
|
||||
Uniform *u = iter.value;
|
||||
|
||||
if(u->type == UNIFORM_SAMPLER) {
|
||||
const char *sampler_name = iter.key;
|
||||
const char size_suffix[] = "_SIZE";
|
||||
char size_uniform_name[strlen(sampler_name) + sizeof(size_suffix)];
|
||||
snprintf(size_uniform_name, sizeof(size_uniform_name), "%s%s", sampler_name, size_suffix);
|
||||
u->size_uniform = ht_get(&prog->uniforms, size_uniform_name, NULL);
|
||||
|
||||
if(u->size_uniform) {
|
||||
Uniform *size_uniform = u->size_uniform;
|
||||
|
||||
if(size_uniform->type != UNIFORM_VEC2) {
|
||||
log_warn("Size uniform %s has invalid type (should be vec2), ignoring", size_uniform_name);
|
||||
u->size_uniform = NULL;
|
||||
} else if(size_uniform->array_size != u->array_size) {
|
||||
log_warn("Size uniform %s has invalid array size (should be %i), ignoring", size_uniform_name, u->array_size);
|
||||
u->size_uniform = NULL;
|
||||
} else {
|
||||
log_debug("Bound size uniform: %s --> %s", sampler_name, size_uniform_name);
|
||||
}
|
||||
|
||||
assert(u->size_uniform != NULL); // fix your shader!
|
||||
}
|
||||
}
|
||||
|
||||
ht_iter_next(&iter);
|
||||
}
|
||||
ht_iter_end(&iter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -390,7 +433,7 @@ static void print_info_log(GLuint prog) {
|
|||
}
|
||||
}
|
||||
|
||||
static void* free_uniform(const char *key, void *data, void *arg) {
|
||||
static void *free_uniform(const char *key, void *data, void *arg) {
|
||||
Uniform *uniform = data;
|
||||
|
||||
if(uniform->type == UNIFORM_SAMPLER) {
|
||||
|
@ -412,7 +455,7 @@ void gl33_shader_program_destroy(ShaderProgram *prog) {
|
|||
free(prog);
|
||||
}
|
||||
|
||||
ShaderProgram* gl33_shader_program_link(uint num_objects, ShaderObject *shobjs[num_objects]) {
|
||||
ShaderProgram *gl33_shader_program_link(uint num_objects, ShaderObject *shobjs[num_objects]) {
|
||||
ShaderProgram *prog = calloc(1, sizeof(*prog));
|
||||
|
||||
prog->gl_handle = glCreateProgram();
|
||||
|
@ -454,6 +497,6 @@ void gl33_shader_program_set_debug_label(ShaderProgram *prog, const char *label)
|
|||
glcommon_set_debug_label(prog->debug_label, "Shader program", GL_PROGRAM, prog->gl_handle, label);
|
||||
}
|
||||
|
||||
const char* gl33_shader_program_get_debug_label(ShaderProgram *prog) {
|
||||
const char *gl33_shader_program_get_debug_label(ShaderProgram *prog) {
|
||||
return prog->debug_label;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,9 @@ struct Uniform {
|
|||
uint location;
|
||||
UniformType type;
|
||||
|
||||
// corresponding _SIZE uniform (for samplers; optional)
|
||||
Uniform *size_uniform;
|
||||
|
||||
struct {
|
||||
// buffer size = elem_size * array_size
|
||||
char *pending;
|
||||
|
@ -46,12 +49,12 @@ struct Uniform {
|
|||
|
||||
void gl33_sync_uniforms(ShaderProgram *prog);
|
||||
|
||||
ShaderProgram* gl33_shader_program_link(uint num_objects, ShaderObject *shobjs[num_objects]);
|
||||
ShaderProgram *gl33_shader_program_link(uint num_objects, ShaderObject *shobjs[num_objects]);
|
||||
void gl33_shader_program_destroy(ShaderProgram *prog);
|
||||
void gl33_shader_program_set_debug_label(ShaderProgram *prog, const char *label);
|
||||
const char* gl33_shader_program_get_debug_label(ShaderProgram *prog);
|
||||
|
||||
Uniform* gl33_shader_uniform(ShaderProgram *prog, const char *uniform_name);
|
||||
Uniform *gl33_shader_uniform(ShaderProgram *prog, const char *uniform_name);
|
||||
UniformType gl33_uniform_type(Uniform *uniform);
|
||||
void gl33_uniform(Uniform *uniform, uint offset, uint count, const void *data);
|
||||
void gl33_unref_texture_from_samplers(Texture *tex);
|
||||
|
|
|
@ -71,6 +71,11 @@ static void APIENTRY glcommon_debug(
|
|||
// HACK: Workaround for an ANGLE bug. Seems like it always reports the original array size for
|
||||
// uniform arrays, even if the arrays has been partially optimized out. Accessing the non-existent
|
||||
// elements then generates a GL_INVALID_OPERATION error, which should be safe to ignore.
|
||||
lvl = LOG_ERROR;
|
||||
}
|
||||
|
||||
if(lvl == LOG_FATAL && glext.version.is_ANGLE && !strcmp(message, "Invalid uniform location")) {
|
||||
// seriously?
|
||||
lvl = LOG_WARN;
|
||||
}
|
||||
|
||||
|
|
|
@ -168,6 +168,13 @@ GLenum glcommon_texture_base_format(GLenum internal_fmt) {
|
|||
case GL_RGBA8_SNORM: return GL_RGBA;
|
||||
case GL_SRGB8: return GL_RGB;
|
||||
case GL_SRGB8_ALPHA8: return GL_RGBA;
|
||||
|
||||
// GLES2 may use these as internal formats
|
||||
case GL_RED: return GL_RED;
|
||||
case GL_RG: return GL_RG;
|
||||
case GL_RGB: return GL_RGB;
|
||||
case GL_RGBA: return GL_RGBA;
|
||||
case GL_DEPTH_COMPONENT: return GL_DEPTH_COMPONENT;
|
||||
}
|
||||
|
||||
UNREACHABLE;
|
||||
|
|
|
@ -35,14 +35,18 @@ static void gles20_draw_indexed(VertexArray *varr, Primitive prim, uint firstidx
|
|||
void *state;
|
||||
gl33_begin_draw(varr, &state);
|
||||
|
||||
IndexBuffer *ibuf = varr->index_attachment;
|
||||
gles20_ibo_index_t *indices = ibuf->elements + firstidx;
|
||||
assert(indices < ibuf->elements + ibuf->num_elements);
|
||||
|
||||
if(instances) {
|
||||
if(base_instance) {
|
||||
glDrawElementsInstancedBaseInstance(gl_prim, count, GLES20_IBO_GL_DATATYPE, varr->index_attachment->elements, instances, base_instance);
|
||||
glDrawElementsInstancedBaseInstance(gl_prim, count, GLES20_IBO_GL_DATATYPE, indices, instances, base_instance);
|
||||
} else {
|
||||
glDrawElementsInstanced(gl_prim, count, GLES20_IBO_GL_DATATYPE, varr->index_attachment->elements, instances);
|
||||
glDrawElementsInstanced(gl_prim, count, GLES20_IBO_GL_DATATYPE, indices, instances);
|
||||
}
|
||||
} else {
|
||||
glDrawElements(gl_prim, count, GLES20_IBO_GL_DATATYPE, varr->index_attachment->elements);
|
||||
glDrawElements(gl_prim, count, GLES20_IBO_GL_DATATYPE, indices);
|
||||
}
|
||||
|
||||
gl33_end_draw(state);
|
||||
|
|
|
@ -155,7 +155,6 @@ void gles_init_texformats_table(void) {
|
|||
}
|
||||
|
||||
for(uint i = 0; i < sizeof(gles_texformats)/sizeof(*gles_texformats); ++i) {
|
||||
log_debug("fuck %i", i);
|
||||
gles_texformats[i].external_formats[0] = gles_texformats[i].primary_external_format;
|
||||
|
||||
if(!is_gles3) {
|
||||
|
@ -178,6 +177,10 @@ GLTexFormatCapabilities gles_texture_format_caps(GLenum internal_fmt) {
|
|||
*/
|
||||
|
||||
switch(internal_fmt) {
|
||||
case GL_RED:
|
||||
case GL_RG:
|
||||
case GL_RGB:
|
||||
case GL_RGBA:
|
||||
case GL_R8:
|
||||
case GL_RG8:
|
||||
case GL_RGB8:
|
||||
|
@ -227,6 +230,7 @@ GLTexFormatCapabilities gles_texture_format_caps(GLenum internal_fmt) {
|
|||
}
|
||||
break;
|
||||
|
||||
case GL_DEPTH_COMPONENT:
|
||||
case GL_DEPTH_COMPONENT16:
|
||||
case GL_DEPTH_COMPONENT24:
|
||||
// FIXME: Is there an extension that makes it filterable?
|
||||
|
|
|
@ -69,11 +69,25 @@ static void* load_shader_object_begin(const char *path, uint flags) {
|
|||
|
||||
struct shobj_load_data *ldata = calloc(1, sizeof(struct shobj_load_data));
|
||||
|
||||
char backend_macro[32] = "BACKEND_";
|
||||
{
|
||||
const char *backend_name = r_backend_name();
|
||||
char *out = backend_macro + sizeof("BACKEND_") - 1;
|
||||
for(const char *in = backend_name; *in;) {
|
||||
*out++ = toupper(*in++);
|
||||
}
|
||||
*out = 0;
|
||||
}
|
||||
|
||||
switch(type->lang) {
|
||||
case SHLANG_GLSL: {
|
||||
GLSLSourceOptions opts = {
|
||||
.version = { 330, GLSL_PROFILE_CORE },
|
||||
.stage = type->stage,
|
||||
.macros = (GLSLMacro[]) {
|
||||
{ backend_macro, "1" },
|
||||
{ NULL, },
|
||||
},
|
||||
};
|
||||
|
||||
if(!glsl_load_source(path, &ldata->source, &opts)) {
|
||||
|
|
|
@ -342,10 +342,12 @@ static void stage1_preload(void) {
|
|||
NULL);
|
||||
preload_resources(RES_SHADER_PROGRAM, RESF_DEFAULT,
|
||||
"blur5",
|
||||
"lasers/linear",
|
||||
"stage1_water",
|
||||
"zbuf_fog",
|
||||
NULL);
|
||||
preload_resources(RES_SHADER_PROGRAM, RESF_OPTIONAL,
|
||||
"lasers/linear",
|
||||
NULL);
|
||||
preload_resources(RES_ANIM, RESF_DEFAULT,
|
||||
"boss/cirno",
|
||||
NULL);
|
||||
|
|
|
@ -182,6 +182,8 @@ static void stage2_preload(void) {
|
|||
"bloom",
|
||||
"zbuf_fog",
|
||||
"alpha_depth",
|
||||
NULL);
|
||||
preload_resources(RES_SHADER_PROGRAM, RESF_OPTIONAL,
|
||||
"lasers/linear",
|
||||
NULL);
|
||||
preload_resources(RES_ANIM, RESF_DEFAULT,
|
||||
|
|
|
@ -174,6 +174,8 @@ static void stage3_preload(void) {
|
|||
"zbuf_fog",
|
||||
"glitch",
|
||||
"maristar_bombbg",
|
||||
NULL);
|
||||
preload_resources(RES_SHADER_PROGRAM, RESF_OPTIONAL,
|
||||
"lasers/accelerated",
|
||||
"lasers/sine_expanding",
|
||||
NULL);
|
||||
|
|
|
@ -232,6 +232,8 @@ static void stage4_preload(void) {
|
|||
preload_resources(RES_SHADER_PROGRAM, RESF_DEFAULT,
|
||||
"zbuf_fog",
|
||||
"sprite_negative",
|
||||
NULL);
|
||||
preload_resources(RES_SHADER_PROGRAM, RESF_OPTIONAL,
|
||||
"lasers/accelerated",
|
||||
NULL);
|
||||
preload_resources(RES_ANIM, RESF_DEFAULT,
|
||||
|
|
|
@ -163,6 +163,8 @@ static void stage5_preload(void) {
|
|||
NULL);
|
||||
preload_resources(RES_SHADER_PROGRAM, RESF_DEFAULT,
|
||||
"tower_light",
|
||||
NULL);
|
||||
preload_resources(RES_SHADER_PROGRAM, RESF_OPTIONAL,
|
||||
"lasers/linear",
|
||||
"lasers/accelerated",
|
||||
"lasers/iku_cathode",
|
||||
|
|
|
@ -305,6 +305,10 @@ static void stage6_preload(void) {
|
|||
NULL);
|
||||
preload_resources(RES_SHADER_PROGRAM, RESF_DEFAULT,
|
||||
"baryon_feedback",
|
||||
"stage6_sky",
|
||||
"tower_wall",
|
||||
NULL);
|
||||
preload_resources(RES_SHADER_PROGRAM, RESF_OPTIONAL,
|
||||
"lasers/accelerated",
|
||||
"lasers/circle",
|
||||
"lasers/elly_toe_fermion",
|
||||
|
@ -314,8 +318,6 @@ static void stage6_preload(void) {
|
|||
"lasers/linear",
|
||||
"lasers/maxwell",
|
||||
"lasers/sine",
|
||||
"stage6_sky",
|
||||
"tower_wall",
|
||||
NULL);
|
||||
preload_resources(RES_ANIM, RESF_DEFAULT,
|
||||
"boss/elly",
|
||||
|
|
Loading…
Reference in a new issue