# Default Shader Parts

Shader parts are used by Model-Based Rendering and Text Shaders. This file contains an index of parts by priority, and the source of each shader part.

## Vertex Part Priorities

How Ren'Py uses vertex part priorities:

- Priority 0 sets up gl_Position.

- Priority 10 is used to capture gl_Position in virtual or drawable coordinates before adjustment.

- Priorities 20-80 adjust gl_Position in virtual or drawable coordinates.

- Priority 90 is used to capture gl_Position in virtual or drawable coordinates after adjustment.

- Priority 100 transforms gl_Position to viewport coordinates.

- Priority 200 stores more information in the variables passed to the fragment shader, without touching gl_Position.

In order:

0. renpy.geometry
10. textshader.linetexture
10. textshader.texture
20. textshader.flip
25. textshader.zoom
30. textshader.jitter
35. textshader.offset
40. textshader.wave
100. renpy.geometry
200. renpy.alpha_mask
200. renpy.blur
200. renpy.dissolve
200. renpy.imagedissolve
200. renpy.mask
200. renpy.movie_yuv
200. renpy.texture
200. textshader.dissolve
200. textshader.typewriter

## Fragment Part Priorities

How Ren'Py uses fragment part priorities:

- Priority 200 determines an original color and stores it in the fragment output (`fragment_color` in GLSL ES 3.00 or `gl_FragColor` in GLSL ES 1.00).

- Priority 300 multiplies that color with a second texture.

- Priority 325 stores alpha before the text shaders adjust it.

- Priority 350 applies text shaders that adjust alpha.

- Priority 375 can undo part of the effect of these text shaders.

- Priority 400 adjusts the color, applying Transform and displayable-based changes.

- Priority 450 converts color to alpha.

- Priority 500 adjusts the alpha channel, applying Transform and displayable-based changes.

In order:

200. renpy.blur
200. renpy.dissolve
200. renpy.imagedissolve
200. renpy.mask
200. renpy.movie_yuv
200. renpy.solid
200. renpy.texture
300. textshader.linetexture
300. textshader.texture
325. textshader.slowalpha
350. textshader.dissolve
350. textshader.typewriter
375. textshader.slowalpha
400. renpy.matrixcolor
450. renpy.red_to_alpha
500. renpy.alpha
500. renpy.alpha_mask

## renpy.alpha

Variables:

    uniform float u_renpy_alpha;
    uniform float u_renpy_over;

Fragment shader (priority 500):

    fragment_color *= u_renpy_alpha * vec4(1.0, 1.0, 1.0, u_renpy_over);

## renpy.alpha_mask

Variables:

    uniform sampler2D tex0;
    uniform sampler2D tex1;
    in vec2 a_tex_coord;
    out vec2 v_tex_coord;

Vertex shader (priority 200):

    v_tex_coord = a_tex_coord;

Fragment shader (priority 500):

    // The mask is in the red channel, and the result is premultiplied.
    float l_renpy_alpha_mask_mask = texture(tex1, v_tex_coord).r;

    fragment_color = vec4(texture(tex0, v_tex_coord).rgb * l_renpy_alpha_mask_mask, l_renpy_alpha_mask_mask);

## renpy.blur

Variables:

    uniform sampler2D tex0;
    in vec2 a_tex_coord;
    out vec2 v_tex_coord;
    uniform float u_renpy_blur_log2;

Vertex shader (priority 200):

    v_tex_coord = a_tex_coord;

Fragment shader (priority 200):

    float l_renpy_blur_norm = 0.0;

    for (int l_renpy_blur_i = -5; l_renpy_blur_i <= 0; l_renpy_blur_i++) {
        float l_renpy_blur_distance = u_renpy_blur_log2 - float(l_renpy_blur_i);
        l_renpy_blur_norm += exp(-0.5 * l_renpy_blur_distance * l_renpy_blur_distance);
    }

    vec4 l_renpy_blur_acc = l_renpy_blur_norm * texture(tex0, v_tex_coord, 0.0);

    for (int l_renpy_blur_i = 1; l_renpy_blur_i < 14; l_renpy_blur_i++) {
        float l_renpy_blur_level = float(l_renpy_blur_i);

        if (l_renpy_blur_level >= u_renpy_blur_log2 + 5.0) {
            break;
        }

        float l_renpy_blur_distance = u_renpy_blur_log2 - l_renpy_blur_level;
        float l_renpy_blur_weight = exp(-0.5 * l_renpy_blur_distance * l_renpy_blur_distance);

        l_renpy_blur_acc += l_renpy_blur_weight * texture(tex0, v_tex_coord, l_renpy_blur_level);
        l_renpy_blur_norm += l_renpy_blur_weight;
    }

    if (l_renpy_blur_norm > 0.0) {
        fragment_color = l_renpy_blur_acc / l_renpy_blur_norm;
    } else {
        fragment_color = texture(tex0, v_tex_coord, 0.0);
    }

## renpy.dissolve

Variables:

    uniform float u_lod_bias;
    uniform sampler2D tex0;
    uniform sampler2D tex1;
    uniform float u_renpy_dissolve;
    in vec2 a_tex_coord;
    out vec2 v_tex_coord;

Vertex shader (priority 200):

    v_tex_coord = a_tex_coord;

Fragment shader (priority 200):

    fragment_color = mix(
        texture(tex0, v_tex_coord, u_lod_bias),
        texture(tex1, v_tex_coord, u_lod_bias),
        u_renpy_dissolve);

## renpy.geometry

Variables:

    uniform mat4 u_transform;
    in vec4 a_position;

Vertex shader (priority 0):

    gl_Position = a_position;

Vertex shader (priority 100):

    gl_Position = u_transform * gl_Position;

## renpy.imagedissolve

Variables:

    uniform float u_lod_bias;
    uniform sampler2D tex0;
    uniform sampler2D tex1;
    uniform sampler2D tex2;
    uniform float u_renpy_dissolve_offset;
    uniform float u_renpy_dissolve_multiplier;
    in vec2 a_tex_coord;
    out vec2 v_tex_coord;

Vertex shader (priority 200):

    v_tex_coord = a_tex_coord;

Fragment shader (priority 200):

    float l_renpy_imagedissolve_done = clamp(
        (texture(tex0, v_tex_coord, u_lod_bias).a + u_renpy_dissolve_offset) * u_renpy_dissolve_multiplier,
        0.0, 1.0);

    fragment_color = mix(
        texture(tex1, v_tex_coord, u_lod_bias),
        texture(tex2, v_tex_coord, u_lod_bias),
        l_renpy_imagedissolve_done);

## renpy.mask

Variables:

    uniform float u_lod_bias;
    uniform sampler2D tex0;
    uniform sampler2D tex1;
    uniform float u_renpy_mask_multiplier;
    uniform float u_renpy_mask_offset;
    in vec2 a_tex_coord;
    out vec2 v_tex_coord;

Vertex shader (priority 200):

    v_tex_coord = a_tex_coord;

Fragment shader (priority 200):

    float l_renpy_mask_mask = texture(tex1, v_tex_coord, u_lod_bias).a;

    fragment_color = texture(tex0, v_tex_coord, u_lod_bias)
        * (l_renpy_mask_mask * u_renpy_mask_multiplier + u_renpy_mask_offset);

## renpy.matrixcolor

Variables:

    uniform mat4 u_renpy_matrixcolor;

Fragment shader (priority 400):

    fragment_color = u_renpy_matrixcolor * fragment_color;

## renpy.movie_yuv

Variables:

    uniform sampler2D tex0;
    uniform sampler2D tex1;
    uniform float u_movie_yuv_full_range;
    uniform float u_movie_yuv_bt709;
    in vec2 a_tex_coord;
    out vec2 v_tex_coord;

Vertex shader (priority 200):

    v_tex_coord = a_tex_coord;

