Skip to content

Instantly share code, notes, and snippets.

@JNNGL
Last active June 27, 2024 10:51
Show Gist options
  • Save JNNGL/535b8e4f6a5f2679bf0dd68831dbb80a to your computer and use it in GitHub Desktop.
Save JNNGL/535b8e4f6a5f2679bf0dd68831dbb80a to your computer and use it in GitHub Desktop.
Animated unicodes in Minecraft using vanilla shaders
#!/usr/bin/python3
import math
import argparse
from PIL import Image
def build_frames(gif, animation_seconds):
num_frames = math.floor(gif.n_frames)
frame_width, frame_height = gif.size
frames_per_line = math.ceil(math.sqrt(num_frames))
frame_dim = max(frame_width, frame_height)
width = frames_per_line * frame_dim + 2
height = frames_per_line * frame_dim + 2
frames = Image.new("RGBA", (width, height), color=(0, 0, 0, 0))
for i in range(num_frames):
gif.seek(i)
frame = gif.copy()
aligned_frame = Image.new("RGBA", (frame_dim, frame_dim), color=(0, 0, 0, 0))
aligned_frame.paste(frame, (0, 0))
frames.paste(aligned_frame,
((i % frames_per_line) * frame_dim + 1, math.floor(i / frames_per_line) * frame_dim + 1),
aligned_frame)
frames.putpixel((0, 0), (149, 213, 75, 1))
frames.putpixel((1, 0), (width, height, 75, 1))
frames.putpixel((2, 0), (frame_dim, num_frames, 75, 1))
s = math.floor(animation_seconds)
frames.putpixel((3, 0), (s, math.floor((animation_seconds - s) * 255.0), 75, 1))
frames.putpixel((width - 1, 0), (width - 1, 0, 75, 1))
frames.putpixel((0, height - 1), (0, height - 1, 75, 1))
frames.putpixel((width - 1, height - 1), (width - 1, height - 1, 75, 1))
return frames
parser = argparse.ArgumentParser(prog='generator', description='Animated emoji generator.')
parser.add_argument('--input')
parser.add_argument('--duration', type=float)
parser.add_argument('--output')
args = parser.parse_args()
frames = build_frames(Image.open(args.input), args.duration)
frames.save(args.output, format='PNG')
#version 150
#moj_import <fog.glsl>
uniform sampler2D Sampler0;
uniform vec4 ColorModulator;
uniform float FogStart;
uniform float FogEnd;
uniform vec4 FogColor;
in float vertexDistance;
in vec4 vertexColor;
in vec2 texCoord0;
in vec2 texCoord1;
in float isAnimated;
out vec4 fragColor;
void main() {
vec4 color = texture(Sampler0, isAnimated > 0.0 ? texCoord1 : texCoord0) * vertexColor * ColorModulator;
if (color.a < 0.1) {
discard;
}
fragColor = linear_fog(color, vertexDistance, FogStart, FogEnd, FogColor);
}
{
"blend": {
"func": "add",
"srcrgb": "srcalpha",
"dstrgb": "1-srcalpha"
},
"vertex": "rendertype_text",
"fragment": "rendertype_text",
"attributes": [
"Position",
"Color",
"UV0",
"UV2"
],
"samplers": [
{ "name": "Sampler0" },
{ "name": "Sampler2" }
],
"uniforms": [
{ "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
{ "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
{ "name": "GameTime", "type": "float", "count": 1, "values": [ 0.0 ] },
{ "name": "IViewRotMat", "type": "matrix3x3", "count": 9, "values": [ 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 ] },
{ "name": "ColorModulator", "type": "float", "count": 4, "values": [ 1.0, 1.0, 1.0, 1.0 ] },
{ "name": "FogStart", "type": "float", "count": 1, "values": [ 0.0 ] },
{ "name": "FogEnd", "type": "float", "count": 1, "values": [ 1.0 ] },
{ "name": "FogColor", "type": "float", "count": 4, "values": [ 0.0, 0.0, 0.0, 0.0 ] },
{ "name": "FogShape", "type": "int", "count": 1, "values": [ 0 ] }
]
}
#version 150
#moj_import <fog.glsl>
in vec3 Position;
in vec4 Color;
in vec2 UV0;
in ivec2 UV2;
uniform sampler2D Sampler0;
uniform sampler2D Sampler2;
uniform mat4 ModelViewMat;
uniform mat4 ProjMat;
uniform mat3 IViewRotMat;
uniform int FogShape;
uniform float GameTime;
out float vertexDistance;
out vec4 vertexColor;
out vec2 texCoord0;
out vec2 texCoord1;
out float isAnimated;
bool validateProperty2(vec4 data) {
return data.zw == vec2(75.0 / 255.0, 1.0 / 255.0);
}
bool decodeProperties0(in vec2 uv, out ivec2 dim, out int frame_dim,
out int nframes, out float time, out ivec2 size) {
vec4 magic = texture(Sampler0, uv);
if (magic != vec4(149.0 / 255.0, 213.0 / 255.0, 75.0 / 255.0, 1.0 / 255.0)) {
return false;
}
ivec2 texsize = textureSize(Sampler0, 0);
float x1 = 1.0 / float(texsize.x);
size = texsize;
vec4 dim_in = texture(Sampler0, uv + vec2(x1, 0.0));
if (!validateProperty2(dim_in)) {
return false;
}
dim = ivec2(dim_in.xy * vec2(255.0));
vec4 frame_data = texture(Sampler0, uv + vec2(x1 * 2.0, 0.0));
if (!validateProperty2(frame_data)) {
return false;
}
frame_dim = int(frame_data.x * 255.0);
nframes = int(frame_data.y * 255.0);
vec4 packed_time = texture(Sampler0, uv + vec2(x1 * 3.0, 0.0));
if (!validateProperty2(packed_time)) {
return false;
}
time = packed_time.x * 255.0 + packed_time.y;
return true;
}
bool decodeProperties(in vec2 uv, out ivec2 dim, out int frame_dim, out int nframes,
out float time, out ivec2 size, out vec2 origin) {
if (decodeProperties0(uv, dim, frame_dim, nframes, time, size)) {
origin = uv;
return true;
}
vec4 uv_offset = texture(Sampler0, uv);
if (!validateProperty2(uv_offset)) {
return false;
}
vec2 pointing = uv - uv_offset.xy * (vec2(255.0) / vec2(textureSize(Sampler0, 0)));
origin = pointing;
return decodeProperties0(pointing, dim, frame_dim, nframes, time, size);
}
void main() {
gl_Position = ProjMat * ModelViewMat * vec4(Position, 1.0);
isAnimated = 0.0;
vec2 uv = UV0;
ivec2 dim;
int frame_dim;
int nframes;
float loop_time;
ivec2 size;
vec2 origin;
if (decodeProperties(UV0, dim, frame_dim, nframes, loop_time, size, origin)) {
isAnimated = 1.0;
float time = fract(GameTime * 1200.0 / loop_time);
int frame = int(time * nframes);
int uframes = (dim.x - 2) / frame_dim;
int u = frame % uframes;
int v = frame / uframes;
uv = vec2((uv.x - origin.x) / float(dim.x) * float(frame_dim) + origin.x, (uv.y - origin.y) / float(dim.y) * float(frame_dim) + origin.y);
uv += (vec2(u, v) * vec2(frame_dim) + 1.0) / vec2(size);
}
vertexDistance = fog_distance(ModelViewMat, IViewRotMat * Position, FogShape);
vertexColor = Color * texelFetch(Sampler2, UV2 / 16, 0);
texCoord0 = UV0;
texCoord1 = uv;
}
@Xiao-MoMi
Copy link

Really appreciate your work. Could you add a license to the codes so we could use them in open source projects and give credits to you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment