shader_type canvas_item; // Scale and mouse position as input parameters const vec2 scale = vec2(1, 1); uniform float dim_color_scale : hint_range(0.0, 1.0) = 0.5; uniform float pos_x : hint_range(0.0, 1.0) = 0.0001 ; uniform float pos_y : hint_range(0.0, 1.0) = 0.05; // Helper function to calculate the distance between a point and a line vec2 Line2point(vec2 linePoint, vec2 lineDire, vec2 point) { lineDire = normalize(lineDire); vec2 line2Ori = -linePoint - dot(-linePoint, lineDire) * lineDire; vec2 p2Ori = -point - dot(-point, lineDire) * lineDire; return line2Ori - p2Ori; } // Function to blend two colors based on their alpha values vec4 ColorWithA(vec4 oldCol, vec4 newCol) { vec4 finalCol; if ((newCol.a + oldCol.a) >= 1.0) { finalCol.rgb = newCol.rgb; finalCol.a = 1.0; } else { finalCol.rgb = newCol.a / (newCol.a + oldCol.a) * newCol.rgb + oldCol.a / (newCol.a + oldCol.a) * oldCol.rgb; finalCol.a = oldCol.a + newCol.a; } return finalCol; } void fragment() { // Initialize mouse position and final color vec2 mouse_pos = vec2(-1., -1.); vec2 uv = UV; vec4 finalColor = vec4(0.0); // Transparent color initially // Adjust scale to maintain aspect ratio of the sprite float scale_min = scale.x / scale.y; vec2 uv_max = vec2(scale_min, 1.0); float trueScale; if (scale.y < scale.x) { scale_min = scale.y / scale.x; uv.y = uv.y * scale_min; uv_max = vec2(1.0, scale_min); trueScale = scale.x; } else { uv.x = uv.x * scale_min; trueScale = scale.y; } // Normalize mouse position based on the texture pixel size mouse_pos.x = pos_x * (1.0 / TEXTURE_PIXEL_SIZE.x); mouse_pos.y = pos_y * (1.0 / TEXTURE_PIXEL_SIZE.y); vec2 normalized_mouse = mouse_pos * uv_max; // Default texture color assignment COLOR = texture(TEXTURE, uv); // Calculate sprite's position relative to the mouse vec2 pPos = uv / TEXTURE_PIXEL_SIZE * trueScale; // Only process if the mouse position is valid if (normalized_mouse.x > -0.0001) { vec2 left_bottom = vec2(0.0, uv_max.y / TEXTURE_PIXEL_SIZE.y * trueScale); vec2 midpoint = (normalized_mouse - left_bottom) / 2.0 + left_bottom; vec2 midDirect = normalize(vec2(-(normalized_mouse - left_bottom).y, (normalized_mouse - left_bottom).x)); // Calculate flip interactions vec2 sharpPoint = vec2(0.0, midpoint.y - midDirect.y / midDirect.x * midpoint.x); vec2 flipEdgeDire = normalize(sharpPoint - normalized_mouse); vec2 sharpPointB = vec2(midpoint.x - midDirect.x / midDirect.y * (midpoint - left_bottom).y, left_bottom.y); vec2 flipEdgeDireB = normalize(sharpPointB - normalized_mouse); // Flip logic based on mouse distance and angle float cyOriOff = length(normalized_mouse - left_bottom); if (cyOriOff > 100.0) cyOriOff = 100.0; float cyR = cyOriOff * 2.0 / PI; vec2 midlineToP = Line2point(midpoint, midDirect, pPos); vec2 sideEdgeToP = Line2point(normalized_mouse, flipEdgeDire, pPos); vec2 BottomEdgeToP = Line2point(normalized_mouse, flipEdgeDireB, pPos); vec2 cyOriToP = midlineToP - normalize(normalized_mouse - left_bottom) * cyOriOff; vec2 cyEdgeToP = midlineToP - normalize(normalized_mouse - left_bottom) * (cyOriOff - cyR); bool atBG = (cyOriToP).x <= -0.01; bool atPageBack = !atBG && (sideEdgeToP.y > 0.0) && (BottomEdgeToP.x <= 0.0); bool atCy = cyEdgeToP.x >= 0.0 && (cyOriToP).x <= 0.0; bool atCyPage = false; float shadow = 1.0; vec2 uvCy, uvCyB; // Handle flip state and apply shadow effect if (atCy) { vec2 cyOri = pPos - cyOriToP; vec2 trueDis = cyR * asin(length(cyOriToP) / cyR) * normalize(cyOriToP); vec2 truePos = cyOri + trueDis; uvCyB = truePos * TEXTURE_PIXEL_SIZE / trueScale; shadow *= 1.0 - pow(length(trueDis) / (cyR * PI / 2.0), 3.0); // Determine if we are on the flip side of the page if ((BottomEdgeToP.x < 0.0) && (sideEdgeToP.y > 0.0)) { atCyPage = true; uvCy = vec2(length(sideEdgeToP), left_bottom.y - length(BottomEdgeToP)) * TEXTURE_PIXEL_SIZE / trueScale; } if (uvCyB.x > uv_max.x || uvCyB.y > uv_max.y || uvCyB.x <= 0.0 || uvCyB.y <= 0.0) { atCy = false; } } // Blend final color based on conditions COLOR = vec4(0.0); // Reset COLOR if (!atBG && !atCy) { vec4 color = texture(TEXTURE, uv); finalColor = color; } if (atCy) { vec4 cyColor = texture(TEXTURE, uvCyB); finalColor = cyColor; } if (atCyPage) { vec4 cyPageColor = texture(TEXTURE, uvCy); cyPageColor.xyz *= dim_color_scale; // Dim the color slightly finalColor = mix(finalColor, cyPageColor, cyPageColor.a); } else if (atPageBack) { // If the fragment is on the flipped page, adjust the color for the back of the page uv = vec2(length(sideEdgeToP), left_bottom.y - length(BottomEdgeToP)) * TEXTURE_PIXEL_SIZE / trueScale; vec4 pageBackColor = texture(TEXTURE, uv); pageBackColor.xyz *= dim_color_scale; // Dim the back page color finalColor = mix(finalColor, pageBackColor, pageBackColor.a); } COLOR = finalColor; } else{ } }