Fragment shader (priority 200):

    // Rec. 601 used for standard definition.
    const mat3 l_renpy_movie_yuv_bt601 = mat3(
        1.0,    1.0,       1.0,
        0.0,   -0.344136,  1.772,
        1.402, -0.714136,  0.0);

    // Rec. 709 used for high definition.
    const mat3 l_renpy_movie_yuv_bt709 = mat3(
        1.0,    1.0,       1.0,
        0.0,   -0.187324,  1.8556,
        1.5748, -0.468124,  0.0);

    float l_renpy_movie_yuv_luma = texture(tex0, v_tex_coord).r;
    vec2 l_renpy_movie_yuv_chroma = texture(tex1, v_tex_coord).ra - 0.5;

    if (u_movie_yuv_full_range < 0.5) {
        // Studio swing puts luma in 16-235 and chroma in 16-240, of 0-255.
        l_renpy_movie_yuv_luma = (l_renpy_movie_yuv_luma - 16.0 / 255.0) * (255.0 / 219.0);
        l_renpy_movie_yuv_chroma *= 255.0 / 224.0;
    }

    vec3 l_renpy_movie_yuv_yuv = vec3(l_renpy_movie_yuv_luma, l_renpy_movie_yuv_chroma);
    vec3 l_renpy_movie_yuv_rgb = (u_movie_yuv_bt709 > 0.5) ? l_renpy_movie_yuv_bt709 * l_renpy_movie_yuv_yuv : l_renpy_movie_yuv_bt601 * l_renpy_movie_yuv_yuv;

    fragment_color = vec4(clamp(l_renpy_movie_yuv_rgb, 0.0, 1.0), 1.0);

## renpy.red_to_alpha

Fragment shader (priority 450):

    fragment_color = vec4(fragment_color.r);

## renpy.solid

Variables:

    uniform vec4 u_renpy_solid_color;

Fragment shader (priority 200):

    fragment_color = u_renpy_solid_color;

## renpy.texture

Variables:

    uniform float u_lod_bias;
    uniform sampler2D tex0;
    in vec2 a_tex_coord;
    out vec2 v_tex_coord;

Vertex shader (priority 200):

    v_tex_coord = a_tex_coord;

Fragment shader (priority 200):

    fragment_color = texture(tex0, v_tex_coord, u_lod_bias);

## textshader.dissolve

Variables:

    uniform float u_textshader_dissolve_duration;
    uniform float u_text_slow_duration;
    uniform float u_text_slow_time;
    in float a_text_time;
    out float v_text_time;

Vertex shader (priority 200):

    v_text_time = a_text_time;

Fragment shader (priority 350):

    float l_textshader_dissolve_duration = u_textshader_dissolve_duration * u_text_slow_duration;
    float l_textshader_dissolve_done = step(v_text_time, u_text_slow_time);

    if (l_textshader_dissolve_duration > 0.0) {
        l_textshader_dissolve_done = clamp((u_text_slow_time - v_text_time) / l_textshader_dissolve_duration, 0.0, 1.0);
    }

    fragment_color *= l_textshader_dissolve_done;

## textshader.flip

Variables:

    uniform float u_textshader_flip_duration;
    uniform float u_text_slow_duration;
    uniform float u_text_slow_time;
    in vec2 a_text_center;
    in float a_text_min_time;

Vertex shader (priority 20):

    float l_textshader_flip_duration = u_textshader_flip_duration * u_text_slow_duration;
    float l_textshader_flip_done = step(a_text_min_time, u_text_slow_time);

    if (l_textshader_flip_duration > 0.0) {
        l_textshader_flip_done = clamp((u_text_slow_time - a_text_min_time) / l_textshader_flip_duration, 0.0, 1.0);
    }

    gl_Position.x = mix(2.0 * a_text_center.x - gl_Position.x, gl_Position.x, l_textshader_flip_done);

## textshader.jitter

Variables:

    uniform vec2 u_textshader_jitter_jitter;
    uniform vec4 u_random;
    uniform float u_text_to_drawable;

