From 8072a87ef226cc9d84578feae044d682e346b77f Mon Sep 17 00:00:00 2001 From: Shaun Reich Date: Fri, 23 Dec 2022 11:22:58 -0500 Subject: [PATCH] add rectangular outline to notes --- resources/shaders/notes.frag | 14 +++++++++----- src/resources/shaders.cpp | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/resources/shaders/notes.frag b/resources/shaders/notes.frag index fd9b8b2..127a430 100644 --- a/resources/shaders/notes.frag +++ b/resources/shaders/notes.frag @@ -36,19 +36,23 @@ void main(){ if( radiusPosition > 1.0){ discard; } - + // Fragment color. int cid = int(In.channel); fragColor.rgb = colorScale * mix(baseColor[cid], minorColor[cid], In.isMinor); - - if( radiusPosition > 0.8){ - fragColor.rgb *= 1.05; - } + if( radiusPosition > 0.4){ + //outer border + fragColor.rgb *= 1.5; + } else { + //inner + fragColor.rgb *= 0.8; + } float distFromBottom = horizontalMode ? normalizedCoord.x : normalizedCoord.y; float fadeOutFinal = min(fadeOut, 0.9999); distFromBottom = max(distFromBottom - fadeOutFinal, 0.0) / (1.0 - fadeOutFinal); float alpha = 1.0 - distFromBottom; + fragColor.a = alpha; } diff --git a/src/resources/shaders.cpp b/src/resources/shaders.cpp index 011c7a3..fdfc4ad 100644 --- a/src/resources/shaders.cpp +++ b/src/resources/shaders.cpp @@ -5,7 +5,7 @@ const std::unordered_map shaders = { { "flashes_vert", "#version 330\n layout(location = 0) in vec2 v;\n layout(location = 1) in int onChan;\n uniform float time;\n uniform vec2 inverseScreenSize;\n uniform float userScale = 1.0;\n uniform float keyboardHeight = 0.25;\n uniform int minNote;\n uniform float notesCount;\n uniform bool horizontalMode = false;\n vec2 flipIfNeeded(vec2 inPos){\n return horizontalMode ? vec2(inPos.y, -inPos.x) : inPos;\n }\n const float shifts[128] = float[](\n 0,0.5,1,1.5,2,3,3.5,4,4.5,5,5.5,6,7,7.5,8,8.5,9,10,10.5,11,11.5,12,12.5,13,14,14.5,15,15.5,16,17,17.5,18,18.5,19,19.5,20,21,21.5,22,22.5,23,24,24.5,25,25.5,26,26.5,27,28,28.5,29,29.5,30,31,31.5,32,32.5,33,33.5,34,35,35.5,36,36.5,37,38,38.5,39,39.5,40,40.5,41,42,42.5,43,43.5,44,45,45.5,46,46.5,47,47.5,48,49,49.5,50,50.5,51,52,52.5,53,53.5,54,54.5,55,56,56.5,57,57.5,58,59,59.5,60,60.5,61,61.5,62,63,63.5,64,64.5,65,66,66.5,67,67.5,68,68.5,69,70,70.5,71,71.5,72,73,73.5,74\n );\n const vec2 scale = 0.9*vec2(3.5,3.0);\n out INTERFACE {\n vec2 uv;\n float onChannel;\n float id;\n } Out;\n void main(){\n \n // Scale quad, keep the square ratio.\n float screenRatio = inverseScreenSize.y/inverseScreenSize.x;\n vec2 scalingFactor = vec2(1.0, horizontalMode ? (1.0/screenRatio) : screenRatio);\n vec2 scaledPosition = v * 2.0 * scale * userScale/notesCount * scalingFactor;\n // Shift based on note/flash id.\n vec2 globalShift = vec2(-1.0 + ((shifts[gl_InstanceID] - shifts[minNote]) * 2.0 + 1.0) / notesCount, 2.0 * keyboardHeight - 1.0);\n \n gl_Position = vec4(flipIfNeeded(scaledPosition + globalShift), 0.0 , 1.0) ;\n \n // Pass infos to the fragment shader.\n Out.uv = v;\n Out.onChannel = float(onChan);\n Out.id = float(gl_InstanceID);\n \n }\n "}, { "flashes_frag", "#version 330\n #define SETS_COUNT 8\n in INTERFACE {\n vec2 uv;\n float onChannel;\n float id;\n } In;\n uniform sampler2D textureFlash;\n uniform float time;\n uniform vec3 baseColor[SETS_COUNT];\n #define numberSprites 8.0\n out vec4 fragColor;\n float rand(vec2 co){\n return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);\n }\n void main(){\n \n // If not on, discard flash immediatly.\n int cid = int(In.onChannel);\n if(cid < 0){\n discard;\n }\n float mask = 0.0;\n \n // If up half, read from texture atlas.\n if(In.uv.y > 0.0){\n // Select a sprite, depending on time and flash id.\n float shift = floor(mod(15.0 * time, numberSprites)) + floor(rand(In.id * vec2(time,1.0)));\n vec2 globalUV = vec2(0.5 * mod(shift, 2.0), 0.25 * floor(shift/2.0));\n \n // Scale UV to fit in one sprite from atlas.\n vec2 localUV = In.uv * 0.5 + vec2(0.25,-0.25);\n localUV.y = min(-0.05,localUV.y); //Safety clamp on the upper side (or you could set clamp_t)\n \n // Read in black and white texture do determine opacity (mask).\n vec2 finalUV = globalUV + localUV;\n mask = texture(textureFlash,finalUV).r;\n }\n \n // Colored sprite.\n vec4 spriteColor = vec4(baseColor[cid], mask);\n \n // Circular halo effect.\n float haloAlpha = 1.0 - smoothstep(0.07,0.5,length(In.uv));\n vec4 haloColor = vec4(1.0,1.0,1.0, haloAlpha * 0.92);\n \n // Mix the sprite color and the halo effect.\n fragColor = mix(spriteColor, haloColor, haloColor.a);\n \n // Boost intensity.\n fragColor *= 1.1;\n // Premultiplied alpha.\n fragColor.rgb *= fragColor.a;\n }\n "}, { "notes_vert", "#version 330\n layout(location = 0) in vec2 v;\n layout(location = 1) in vec4 id; //note id, start, duration, is minor\n layout(location = 2) in float channel; //note id, start, duration, is minor\n uniform float time;\n uniform float mainSpeed;\n uniform float minorsWidth = 1.0;\n uniform float keyboardHeight = 0.25;\n uniform bool reverseMode = false;\n uniform bool horizontalMode = false;\n vec2 flipIfNeeded(vec2 inPos){\n return horizontalMode ? vec2(inPos.y, -inPos.x) : inPos;\n }\n uniform int minNoteMajor;\n uniform float notesCount;\n out INTERFACE {\n vec2 uv;\n vec2 noteSize;\n float isMinor;\n float channel;\n } Out;\n void main(){\n \n float scalingFactor = id.w != 0.0 ? minorsWidth : 1.0;\n // Size of the note : width, height based on duration and current speed.\n Out.noteSize = vec2(0.9*2.0/notesCount * scalingFactor, id.z*mainSpeed);\n \n // Compute note shift.\n // Horizontal shift based on note id, width of keyboard, and if the note is minor or not.\n // Vertical shift based on note start time, current time, speed, and height of the note quad.\n //float a = (1.0/(notesCount-1.0)) * (2.0 - 2.0/notesCount);\n //float b = -1.0 + 1.0/notesCount;\n // This should be in -1.0, 1.0.\n // input: id.x is in [0 MAJOR_COUNT]\n // we want minNote to -1+1/c, maxNote to 1-1/c\n float a = 2.0;\n float b = -notesCount + 1.0 - 2.0 * float(minNoteMajor);\n float horizLoc = (id.x * a + b + id.w) / notesCount;\n float vertLoc = 2.0 * keyboardHeight - 1.0;\n vertLoc += (reverseMode ? -1.0 : 1.0) * (Out.noteSize.y * 0.5 + mainSpeed * (id.y - time));\n vec2 noteShift = vec2(horizLoc, vertLoc);\n \n // Scale uv.\n Out.uv = Out.noteSize * v;\n Out.isMinor = id.w;\n Out.channel = channel;\n // Output position.\n gl_Position = vec4(flipIfNeeded(Out.noteSize * v + noteShift), 0.0 , 1.0) ;\n \n }\n "}, -{ "notes_frag", "#version 330\n #define SETS_COUNT 8\n in INTERFACE {\n vec2 uv;\n vec2 noteSize;\n float isMinor;\n float channel;\n } In;\n uniform vec3 baseColor[SETS_COUNT];\n uniform vec3 minorColor[SETS_COUNT];\n uniform vec2 inverseScreenSize;\n uniform float colorScale;\n uniform float keyboardHeight = 0.25;\n uniform float fadeOut = 0.0;\n uniform bool horizontalMode = false;\n #define cornerRadius 0.01\n out vec4 fragColor;\n void main(){\n \n // If lower area of the screen, discard fragment as it should be hidden behind the keyboard.\n vec2 normalizedCoord = vec2(gl_FragCoord.xy) * inverseScreenSize;\n if((horizontalMode ? normalizedCoord.x : normalizedCoord.y) < keyboardHeight){\n discard;\n }\n \n // Rounded corner (super-ellipse equation).\n float radiusPosition = pow(abs(In.uv.x/(0.5*In.noteSize.x)), In.noteSize.x/cornerRadius) + pow(abs(In.uv.y/(0.5*In.noteSize.y)), In.noteSize.y/cornerRadius);\n \n if( radiusPosition > 1.0){\n discard;\n }\n \n // Fragment color.\n int cid = int(In.channel);\n fragColor.rgb = colorScale * mix(baseColor[cid], minorColor[cid], In.isMinor);\n \n if( radiusPosition > 0.8){\n fragColor.rgb *= 1.05;\n }\n float distFromBottom = horizontalMode ? normalizedCoord.x : normalizedCoord.y;\n float fadeOutFinal = min(fadeOut, 0.9999);\n distFromBottom = max(distFromBottom - fadeOutFinal, 0.0) / (1.0 - fadeOutFinal);\n float alpha = 1.0 - distFromBottom;\n fragColor.a = alpha;\n }\n "}, +{ "notes_frag", "#version 330\n #define SETS_COUNT 8\n in INTERFACE {\n vec2 uv;\n vec2 noteSize;\n float isMinor;\n float channel;\n } In;\n uniform vec3 baseColor[SETS_COUNT];\n uniform vec3 minorColor[SETS_COUNT];\n uniform vec2 inverseScreenSize;\n uniform float colorScale;\n uniform float keyboardHeight = 0.25;\n uniform float fadeOut = 0.0;\n uniform bool horizontalMode = false;\n #define cornerRadius 0.01\n out vec4 fragColor;\n void main(){\n \n // If lower area of the screen, discard fragment as it should be hidden behind the keyboard.\n vec2 normalizedCoord = vec2(gl_FragCoord.xy) * inverseScreenSize;\n if((horizontalMode ? normalizedCoord.x : normalizedCoord.y) < keyboardHeight){\n discard;\n }\n \n // Rounded corner (super-ellipse equation).\n float radiusPosition = pow(abs(In.uv.x/(0.5*In.noteSize.x)), In.noteSize.x/cornerRadius) + pow(abs(In.uv.y/(0.5*In.noteSize.y)), In.noteSize.y/cornerRadius);\n \n if( radiusPosition > 1.0){\n discard;\n }\n // Fragment color.\n int cid = int(In.channel);\n fragColor.rgb = colorScale * mix(baseColor[cid], minorColor[cid], In.isMinor);\n if( radiusPosition > 0.4){\n //outer border\n fragColor.rgb *= 1.5;\n } else {\n //inner\n fragColor.rgb *= 0.8;\n }\n float distFromBottom = horizontalMode ? normalizedCoord.x : normalizedCoord.y;\n float fadeOutFinal = min(fadeOut, 0.9999);\n distFromBottom = max(distFromBottom - fadeOutFinal, 0.0) / (1.0 - fadeOutFinal);\n float alpha = 1.0 - distFromBottom;\n fragColor.a = alpha;\n }\n "}, { "particles_vert", "#version 330\n #define SETS_COUNT 8\n layout(location = 0) in vec2 v;\n uniform float time;\n uniform float scale;\n uniform vec3 baseColor[SETS_COUNT];\n uniform vec2 inverseScreenSize;\n uniform sampler2D textureParticles;\n uniform vec2 inverseTextureSize;\n uniform int globalId;\n uniform float duration;\n uniform int channel;\n uniform int texCount;\n uniform float colorScale;\n uniform float expansionFactor = 1.0;\n uniform float speedScaling = 0.2;\n uniform float keyboardHeight = 0.25;\n uniform int minNote;\n uniform float notesCount;\n uniform bool horizontalMode = false;\n vec2 flipIfNeeded(vec2 inPos){\n return horizontalMode ? vec2(inPos.y, -inPos.x) : inPos;\n }\n const float shifts[128] = float[](\n 0,0.5,1,1.5,2,3,3.5,4,4.5,5,5.5,6,7,7.5,8,8.5,9,10,10.5,11,11.5,12,12.5,13,14,14.5,15,15.5,16,17,17.5,18,18.5,19,19.5,20,21,21.5,22,22.5,23,24,24.5,25,25.5,26,26.5,27,28,28.5,29,29.5,30,31,31.5,32,32.5,33,33.5,34,35,35.5,36,36.5,37,38,38.5,39,39.5,40,40.5,41,42,42.5,43,43.5,44,45,45.5,46,46.5,47,47.5,48,49,49.5,50,50.5,51,52,52.5,53,53.5,54,54.5,55,56,56.5,57,57.5,58,59,59.5,60,60.5,61,61.5,62,63,63.5,64,64.5,65,66,66.5,67,67.5,68,68.5,69,70,70.5,71,71.5,72,73,73.5,74\n );\n out INTERFACE {\n vec4 color;\n vec2 uv;\n float id;\n } Out;\n float rand(vec2 co){\n return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);\n }\n void main(){\n Out.id = float(gl_InstanceID % texCount);\n Out.uv = v + 0.5;\n // Fade color based on time.\n Out.color = vec4(colorScale * baseColor[channel], 1.0-time*time);\n \n float localTime = speedScaling * time * duration;\n float particlesCount = 1.0/inverseTextureSize.y;\n \n // Pick particle id at random.\n float particleId = float(gl_InstanceID) + floor(particlesCount * 10.0 * rand(vec2(globalId,globalId)));\n float textureId = mod(particleId,particlesCount);\n float particleShift = floor(particleId/particlesCount);\n \n // Particle uv, in pixels.\n vec2 particleUV = vec2(localTime / inverseTextureSize.x + 10.0 * particleShift, textureId);\n // UV in [0,1]\n particleUV = (particleUV+0.5)*vec2(1.0,-1.0)*inverseTextureSize;\n // Avoid wrapping.\n particleUV.x = clamp(particleUV.x,0.0,1.0);\n // We want to skip reading from the very beginning of the trajectories because they are identical.\n // particleUV.x = 0.95 * particleUV.x + 0.05;\n // Read corresponding trajectory to get particle current position.\n vec3 position = texture(textureParticles, particleUV).xyz;\n // Center position (from [0,1] to [-0.5,0.5] on x axis.\n position.x -= 0.5;\n \n // Compute shift, randomly disturb it.\n vec2 shift = 0.5*position.xy;\n float random = rand(vec2(particleId + float(globalId),time*0.000002+100.0*float(globalId)));\n shift += vec2(0.0,0.1*random);\n \n // Scale shift with time (expansion effect).\n shift = shift*time*expansionFactor;\n // and with altitude of the particle (ditto).\n shift.x *= max(0.5, pow(shift.y,0.3));\n \n // Horizontal shift is based on the note ID.\n float xshift = -1.0 + ((shifts[globalId] - shifts[int(minNote)]) * 2.0 + 1.0) / notesCount;\n // Combine global shift (due to note id) and local shift (based on read position).\n vec2 globalShift = vec2(xshift, (2.0 * keyboardHeight - 1.0)-0.02);\n vec2 localShift = 0.003 * scale * v + shift * duration * vec2(1.0,0.5);\n float screenRatio = inverseScreenSize.y/inverseScreenSize.x;\n vec2 screenScaling = vec2(1.0, horizontalMode ? (1.0/screenRatio) : screenRatio);\n vec2 finalPos = globalShift + screenScaling * localShift;\n \n // Discard particles that reached the end of their trajectories by putting them off-screen.\n finalPos = mix(vec2(-200.0),finalPos, position.z);\n // Output final particle position.\n gl_Position = vec4(flipIfNeeded(finalPos), 0.0, 1.0);\n \n \n }\n "}, { "particles_frag", "#version 330\n in INTERFACE {\n vec4 color;\n vec2 uv;\n float id;\n } In;\n uniform sampler2DArray lookParticles;\n out vec4 fragColor;\n void main(){\n float alpha = texture(lookParticles, vec3(In.uv, In.id)).r;\n fragColor = In.color;\n fragColor.a *= alpha;\n }\n "}, { "particlesblur_vert", "#version 330\n layout(location = 0) in vec3 v;\n out INTERFACE {\n vec2 uv;\n } Out ;\n void main(){\n \n // We directly output the position.\n gl_Position = vec4(v, 1.0);\n // Output the UV coordinates computed from the positions.\n Out.uv = v.xy * 0.5 + 0.5;\n \n }\n "},