Skip to content

Commit 417660d

Browse files
committed
ImageRenderer: Code cleanup for shaders.
1 parent 257b4fc commit 417660d

File tree

3 files changed

+187
-159
lines changed

3 files changed

+187
-159
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
precision mediump float;
2+
3+
uniform vec2 u_resolution;
4+
uniform int isTouching;
5+
uniform sampler2D u_texture0;
6+
uniform float startRangeX;
7+
uniform float endRangeX;
8+
uniform float startRangeY;
9+
uniform float endRangeY;
10+
uniform float initialAlpha;
11+
uniform float rangeSkippingValue;
12+
13+
float character(float n, vec2 p)
14+
{
15+
p = floor(p * vec2(4.0, -4.0) + 2.5);
16+
if (clamp(p.x, 0.0, 4.0) == p.x)
17+
{
18+
if (clamp(p.y, 0.0, 4.0) == p.y)
19+
{
20+
if (int(mod(n / exp2(p.x + 5.0 * p.y), 2.0)) == 1) return 1.0;
21+
}
22+
}
23+
return 0.0;
24+
}
25+
vec3 invertColor(vec3 color) {
26+
return vec3(1.0 - color.r, 1.0 - color.g, 1.0 - color.b);
27+
}
28+
29+
bool isBlack(vec3 color) {
30+
return color.r == 0.0 && color.g == 0.0 && color.b == 0.0;
31+
}
32+
bool isInsideRange(vec2 uv, float startRangeX, float endRangeX, float startRangeY, float endRangeY, vec2 u_resolution, float rangeModifier) {
33+
// Checks if is inside a square
34+
float scaledStartRangeX = startRangeX + rangeModifier;
35+
float scaledEndRangeX = endRangeX - rangeModifier;
36+
float scaledStartRangeY = startRangeY + rangeModifier;
37+
float scaledEndRangeY = endRangeY - rangeModifier;
38+
39+
return (uv.x > scaledStartRangeX / u_resolution.x && uv.x < scaledEndRangeX / u_resolution.x &&
40+
uv.y > scaledStartRangeY / u_resolution.y && uv.y < scaledEndRangeY / u_resolution.y);
41+
}
42+
bool isInsideCircle(vec2 uv, vec2 center, float radius, vec2 u_resolution) {
43+
vec2 normalizedUV = uv * u_resolution / max(u_resolution.x, u_resolution.y);
44+
vec2 normalizedCenter = center / max(u_resolution.x, u_resolution.y);
45+
float distanceSquared = dot(normalizedUV - normalizedCenter, normalizedUV - normalizedCenter);
46+
float radiusSquared = (radius / max(u_resolution.x, u_resolution.y)) * (radius / max(u_resolution.x, u_resolution.y));
47+
return distanceSquared < radiusSquared;
48+
}
49+
float calculateAlphaFalloff(vec2 uv, vec2 u_resolution) {
50+
float distToLeft = uv.x;
51+
float distToRight = u_resolution.x - uv.x;
52+
float distToTop = uv.y;
53+
float distToBottom = u_resolution.y - uv.y;
54+
55+
float edgeThreshold = 0.2; // Adjust the edge threshold here
56+
57+
// Normalize distances
58+
float maxDist = max(u_resolution.x, u_resolution.y);
59+
distToLeft /= maxDist;
60+
distToRight /= maxDist;
61+
distToTop /= maxDist;
62+
distToBottom /= maxDist;
63+
64+
float alpha = initialAlpha;
65+
66+
// Check if the pixel is closer to the left or right side
67+
float minHorizontalDist = min(distToLeft, distToRight);
68+
alpha *= smoothstep(0.0, edgeThreshold, minHorizontalDist);
69+
70+
// Check if the pixel is closer to the top or bottom side
71+
float minVerticalDist = min(distToTop, distToBottom);
72+
alpha *= smoothstep(0.0, edgeThreshold, minVerticalDist);
73+
74+
return alpha;
75+
}
76+
void main() {
77+
vec2 pix = gl_FragCoord.xy;
78+
vec2 uv = pix / u_resolution.xy;
79+
uv.y = 1.0 - uv.y; // Flip the texture vertically
80+
81+
vec3 col = texture2D(u_texture0, uv).rgb;
82+
float gray = 0.3 * col.r + 0.59 * col.g + 0.11 * col.b;
83+
84+
int n = 4096;
85+
86+
// limited character set
87+
if (gray > 0.2) n = 65600; // :
88+
if (gray > 0.3) n = 163153; // *
89+
if (gray > 0.4) n = 15255086; // o
90+
if (gray > 0.5) n = 13121101; // &
91+
if (gray > 0.6) n = 15252014; // 8
92+
if (gray > 0.7) n = 13195790; // @
93+
if (gray > 0.8) n = 11512810; // #
94+
95+
float charsize = 4.8;
96+
float alpha = 1.0;
97+
vec2 p = mod(pix / charsize, charsize / 2.0) - vec2(charsize / 4.0);
98+
99+
float rangeModifier = endRangeY - startRangeY;
100+
bool insideRange = isInsideCircle(uv, vec2((startRangeX + endRangeX) / 2.0, (startRangeY + endRangeY) / 2.0), (endRangeX - startRangeX) / 2.0, u_resolution);
101+
102+
if (insideRange) {
103+
vec2 center = vec2((startRangeX + endRangeX) / 2.0, (startRangeY + endRangeY) / 2.0);
104+
float distance = distance(uv * u_resolution, center);
105+
106+
107+
108+
// Additional logic for changing characters gradually
109+
float heatArea = clamp(1. - distance / (u_resolution.x * 0.5), 0.0, 1.0);
110+
float bwFactor = 1.0;
111+
float blenderDivider = (u_resolution.x * 0.1);
112+
if (isTouching == 1) {
113+
blenderDivider = (u_resolution.x * 0.22);
114+
} else {
115+
blenderDivider = (u_resolution.x * 0.11);
116+
}
117+
118+
if (heatArea < 0.2) {
119+
n = 4096;
120+
} else if (heatArea < 0.3) {
121+
n = 4096;
122+
} else if (heatArea < 0.4) {
123+
blenderDivider = (u_resolution.x * 0.45);
124+
} else if (heatArea < 0.5) {
125+
blenderDivider = (u_resolution.x * 0.4);
126+
} else if (heatArea < 0.6) {
127+
blenderDivider = (u_resolution.x * 0.4);
128+
}
129+
bwFactor = 1.2;
130+
// Adjust the smoothstep range for a smoother blending
131+
float blendAmount = smoothstep(0.1, 1.0, distance / blenderDivider);
132+
133+
// Gradual blending from the center towards the edges
134+
col = mix(col, vec3(character(float(n), p)), blendAmount);
135+
if (heatArea < 0.2) {
136+
col = vec3(character(float(n), p));
137+
} else if (heatArea < rangeSkippingValue * 0.9) {
138+
col = (col * bwFactor) * character(float(n), p);
139+
}
140+
141+
} else {
142+
col = vec3(character(float(n), p));
143+
}
144+
145+
alpha = calculateAlphaFalloff(pix, u_resolution);
146+
gl_FragColor = vec4(col, alpha);
147+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
uniform mat4 uMVPMatrix;
2+
attribute vec2 vPosition;
3+
attribute vec2 aTextureCoord;
4+
5+
void main() {
6+
gl_Position = vec4(vPosition, 0, 1);
7+
}

app/src/main/java/com/oussama/portfolio/ui/components/glimageview/ImageRenderer.kt

Lines changed: 33 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.oussama.portfolio.ui.components.glimageview
33
import android.animation.Animator
44
import android.animation.AnimatorSet
55
import android.animation.ValueAnimator
6+
import android.content.Context
67
import android.graphics.Bitmap
78
import android.graphics.Color
89
import android.opengl.GLES20
@@ -11,7 +12,10 @@ import android.opengl.GLUtils
1112
import android.opengl.Matrix
1213
import android.view.MotionEvent
1314
import android.view.animation.AnticipateOvershootInterpolator
15+
import com.oussama.portfolio.BaseApplication
1416
import timber.log.Timber
17+
import java.io.BufferedReader
18+
import java.io.InputStreamReader
1519
import java.nio.ByteBuffer
1620
import java.nio.ByteOrder
1721
import java.nio.FloatBuffer
@@ -166,6 +170,32 @@ class ImageRenderer(
166170
fun paused(isPaused: Boolean) {
167171
this.isPaused = isPaused
168172
}
173+
174+
companion object {
175+
@JvmStatic
176+
fun loadFromAsset(context: Context, fileName: String): String {
177+
val assetManager = context.assets
178+
try {
179+
val inputStream = assetManager.open(fileName)
180+
val bufferedReader = BufferedReader(InputStreamReader(inputStream))
181+
val stringBuilder = StringBuilder()
182+
var line: String?
183+
do {
184+
line = bufferedReader.readLine()
185+
if (line != null) {
186+
stringBuilder.append(line)
187+
stringBuilder.append("\n")
188+
}
189+
} while (line != null)
190+
bufferedReader.close()
191+
inputStream.close()
192+
return stringBuilder.toString()
193+
} catch (e: Exception) {
194+
e.printStackTrace()
195+
return ""
196+
}
197+
}
198+
}
169199
}
170200

171201
class Square(bitmap: Bitmap) {
@@ -213,165 +243,9 @@ class Square(bitmap: Bitmap) {
213243
private var rangeSkippingValue = maxRangeSkippingValue
214244

215245
init {
216-
val vertexShaderCode =
217-
"uniform mat4 uMVPMatrix;\n" +
218-
"attribute vec2 vPosition;\n" +
219-
"attribute vec2 aTextureCoord;\n" +
220-
"\n" +
221-
"void main() {\n" +
222-
" gl_Position = vec4(vPosition, 0, 1);\n" +
223-
"}"
224-
225-
val fragmentShaderCode =
226-
"precision mediump float;\n" +
227-
"\n" +
228-
"uniform vec2 u_resolution;\n" +
229-
"uniform int isTouching;\n" +
230-
"uniform sampler2D u_texture0;\n" +
231-
"uniform float startRangeX; \n" +
232-
"uniform float endRangeX; \n" +
233-
"uniform float startRangeY; \n" +
234-
"uniform float endRangeY; \n" +
235-
"uniform float initialAlpha; \n" +
236-
"uniform float rangeSkippingValue; \n" +
237-
"\n" +
238-
"float character(float n, vec2 p)\n" +
239-
"{\n" +
240-
"p = floor(p*vec2(4.0, -4.0) + 2.5);\n" +
241-
" if (clamp(p.x, 0.0, 4.0) == p.x)\n" +
242-
"{\n" +
243-
" if (clamp(p.y, 0.0, 4.0) == p.y)\n" +
244-
"{\n" +
245-
" if (int(mod(n/exp2(p.x + 5.0*p.y), 2.0)) == 1) return 1.0;\n" +
246-
"}\n" +
247-
" }\n" +
248-
"return 0.0;\n" +
249-
"}\n" +
250-
"vec3 invertColor(vec3 color) {\n" +
251-
" return vec3(1.0 - color.r, 1.0 - color.g, 1.0 - color.b);\n" +
252-
"}\n" +
253-
"\n" +
254-
"bool isBlack(vec3 color) {\n" +
255-
" return color.r == 0.0 && color.g == 0.0 && color.b == 0.0;\n" +
256-
"}\n" +
257-
"bool isInsideRange(vec2 uv, float startRangeX, float endRangeX, float startRangeY, float endRangeY, vec2 u_resolution, float rangeModifier) { // Checks if is inside a square \n" +
258-
" float scaledStartRangeX = startRangeX + rangeModifier;\n" +
259-
" float scaledEndRangeX = endRangeX - rangeModifier;\n" +
260-
" float scaledStartRangeY = startRangeY + rangeModifier;\n" +
261-
" float scaledEndRangeY = endRangeY - rangeModifier;\n" +
262-
"\n" +
263-
" return (uv.x > scaledStartRangeX / u_resolution.x && uv.x < scaledEndRangeX / u_resolution.x &&\n" +
264-
" uv.y > scaledStartRangeY / u_resolution.y && uv.y < scaledEndRangeY / u_resolution.y);\n" +
265-
"}\n" +
266-
"bool isInsideCircle(vec2 uv, vec2 center, float radius, vec2 u_resolution) {\n" +
267-
" vec2 normalizedUV = uv * u_resolution / max(u_resolution.x, u_resolution.y);\n" +
268-
" vec2 normalizedCenter = center / max(u_resolution.x, u_resolution.y);\n" +
269-
" float distanceSquared = dot(normalizedUV - normalizedCenter, normalizedUV - normalizedCenter);\n" +
270-
" float radiusSquared = (radius / max(u_resolution.x, u_resolution.y)) * (radius / max(u_resolution.x, u_resolution.y));\n" +
271-
" return distanceSquared < radiusSquared;\n" +
272-
"}" +
273-
"float calculateAlphaFalloff(vec2 uv, vec2 u_resolution) {\n" +
274-
" float distToLeft = uv.x;\n" +
275-
" float distToRight = u_resolution.x - uv.x;\n" +
276-
" float distToTop = uv.y;\n" +
277-
" float distToBottom = u_resolution.y - uv.y;\n" +
278-
"\n" +
279-
" float edgeThreshold = 0.2; // Adjust the edge threshold here\n" +
280-
"\n" +
281-
" // Normalize distances\n" +
282-
" float maxDist = max(u_resolution.x, u_resolution.y);\n" +
283-
" distToLeft /= maxDist;\n" +
284-
" distToRight /= maxDist;\n" +
285-
" distToTop /= maxDist;\n" +
286-
" distToBottom /= maxDist;\n" +
287-
"\n" +
288-
" float alpha = initialAlpha;\n" +
289-
"\n" +
290-
" // Check if the pixel is closer to the left or right side\n" +
291-
" float minHorizontalDist = min(distToLeft, distToRight);\n" +
292-
" alpha *= smoothstep(0.0, edgeThreshold, minHorizontalDist);\n" +
293-
"\n" +
294-
" // Check if the pixel is closer to the top or bottom side\n" +
295-
" float minVerticalDist = min(distToTop, distToBottom);\n" +
296-
" alpha *= smoothstep(0.0, edgeThreshold, minVerticalDist);\n" +
297-
"\n" +
298-
" return alpha;\n" +
299-
"}\n" +
300-
"void main() {\n" +
301-
" vec2 pix = gl_FragCoord.xy;\n" +
302-
" vec2 uv = pix / u_resolution.xy;\n" +
303-
" uv.y = 1.0 - uv.y; // Flip the texture vertically\n" +
304-
"\n" +
305-
" vec3 col = texture2D(u_texture0, uv).rgb;\n" +
306-
" float gray = 0.3 * col.r + 0.59 * col.g + 0.11 * col.b;\n" +
307-
"\n" +
308-
" int n = 4096;\n" +
309-
"\n" +
310-
" // limited character set\n" +
311-
" if (gray > 0.2) n = 65600; // :\n" +
312-
" if (gray > 0.3) n = 163153; // *\n" +
313-
" if (gray > 0.4) n = 15255086; // o \n" +
314-
" if (gray > 0.5) n = 13121101; // &\n" +
315-
" if (gray > 0.6) n = 15252014; // 8\n" +
316-
" if (gray > 0.7) n = 13195790; // @\n" +
317-
" if (gray > 0.8) n = 11512810; // #\n" +
318-
"\n" +
319-
" float charsize = 4.8;\n" +
320-
" float alpha = 1.0;\n" +
321-
" vec2 p = mod(pix / charsize, charsize / 2.0) - vec2(charsize / 4.0);\n" +
322-
"\n" +
323-
" float rangeModifier = endRangeY - startRangeY;\n" +
324-
" bool insideRange = isInsideCircle(uv, vec2((startRangeX + endRangeX) / 2.0, (startRangeY + endRangeY) / 2.0), (endRangeX - startRangeX) / 2.0, u_resolution);\n" +
325-
"\n" +
326-
" if (insideRange) {\n" +
327-
" vec2 center = vec2((startRangeX + endRangeX) / 2.0, (startRangeY + endRangeY) / 2.0);\n" +
328-
" float distance = distance(uv * u_resolution, center);\n" +
329-
" \n" +
330-
331-
"\n" +
332-
" // Additional logic for changing characters gradually\n" +
333-
" float heatArea = clamp(1. - distance / (u_resolution.x * 0.5), 0.0, 1.0);\n" +
334-
" float bwFactor = 1.0;\n" +
335-
" float blenderDivider = (u_resolution.x * 0.1);\n" +
336-
" if (isTouching == 1) {\n" +
337-
" blenderDivider = (u_resolution.x * 0.22);\n" +
338-
" } else {\n" +
339-
"blenderDivider = (u_resolution.x * 0.11);" +
340-
"}" +
341-
342-
" if (heatArea < 0.2) {\n" +
343-
" n = 4096;\n" +
344-
" } else if (heatArea < 0.3) {\n" +
345-
" n = 4096;\n" +
346-
" } else if (heatArea < 0.4) {\n" +
347-
" blenderDivider = (u_resolution.x * 0.45);" +
348-
" } else if (heatArea < 0.5) {\n" +
349-
" blenderDivider = (u_resolution.x * 0.4);" +
350-
" } else if (heatArea < 0.6) {\n" +
351-
" blenderDivider = (u_resolution.x * 0.4);" +
352-
" } \n" +
353-
"bwFactor = 1.2;\n" +
354-
" // Adjust the smoothstep range for a smoother blending\n" +
355-
" float blendAmount = smoothstep(0.1, 1.0, distance / blenderDivider);\n" +
356-
"\n" +
357-
" // Gradual blending from the center towards the edges\n" +
358-
" col = mix(col, vec3(character(float(n), p)), blendAmount);\n" +
359-
" if (heatArea < 0.2) {\n" +
360-
" col = vec3(character(float(n), p));\n" +
361-
" } else if (heatArea < rangeSkippingValue*0.9) {\n" +
362-
" col = (col * bwFactor) * character(float(n), p);\n" +
363-
" }\n" +
364-
365-
" } else {\n" +
366-
" col = vec3(character(float(n), p));\n" +
367-
" }\n" +
368-
"\n" +
369-
" alpha = calculateAlphaFalloff(pix, u_resolution); " +
370-
" gl_FragColor = vec4(col, alpha);\n" +
371-
"}"
372-
373-
val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode)
374-
val fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode)
246+
247+
val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, ImageRenderer.loadFromAsset(BaseApplication.INSTANCE, "shaders/vertex_shader.glsl"))
248+
val fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, ImageRenderer.loadFromAsset(BaseApplication.INSTANCE, "shaders/fragment_shader.glsl"))
375249

376250
program = GLES20.glCreateProgram().also {
377251
GLES20.glAttachShader(it, vertexShader)

0 commit comments

Comments
 (0)