Vertex shader (priority 30):

    vec2 l_textshader_jitter_jitter = u_textshader_jitter_jitter * u_text_to_drawable;
    gl_Position.xy += l_textshader_jitter_jitter * u_random.xy - l_textshader_jitter_jitter / 2.0;

## textshader.linetexture

Variables:

    uniform sampler2D u_textshader_linetexture_texture;
    uniform vec2 u_textshader_linetexture_scale;
    uniform vec2 u_textshader_linetexture_texture_res;

    uniform float u_text_to_virtual;
    uniform float u_text_main;

    in vec2 a_text_center;
    out vec2 v_textshader_linetexture_coord;

Vertex shader (priority 10):

    v_textshader_linetexture_coord = vec2(gl_Position.x, gl_Position.y - a_text_center.y) / u_textshader_linetexture_scale * u_text_to_virtual / u_textshader_linetexture_texture_res;
    v_textshader_linetexture_coord.y += 0.5;

Fragment shader (priority 300):

    if (u_text_main == 1.0) {
        fragment_color *= texture(u_textshader_linetexture_texture, v_textshader_linetexture_coord);
    }

## textshader.offset

Variables:

    uniform vec2 u_textshader_offset_offset;
    uniform float u_text_to_drawable;

Vertex shader (priority 35):

    gl_Position.xy += u_textshader_offset_offset * u_text_to_drawable;

## textshader.slowalpha

Variables:

    uniform float u_textshader_slowalpha_alpha;

Fragment shader (priority 325):

    vec4 l_textshader_slowalpha_color = fragment_color;

Fragment shader (priority 375):

    fragment_color = mix(fragment_color, l_textshader_slowalpha_color, u_textshader_slowalpha_alpha);

## textshader.texture

Variables:

    uniform sampler2D u_textshader_texture_texture;
    uniform vec2 u_textshader_texture_texture_res;

    uniform float u_text_to_virtual;
    uniform float u_text_main;
    out vec2 v_textshader_texture_coord;

Vertex shader (priority 10):

    v_textshader_texture_coord = u_text_to_virtual * gl_Position.xy / u_textshader_texture_texture_res;

Fragment shader (priority 300):

    if (u_text_main == 1.0) {
        fragment_color *= texture(u_textshader_texture_texture, v_textshader_texture_coord);
    }

## textshader.typewriter

Variables:

    uniform float u_text_slow_time;
    in float a_text_min_time;
    out float v_text_min_time;

Vertex shader (priority 200):

    v_text_min_time = a_text_min_time;

Fragment shader (priority 350):

    fragment_color *= step(v_text_min_time, u_text_slow_time);

## textshader.wave

Variables:

    uniform float u_textshader_wave_amplitude;
    uniform float u_textshader_wave_frequency;
    uniform float u_textshader_wave_wavelength;

    uniform float u_time;
    uniform float u_text_to_drawable;
    in float a_text_index;

Vertex shader (priority 40):

    const float l_textshader_wave_two_pi = 6.28318530718;

    float l_textshader_wave_phase = a_text_index / u_textshader_wave_wavelength + u_time * u_textshader_wave_frequency;
    gl_Position.y += cos(l_textshader_wave_two_pi * l_textshader_wave_phase) * u_textshader_wave_amplitude * u_text_to_drawable;

## textshader.zoom

Variables:

    uniform float u_textshader_zoom_zoom;
    uniform float u_textshader_zoom_duration;
    uniform float u_text_slow_duration;
    uniform float u_text_slow_time;
    in vec2 a_text_center;
    in float a_text_min_time;

Vertex shader (priority 25):

    float l_textshader_zoom_duration = u_textshader_zoom_duration * u_text_slow_duration;

    if (l_textshader_zoom_duration > 0.0) {
        float l_textshader_zoom_done = clamp((u_text_slow_time - a_text_min_time) / l_textshader_zoom_duration, 0.0, 1.0);
        gl_Position.xy = mix(a_text_center + (gl_Position.xy - a_text_center) * u_textshader_zoom_zoom, gl_Position.xy, l_textshader_zoom_done);
    }