mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-10-23 13:43:00 +00:00
Autoformat slang code
This commit is contained in:
parent
24a7a9d50b
commit
953ac19e77
40 changed files with 1264 additions and 1209 deletions
|
|
@ -41,7 +41,7 @@ for x in os.listdir(base):
|
|||
if file.startswith('wayland-') and os.path.basename(root) == 'glfw':
|
||||
continue
|
||||
ext = os.path.splitext(file)[1]
|
||||
if ext in ('.c', '.h', '.m'):
|
||||
if ext in ('.c', '.h', '.m', '.slang'):
|
||||
clang_files.append(os.path.join(root, file))
|
||||
|
||||
CACHE_DIR = os.path.join(base, '.cache', 'autoformat')
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ This is in a :file:`.slang` file. It must define a function called
|
|||
``fragment_main()`` whose signature is:
|
||||
|
||||
.. literalinclude:: ../kitty/shaders/custom/sample.slang
|
||||
:start-at: public float4 fragment_main(
|
||||
:start-after: START_FUNCTION_SIGNATURE
|
||||
:end-before: END_FUNCTION_SIGNATURE
|
||||
|
||||
The two structs passed into this function have the definition shown below:
|
||||
|
|
|
|||
|
|
@ -6,14 +6,16 @@ module alpha_blend;
|
|||
|
||||
// Alpha blend two colors returning the resulting color pre-multiplied by its alpha
|
||||
// and its alpha. See https://en.wikipedia.org/wiki/Alpha_compositing
|
||||
public float4 alpha_blend(float4 over, float4 under) {
|
||||
public float4
|
||||
alpha_blend(float4 over, float4 under) {
|
||||
float alpha = lerp(under.a, 1.0f, over.a);
|
||||
float3 combined_color = lerp(under.rgb * under.a, over.rgb, over.a);
|
||||
return float4(combined_color, alpha);
|
||||
}
|
||||
|
||||
// Same as alpha_blend() except that it assumes over and under are both premultiplied.
|
||||
public float4 alpha_blend_premul(float4 over, float4 under) {
|
||||
public float4
|
||||
alpha_blend_premul(float4 over, float4 under) {
|
||||
float inv_over_alpha = 1.0f - over.a;
|
||||
float alpha = over.a + under.a * inv_over_alpha;
|
||||
return float4(over.rgb + under.rgb * inv_over_alpha, alpha);
|
||||
|
|
@ -21,8 +23,8 @@ public float4 alpha_blend_premul(float4 over, float4 under) {
|
|||
|
||||
// Same as alpha_blend_premul with under_alpha = 1 outputs a blended color
|
||||
// with alpha 1 which is effectively pre-multiplied since alpha is 1
|
||||
public float4 alpha_blend_premul(float4 over, float3 under) {
|
||||
public float4
|
||||
alpha_blend_premul(float4 over, float3 under) {
|
||||
float inv_over_alpha = 1.0f - over.a;
|
||||
return float4(over.rgb + under.rgb * inv_over_alpha, 1.0f);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ import utils;
|
|||
#define NUM_COLORS 256
|
||||
|
||||
// Inputs {{{
|
||||
public struct CellRenderData
|
||||
{
|
||||
public struct CellRenderData {
|
||||
public float use_cell_bg_for_selection_fg, use_cell_fg_for_selection_fg, use_cell_for_selection_bg;
|
||||
|
||||
public uint default_fg, highlight_fg, highlight_bg, main_cursor_fg, main_cursor_bg, url_color, url_style, inverted, extra_cursor_fg, extra_cursor_bg;
|
||||
|
|
@ -45,19 +44,20 @@ public ConstantBuffer<GammaLUT> glt;
|
|||
#define gamma_lut glt.gamma_lut
|
||||
//
|
||||
|
||||
static const int fg_index_map[3] = {0, 1, 0};
|
||||
static const int fg_index_map[3] = { 0, 1, 0 };
|
||||
static const uint2 cell_pos_map[4] = {
|
||||
uint2(1u, 0u), // right, top
|
||||
uint2(1u, 1u), // right, bottom
|
||||
uint2(0u, 1u), // left, bottom
|
||||
uint2(0u, 0u) // left, top
|
||||
uint2(1u, 0u), // right, top
|
||||
uint2(1u, 1u), // right, bottom
|
||||
uint2(0u, 1u), // left, bottom
|
||||
uint2(0u, 0u) // left, top
|
||||
};
|
||||
static const uint cursor_shape_map[] = { // maps cursor shape to foreground sprite index
|
||||
0u, // NO_CURSOR
|
||||
0u, // BLOCK (this is rendered as background)
|
||||
2u, // BEAM
|
||||
3u, // UNDERLINE
|
||||
4u // UNFOCUSED
|
||||
static const uint cursor_shape_map[] = {
|
||||
// maps cursor shape to foreground sprite index
|
||||
0u, // NO_CURSOR
|
||||
0u, // BLOCK (this is rendered as background)
|
||||
2u, // BEAM
|
||||
3u, // UNDERLINE
|
||||
4u // UNFOCUSED
|
||||
};
|
||||
|
||||
// }}}
|
||||
|
|
@ -69,7 +69,8 @@ public static const uint BIT_MASK = 1u;
|
|||
// Linear space luminance values
|
||||
public static const float3 Y = float3(0.2126, 0.7152, 0.0722);
|
||||
|
||||
public float3 color_to_vec(uint c) {
|
||||
public float3
|
||||
color_to_vec(uint c) {
|
||||
uint r, g, b;
|
||||
r = (c >> 16) & BYTE_MASK;
|
||||
g = (c >> 8) & BYTE_MASK;
|
||||
|
|
@ -77,21 +78,25 @@ public float3 color_to_vec(uint c) {
|
|||
return float3(gamma_lut[r], gamma_lut[g], gamma_lut[b]);
|
||||
}
|
||||
|
||||
public float one_if_equal_zero_otherwise(float a, float b) {
|
||||
public float
|
||||
one_if_equal_zero_otherwise(float a, float b) {
|
||||
return (1.0f - zero_or_one(abs(float(a) - float(b))));
|
||||
}
|
||||
|
||||
// We need an integer variant to accommodate GPU driver bugs, see
|
||||
// https://github.com/kovidgoyal/kitty/issues/9072
|
||||
public uint one_if_equal_zero_otherwise(int a, int b) {
|
||||
public uint
|
||||
one_if_equal_zero_otherwise(int a, int b) {
|
||||
return (1u - uint(zero_or_one(abs(float(a) - float(b)))));
|
||||
}
|
||||
|
||||
public uint one_if_equal_zero_otherwise(uint a, uint b) {
|
||||
public uint
|
||||
one_if_equal_zero_otherwise(uint a, uint b) {
|
||||
return (1u - uint(zero_or_one(abs(float(a) - float(b)))));
|
||||
}
|
||||
|
||||
public uint resolve_color(uint c, uint defval) {
|
||||
public uint
|
||||
resolve_color(uint c, uint defval) {
|
||||
int t = int(c & BYTE_MASK);
|
||||
uint is_one = one_if_equal_zero_otherwise(t, 1);
|
||||
uint is_two = one_if_equal_zero_otherwise(t, 2);
|
||||
|
|
@ -99,30 +104,32 @@ public uint resolve_color(uint c, uint defval) {
|
|||
return is_one * color_table[(c >> 8) & BYTE_MASK] + is_two * (c >> 8) + is_neither_one_nor_two * defval;
|
||||
}
|
||||
|
||||
public float3 to_color(uint c, uint defval) {
|
||||
public float3
|
||||
to_color(uint c, uint defval) {
|
||||
return color_to_vec(resolve_color(c, defval));
|
||||
}
|
||||
|
||||
[ForceInline]
|
||||
float3 q_func(float type_val, uint which, float3 val) {
|
||||
float3
|
||||
q_func(float type_val, uint which, float3 val) {
|
||||
return one_if_equal_zero_otherwise(type_val, float(which)) * val;
|
||||
}
|
||||
|
||||
float3 resolve_dynamic_color(uint c, float3 special_val, float3 defval) {
|
||||
float3
|
||||
resolve_dynamic_color(uint c, float3 special_val, float3 defval) {
|
||||
float type_val = float((c >> 24) & BYTE_MASK);
|
||||
return (
|
||||
q_func(type_val, COLOR_IS_RGB, color_to_vec(c)) +
|
||||
q_func(type_val, COLOR_IS_INDEX, color_to_vec(color_table[c & BYTE_MASK])) +
|
||||
q_func(type_val, COLOR_IS_SPECIAL, special_val) +
|
||||
q_func(type_val, COLOR_NOT_SET, defval)
|
||||
);
|
||||
q_func(type_val, COLOR_IS_RGB, color_to_vec(c)) + q_func(type_val, COLOR_IS_INDEX, color_to_vec(color_table[c & BYTE_MASK])) +
|
||||
q_func(type_val, COLOR_IS_SPECIAL, special_val) + q_func(type_val, COLOR_NOT_SET, defval));
|
||||
}
|
||||
|
||||
public float contrast_ratio(float under_luminance, float over_luminance) {
|
||||
public float
|
||||
contrast_ratio(float under_luminance, float over_luminance) {
|
||||
return clamp((max(under_luminance, over_luminance) + 0.05f) / (min(under_luminance, over_luminance) + 0.05f), 1.f, 21.f);
|
||||
}
|
||||
|
||||
public float contrast_ratio(float3 a, float3 b) {
|
||||
public float
|
||||
contrast_ratio(float3 a, float3 b) {
|
||||
return contrast_ratio(dot(a, Y), dot(b, Y));
|
||||
}
|
||||
|
||||
|
|
@ -130,25 +137,23 @@ public struct ColorPair {
|
|||
public float3 bg, fg;
|
||||
};
|
||||
|
||||
float contrast_ratio(ColorPair a) {
|
||||
float
|
||||
contrast_ratio(ColorPair a) {
|
||||
return contrast_ratio(a.bg, a.fg);
|
||||
}
|
||||
|
||||
ColorPair if_less_than_pair(float a, float b, ColorPair thenval, ColorPair elseval) {
|
||||
return ColorPair(
|
||||
if_less_than(a, b, thenval.bg, elseval.bg),
|
||||
if_less_than(a, b, thenval.fg, elseval.fg)
|
||||
);
|
||||
ColorPair
|
||||
if_less_than_pair(float a, float b, ColorPair thenval, ColorPair elseval) {
|
||||
return ColorPair(if_less_than(a, b, thenval.bg, elseval.bg), if_less_than(a, b, thenval.fg, elseval.fg));
|
||||
}
|
||||
|
||||
ColorPair if_one_then_pair(float condition, ColorPair thenval, ColorPair elseval) {
|
||||
return ColorPair(
|
||||
if_one_then(condition, thenval.bg, elseval.bg),
|
||||
if_one_then(condition, thenval.fg, elseval.fg)
|
||||
);
|
||||
ColorPair
|
||||
if_one_then_pair(float condition, ColorPair thenval, ColorPair elseval) {
|
||||
return ColorPair(if_one_then(condition, thenval.bg, elseval.bg), if_one_then(condition, thenval.fg, elseval.fg));
|
||||
}
|
||||
|
||||
ColorPair resolve_extra_cursor_colors_for_special_cursor(float3 cell_bg, float3 cell_fg) {
|
||||
ColorPair
|
||||
resolve_extra_cursor_colors_for_special_cursor(float3 cell_bg, float3 cell_fg) {
|
||||
ColorPair cell = ColorPair(cell_fg, cell_bg);
|
||||
ColorPair base = ColorPair(color_to_vec(crd.default_fg), color_to_vec(crd.bg_colors0));
|
||||
float cr = contrast_ratio(cell);
|
||||
|
|
@ -157,37 +162,34 @@ ColorPair resolve_extra_cursor_colors_for_special_cursor(float3 cell_bg, float3
|
|||
return if_less_than_pair(cr, 2.5f, higher_contrast_pair, cell);
|
||||
}
|
||||
|
||||
ColorPair resolve_extra_cursor_colors(float3 cell_bg, float3 cell_fg, ColorPair main_cursor) {
|
||||
ColorPair
|
||||
resolve_extra_cursor_colors(float3 cell_bg, float3 cell_fg, ColorPair main_cursor) {
|
||||
ColorPair ans = ColorPair(
|
||||
resolve_dynamic_color(crd.extra_cursor_bg, main_cursor.bg, main_cursor.bg),
|
||||
resolve_dynamic_color(crd.extra_cursor_fg, cell_bg, main_cursor.fg)
|
||||
);
|
||||
resolve_dynamic_color(crd.extra_cursor_bg, main_cursor.bg, main_cursor.bg), resolve_dynamic_color(crd.extra_cursor_fg, cell_bg, main_cursor.fg));
|
||||
ColorPair special = resolve_extra_cursor_colors_for_special_cursor(cell_bg, cell_fg);
|
||||
return if_one_then_pair(zero_or_one(abs(float(crd.extra_cursor_bg & BYTE_MASK) - float(COLOR_IS_SPECIAL))), ans, special);
|
||||
}
|
||||
|
||||
uint is_cursor(uint x, uint y) {
|
||||
uint
|
||||
is_cursor(uint x, uint y) {
|
||||
uint clamped_x = clamp(x, crd.cursor_x1, crd.cursor_x2);
|
||||
uint clamped_y = clamp(y, crd.cursor_y1, crd.cursor_y2);
|
||||
return one_if_equal_zero_otherwise(x, clamped_x) * one_if_equal_zero_otherwise(y, clamped_y);
|
||||
}
|
||||
|
||||
float background_opacity_for(uint bg, uint colorval, float opacity_if_matched) {
|
||||
float
|
||||
background_opacity_for(uint bg, uint colorval, float opacity_if_matched) {
|
||||
float not_matched = step(1.0, abs(float(colorval) - float(bg)));
|
||||
return not_matched + opacity_if_matched * (1.0 - not_matched);
|
||||
}
|
||||
|
||||
float calc_background_opacity(uint bg) {
|
||||
float
|
||||
calc_background_opacity(uint bg) {
|
||||
return (
|
||||
background_opacity_for(bg, crd.bg_colors0, crd.bg_opacities0) *
|
||||
background_opacity_for(bg, crd.bg_colors1, crd.bg_opacities1) *
|
||||
background_opacity_for(bg, crd.bg_colors2, crd.bg_opacities2) *
|
||||
background_opacity_for(bg, crd.bg_colors3, crd.bg_opacities3) *
|
||||
background_opacity_for(bg, crd.bg_colors4, crd.bg_opacities4) *
|
||||
background_opacity_for(bg, crd.bg_colors5, crd.bg_opacities5) *
|
||||
background_opacity_for(bg, crd.bg_colors6, crd.bg_opacities6) *
|
||||
background_opacity_for(bg, crd.bg_colors7, crd.bg_opacities7)
|
||||
);
|
||||
background_opacity_for(bg, crd.bg_colors0, crd.bg_opacities0) * background_opacity_for(bg, crd.bg_colors1, crd.bg_opacities1) *
|
||||
background_opacity_for(bg, crd.bg_colors2, crd.bg_opacities2) * background_opacity_for(bg, crd.bg_colors3, crd.bg_opacities3) *
|
||||
background_opacity_for(bg, crd.bg_colors4, crd.bg_opacities4) * background_opacity_for(bg, crd.bg_colors5, crd.bg_opacities5) *
|
||||
background_opacity_for(bg, crd.bg_colors6, crd.bg_opacities6) * background_opacity_for(bg, crd.bg_colors7, crd.bg_opacities7));
|
||||
}
|
||||
// }}}
|
||||
|
||||
|
|
@ -205,20 +207,19 @@ public struct CellData {
|
|||
// plus the intermediate data the cell foreground pass needs.
|
||||
public struct BackgroundOutput {
|
||||
public float4 position;
|
||||
public float3 background_rgb; // final background color (linear, post cursor/selection)
|
||||
public float bg_alpha; // final alpha, post special-cell opacity (pre draw_bg_bitfield mask)
|
||||
public float3 background_rgb; // final background color (linear, post cursor/selection)
|
||||
public float bg_alpha; // final alpha, post special-cell opacity (pre draw_bg_bitfield mask)
|
||||
public float cell_has_default_bg;
|
||||
public float3 bg; // original background color, pre selection/cursor (used for selection fg)
|
||||
public float3 foreground; // resolved foreground color, pre selection/override
|
||||
public float3 bg; // original background color, pre selection/cursor (used for selection fg)
|
||||
public float3 foreground; // resolved foreground color, pre selection/override
|
||||
public uint fg_as_uint;
|
||||
public uint text_attrs;
|
||||
public uint is_reversed;
|
||||
public CellData cell_data;
|
||||
};
|
||||
|
||||
public BackgroundOutput compute_background(
|
||||
uint3 colors, uint2 sprite_idx, uint is_selected, uint instance_id, uint vertex_id
|
||||
) {
|
||||
public BackgroundOutput
|
||||
compute_background(uint3 colors, uint2 sprite_idx, uint is_selected, uint instance_id, uint vertex_id) {
|
||||
BackgroundOutput bo;
|
||||
|
||||
// set cell color indices {{{
|
||||
|
|
@ -234,7 +235,7 @@ public BackgroundOutput compute_background(
|
|||
bg_as_uint = has_mark * color_table[NUM_COLORS + mark - 1] + (BIT_MASK - has_mark) * bg_as_uint;
|
||||
float cell_has_default_bg = 1.f - step(1.f, abs(float(bg_as_uint - crd.bg_colors0))); // 1 if has default bg else 0
|
||||
float3 bg = color_to_vec(bg_as_uint);
|
||||
float3 cell_bg = bg; // preserve original bg for the selection foreground color
|
||||
float3 cell_bg = bg; // preserve original bg for the selection foreground color
|
||||
uint fg_as_uint = resolve_color(colors[fg_index], default_colors[fg_index]);
|
||||
fg_as_uint = has_mark * color_table[NUM_COLORS + MARK_MASK + mark] + (1u - has_mark) * fg_as_uint;
|
||||
float3 foreground = color_to_vec(fg_as_uint);
|
||||
|
|
@ -290,7 +291,7 @@ public BackgroundOutput compute_background(
|
|||
float effective_cursor_opacity = max(crd.cursor_opacity, bg_alpha);
|
||||
// is_special_cell is either 0 or 1
|
||||
float is_special_cell = cell_data.has_block_cursor + float(is_selected & BIT_MASK);
|
||||
is_special_cell += float(is_reversed); // reverse video cells should be opaque as well
|
||||
is_special_cell += float(is_reversed); // reverse video cells should be opaque as well
|
||||
is_special_cell = zero_or_one(is_special_cell);
|
||||
cell_has_default_bg = if_one_then(is_special_cell, 0., cell_has_default_bg);
|
||||
|
||||
|
|
@ -319,7 +320,8 @@ public BackgroundOutput compute_background(
|
|||
// same as the cell background pass but without the draw_bg_bitfield masking, so
|
||||
// the padding is always drawn. The premultiplied alpha ensures padding matches
|
||||
// its neighboring cell under a semi-transparent OS window.
|
||||
public float4 padding_background_premul(uint3 colors, uint2 sprite_idx, uint is_selected, uint instance_id) {
|
||||
public float4
|
||||
padding_background_premul(uint3 colors, uint2 sprite_idx, uint is_selected, uint instance_id) {
|
||||
BackgroundOutput bo = compute_background(colors, sprite_idx, is_selected, instance_id, 0u);
|
||||
return vec4_premul(bo.background_rgb, bo.bg_alpha);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@
|
|||
import alpha_blend;
|
||||
|
||||
// Constants and Macros
|
||||
#define left 0
|
||||
#define top 1
|
||||
#define right 2
|
||||
#define bottom 3
|
||||
#define left 0
|
||||
#define top 1
|
||||
#define right 2
|
||||
#define bottom 3
|
||||
#define tex_left 0.0
|
||||
#define tex_top 0.0
|
||||
#define tex_right 1.0
|
||||
|
|
@ -17,12 +17,7 @@ import alpha_blend;
|
|||
#define x_axis 0
|
||||
#define y_axis 1
|
||||
|
||||
static const float2 tex_map[4] = {
|
||||
float2(tex_left, tex_top),
|
||||
float2(tex_left, tex_bottom),
|
||||
float2(tex_right, tex_bottom),
|
||||
float2(tex_right, tex_top)
|
||||
};
|
||||
static const float2 tex_map[4] = { float2(tex_left, tex_top), float2(tex_left, tex_bottom), float2(tex_right, tex_bottom), float2(tex_right, tex_top) };
|
||||
|
||||
|
||||
struct VertexOutput {
|
||||
|
|
@ -31,11 +26,13 @@ struct VertexOutput {
|
|||
};
|
||||
|
||||
// Helper Functions
|
||||
float scale_factor(float window_size, float image_size) {
|
||||
float
|
||||
scale_factor(float window_size, float image_size) {
|
||||
return window_size / image_size;
|
||||
}
|
||||
|
||||
float tiling_factor(int i, float4 sizes, float tiled) {
|
||||
float
|
||||
tiling_factor(int i, float4 sizes, float tiled) {
|
||||
int window = i;
|
||||
int image = i + 2;
|
||||
return tiled * scale_factor(sizes[window], sizes[image]) + (1.0 - tiled);
|
||||
|
|
@ -43,12 +40,8 @@ float tiling_factor(int i, float4 sizes, float tiled) {
|
|||
|
||||
// Main Vertex Shader Entry Point
|
||||
[shader("vertex")]
|
||||
VertexOutput vertex_main(
|
||||
uint vertex_id : SV_VertexID,
|
||||
uniform float tiled,
|
||||
uniform float4 sizes,
|
||||
uniform float4 positions,
|
||||
) {
|
||||
VertexOutput
|
||||
vertex_main(uint vertex_id: SV_VertexID, uniform float tiled, uniform float4 sizes, uniform float4 positions, ) {
|
||||
const float2 pos_map[4] = {
|
||||
float2(positions[left], positions[top]),
|
||||
float2(positions[left], positions[bottom]),
|
||||
|
|
@ -60,10 +53,7 @@ VertexOutput vertex_main(
|
|||
VertexOutput output;
|
||||
// Calculate outputs
|
||||
float2 tex_coords = tex_map[vertex_id];
|
||||
output.texcoord = float2(
|
||||
tex_coords[x_axis] * tiling_factor(x_axis, sizes, tiled),
|
||||
tex_coords[y_axis] * tiling_factor(y_axis, sizes, tiled)
|
||||
);
|
||||
output.texcoord = float2(tex_coords[x_axis] * tiling_factor(x_axis, sizes, tiled), tex_coords[y_axis] * tiling_factor(y_axis, sizes, tiled));
|
||||
output.position = float4(pos_map[vertex_id], 0.0, 1.0);
|
||||
return output;
|
||||
}
|
||||
|
|
@ -73,7 +63,9 @@ uniform Sampler2D image;
|
|||
|
||||
// Main Fragment Shader Entry Point
|
||||
[shader("fragment")]
|
||||
float4 fragment_main(float2 texcoord: TEXCOORD, uniform float4 background) : SV_Target {
|
||||
float4
|
||||
fragment_main(float2 texcoord: TEXCOORD, uniform float4 background)
|
||||
: SV_Target {
|
||||
// Sample the texture using Slang's intrinsic texture object syntax
|
||||
float4 color = image.Sample(texcoord);
|
||||
// Compute final color with alpha blending
|
||||
|
|
|
|||
|
|
@ -16,18 +16,13 @@ public struct BlitOutput {
|
|||
#define bottom 3
|
||||
|
||||
// Static constant array mapping vertex IDs
|
||||
static const int2 vertex_pos_map[4] = {
|
||||
{right, top},
|
||||
{right, bottom},
|
||||
{left, bottom},
|
||||
{left, top}
|
||||
};
|
||||
static const int2 vertex_pos_map[4] = { { right, top }, { right, bottom }, { left, bottom }, { left, top } };
|
||||
|
||||
public BlitOutput get_coords_for_blit(uint vertex_id, float4 src_rect, float4 dest_rect) {
|
||||
public BlitOutput
|
||||
get_coords_for_blit(uint vertex_id, float4 src_rect, float4 dest_rect) {
|
||||
int2 pos = vertex_pos_map[vertex_id];
|
||||
BlitOutput output;
|
||||
output.texcoord = float2(src_rect[pos.x], src_rect[pos.y]);
|
||||
output.position = float2(dest_rect[pos.x], dest_rect[pos.y]);
|
||||
return output;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,19 +14,18 @@ struct VSOutput {
|
|||
|
||||
|
||||
[shader("vertex")]
|
||||
VSOutput vertex_main(
|
||||
uint vertex_id : SV_VertexID,
|
||||
uniform float4 src_rect,
|
||||
uniform float4 dest_rect,
|
||||
) {
|
||||
VSOutput
|
||||
vertex_main(uint vertex_id: SV_VertexID, uniform float4 src_rect, uniform float4 dest_rect, ) {
|
||||
BlitOutput ans = get_coords_for_blit(vertex_id, src_rect, dest_rect);
|
||||
return {ans.texcoord, float4(ans.position[0], ans.position[1], 0.0, 1.0)};
|
||||
return { ans.texcoord, float4(ans.position[0], ans.position[1], 0.0, 1.0) };
|
||||
}
|
||||
|
||||
uniform Sampler2D image;
|
||||
|
||||
[shader("fragment")]
|
||||
float4 fragment_main(float2 texcoord : TEXCOORD) : SV_Target {
|
||||
float4
|
||||
fragment_main(float2 texcoord: TEXCOORD)
|
||||
: SV_Target {
|
||||
float4 color_premul = image.Sample(texcoord);
|
||||
return vec4_premul(linear2srgb(color_premul.rgb / color_premul.a), color_premul.a);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,8 +34,7 @@ struct VertexInput {
|
|||
};
|
||||
|
||||
// Vertex shader output structure
|
||||
struct VertexOutput
|
||||
{
|
||||
struct VertexOutput {
|
||||
float4 color_premul : COLOR_PREMUL;
|
||||
float4 position : SV_Position;
|
||||
};
|
||||
|
|
@ -47,28 +46,26 @@ static const int RIGHT = 2;
|
|||
static const int BOTTOM = 3;
|
||||
static const uint FF = 0xff;
|
||||
|
||||
static const uint2 pos_map[4] = {
|
||||
uint2(RIGHT, TOP),
|
||||
uint2(RIGHT, BOTTOM),
|
||||
uint2(LEFT, BOTTOM),
|
||||
uint2(LEFT, TOP)
|
||||
};
|
||||
static const uint2 pos_map[4] = { uint2(RIGHT, TOP), uint2(RIGHT, BOTTOM), uint2(LEFT, BOTTOM), uint2(LEFT, TOP) };
|
||||
|
||||
float to_color(uint c) {
|
||||
float
|
||||
to_color(uint c) {
|
||||
return gamma_lut[c & FF];
|
||||
}
|
||||
|
||||
float is_integer_value(uint c, int x) {
|
||||
float
|
||||
is_integer_value(uint c, int x) {
|
||||
return 1. - step(0.5, abs(float(c) - float(x)));
|
||||
}
|
||||
|
||||
float3 as_color_vector(uint c, int shift) {
|
||||
float3
|
||||
as_color_vector(uint c, int shift) {
|
||||
return float3(to_color(c >> shift), to_color(c >> (shift - 8)), to_color(c >> (shift - 16)));
|
||||
}
|
||||
|
||||
[shader("vertex")]
|
||||
VertexOutput vertex_main(float4 rect, uint rect_color, uniform float background_opacity, uint vertex_id : SV_VertexID)
|
||||
{
|
||||
VertexOutput
|
||||
vertex_main(float4 rect, uint rect_color, uniform float background_opacity, uint vertex_id: SV_VertexID) {
|
||||
VertexOutput output;
|
||||
|
||||
uint2 pos = pos_map[vertex_id];
|
||||
|
|
@ -83,10 +80,9 @@ VertexOutput vertex_main(float4 rect, uint rect_color, uniform float background_
|
|||
color3 = if_one_then(is_window_bg, window_bg, color3);
|
||||
|
||||
// Actual border quads and tab bar edge strips must be always drawn opaque
|
||||
float is_not_a_border = zero_or_one(abs(
|
||||
(float(rc) - ACTIVE_BORDER_COLOR) * (float(rc) - INACTIVE_BORDER_COLOR) * (float(rc) - BELL_BORDER_COLOR) *
|
||||
(float(rc) - TAB_BAR_EDGE_LEFT_COLOR) * (float(rc) - TAB_BAR_EDGE_RIGHT_COLOR)
|
||||
));
|
||||
float is_not_a_border = zero_or_one(
|
||||
abs((float(rc) - ACTIVE_BORDER_COLOR) * (float(rc) - INACTIVE_BORDER_COLOR) * (float(rc) - BELL_BORDER_COLOR) * (float(rc) - TAB_BAR_EDGE_LEFT_COLOR) *
|
||||
(float(rc) - TAB_BAR_EDGE_RIGHT_COLOR)));
|
||||
|
||||
float final_opacity = if_one_then(is_not_a_border, background_opacity, 1.);
|
||||
output.color_premul = vec4_premul(color3, final_opacity);
|
||||
|
|
@ -95,6 +91,8 @@ VertexOutput vertex_main(float4 rect, uint rect_color, uniform float background_
|
|||
}
|
||||
|
||||
[shader("fragment")]
|
||||
float4 fragment_main(float4 color_premul : COLOR_PREMUL) : SV_Target {
|
||||
float4
|
||||
fragment_main(float4 color_premul: COLOR_PREMUL)
|
||||
: SV_Target {
|
||||
return color_premul;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ struct VertexOutput {
|
|||
|
||||
float3 background;
|
||||
float4 effective_background_premul;
|
||||
float effective_text_alpha;
|
||||
float effective_text_alpha;
|
||||
float3 sprite_pos;
|
||||
float3 underline_pos;
|
||||
float3 cursor_pos;
|
||||
|
|
@ -42,11 +42,12 @@ struct VertexOutput {
|
|||
float3 cell_foreground;
|
||||
float4 cursor_color_premult;
|
||||
float3 decoration_fg;
|
||||
float colored_sprite;
|
||||
float colored_sprite;
|
||||
};
|
||||
|
||||
// Foreground utility functions {{{
|
||||
uint3 to_sprite_coords(uint idx) {
|
||||
uint3
|
||||
to_sprite_coords(uint idx) {
|
||||
uint sprites_per_page = crd.sprites_xnum * crd.sprites_ynum;
|
||||
uint z = idx / sprites_per_page;
|
||||
uint num_on_last_page = idx - sprites_per_page * z;
|
||||
|
|
@ -55,23 +56,26 @@ uint3 to_sprite_coords(uint idx) {
|
|||
return uint3(x, y, z);
|
||||
}
|
||||
|
||||
float3 to_sprite_pos(uint2 pos, uint idx) {
|
||||
float3
|
||||
to_sprite_pos(uint2 pos, uint idx) {
|
||||
uint3 c = to_sprite_coords(idx);
|
||||
float2 s_xpos = float2(float(c.x), float(c.x) + 1.0f) * (1.0f / float(crd.sprites_xnum));
|
||||
float2 s_ypos = float2(float(c.y), float(c.y) + 1.0f) * (1.0f / float(crd.sprites_ynum));
|
||||
uint texture_height_px = (crd.cell_height + 1u) * crd.sprites_ynum;
|
||||
float row_height = 1.0f / float(texture_height_px);
|
||||
s_ypos[1] -= row_height; // skip the decorations_exclude row
|
||||
s_ypos[1] -= row_height; // skip the decorations_exclude row
|
||||
return float3(s_xpos[pos.x], s_ypos[pos.y], float(c.z));
|
||||
}
|
||||
|
||||
uint to_underline_exclusion_pos(uint2 sprite_idx) {
|
||||
uint
|
||||
to_underline_exclusion_pos(uint2 sprite_idx) {
|
||||
uint3 c = to_sprite_coords(sprite_idx[0]);
|
||||
uint cell_top_px = c.y * (crd.cell_height + 1u);
|
||||
return cell_top_px + crd.cell_height;
|
||||
}
|
||||
|
||||
uint read_sprite_decorations_idx(uint2 sprite_idx) {
|
||||
uint
|
||||
read_sprite_decorations_idx(uint2 sprite_idx) {
|
||||
int idx = int(sprite_idx[0] & SPRITE_INDEX_MASK);
|
||||
int width, height;
|
||||
sprite_decorations_map.GetDimensions(width, height);
|
||||
|
|
@ -81,29 +85,32 @@ uint read_sprite_decorations_idx(uint2 sprite_idx) {
|
|||
return sprite_decorations_map[int2(x, y)].r;
|
||||
}
|
||||
|
||||
uint2 get_decorations_indices(uint2 sprite_idx, uint in_url /* [0, 1] */, uint text_attrs) {
|
||||
uint2
|
||||
get_decorations_indices(uint2 sprite_idx, uint in_url /* [0, 1] */, uint text_attrs) {
|
||||
uint decorations_idx = read_sprite_decorations_idx(sprite_idx);
|
||||
uint has_decorations = uint(zero_or_one(float(decorations_idx)));
|
||||
uint strike_style = ((text_attrs >> STRIKE_SHIFT) & BIT_MASK); // 0 or 1
|
||||
uint strike_idx = decorations_idx * strike_style;
|
||||
uint underline_style = ((text_attrs >> DECORATION_SHIFT) & DECORATION_MASK);
|
||||
underline_style = in_url * crd.url_style + (1u - in_url) * underline_style; // [0, 5]
|
||||
uint has_underline = uint(step(0.5f, float(underline_style))); // [0, 1]
|
||||
uint has_underline = uint(step(0.5f, float(underline_style))); // [0, 1]
|
||||
return has_decorations * uint2(strike_idx, has_underline * (decorations_idx + underline_style));
|
||||
}
|
||||
// }}}
|
||||
|
||||
// Override foreground colors {{{
|
||||
float3 fg_override_luminance(float colored_sprite, float under_luminance, float over_lumininace, float3 under, float3 over) {
|
||||
float3
|
||||
fg_override_luminance(float colored_sprite, float under_luminance, float over_lumininace, float3 under, float3 over) {
|
||||
// If the difference in luminance is too small,
|
||||
// force the foreground color to be black or white.
|
||||
float diff_luminance = abs(under_luminance - over_lumininace);
|
||||
float override_level = (1.f - colored_sprite) * step(diff_luminance, crd.fg_override_threshold);
|
||||
float original_level = 1.f - override_level;
|
||||
return original_level * over + override_level * float3(step(under_luminance, 0.5f));
|
||||
float override_level = (1.f - colored_sprite) * step(diff_luminance, crd.fg_override_threshold);
|
||||
float original_level = 1.f - override_level;
|
||||
return original_level * over + override_level * float3(step(under_luminance, 0.5f));
|
||||
}
|
||||
|
||||
float3 fg_override_contrast(float under_luminance, float over_luminance, float3 under, float3 over) {
|
||||
float3
|
||||
fg_override_contrast(float under_luminance, float over_luminance, float3 under, float3 over) {
|
||||
float ratio = contrast_ratio(under_luminance, over_luminance);
|
||||
float3 diff = abs(under - over);
|
||||
float3 over_hsluv = rgbToHsluv(over);
|
||||
|
|
@ -119,7 +126,8 @@ float3 fg_override_contrast(float under_luminance, float over_luminance, float3
|
|||
return lerp(result, over, fallback_condition);
|
||||
}
|
||||
|
||||
float3 override_foreground_color(float3 over, float3 under, float colored_sprite) {
|
||||
float3
|
||||
override_foreground_color(float3 over, float3 under, float colored_sprite) {
|
||||
float under_luminance = dot(under, Y);
|
||||
float over_lumininace = dot(over.rgb, Y);
|
||||
if (FG_OVERRIDE_ALGO == 1) return fg_override_luminance(colored_sprite, under_luminance, over_lumininace, under, over);
|
||||
|
|
@ -128,14 +136,14 @@ float3 override_foreground_color(float3 over, float3 under, float colored_sprite
|
|||
// }}}
|
||||
|
||||
[shader("vertex")]
|
||||
VertexOutput vertex_main(
|
||||
VertexOutput
|
||||
vertex_main(
|
||||
[[vk::location(0)]] uint3 colors,
|
||||
[[vk::location(1)]] uint2 sprite_idx,
|
||||
[[vk::location(2)]] uint is_selected,
|
||||
uint vertex_id : SV_VertexID,
|
||||
uint instance_id : SV_InstanceID,
|
||||
uniform uint draw_bg_bitfield,
|
||||
) {
|
||||
[[vk::location(2)]] uint is_selected,
|
||||
uint vertex_id: SV_VertexID,
|
||||
uint instance_id: SV_InstanceID,
|
||||
uniform uint draw_bg_bitfield, ) {
|
||||
VertexOutput vo;
|
||||
|
||||
BackgroundOutput bo = compute_background(colors, sprite_idx, is_selected, instance_id, vertex_id);
|
||||
|
|
@ -153,8 +161,7 @@ VertexOutput vertex_main(
|
|||
vo.colored_sprite = float((sprite_idx[0] & SPRITE_COLORED_MASK) >> SPRITE_COLORED_SHIFT);
|
||||
|
||||
float has_dim = float((text_attrs >> DIM_SHIFT) & BIT_MASK), has_blink = float((text_attrs >> BLINK_SHIFT) & BIT_MASK);
|
||||
vo.effective_text_alpha = crd.inactive_text_alpha * if_one_then(has_dim, crd.dim_opacity, 1.0) * if_one_then(
|
||||
has_blink, crd.blink_opacity, 1.0);
|
||||
vo.effective_text_alpha = crd.inactive_text_alpha * if_one_then(has_dim, crd.dim_opacity, 1.0) * if_one_then(has_blink, crd.blink_opacity, 1.0);
|
||||
float in_url = float((is_selected >> 1) & BIT_MASK);
|
||||
vo.decoration_fg = if_one_then(in_url, color_to_vec(crd.url_color), to_color(colors[2], fg_as_uint));
|
||||
// Selection
|
||||
|
|
@ -203,21 +210,25 @@ uniform Sampler2DArray sprites;
|
|||
// Scaling factor for the extra text-alpha adjustment for luminance-difference.
|
||||
static const float text_gamma_scaling = 0.5;
|
||||
|
||||
float clamp_to_unit_float(float x) {
|
||||
float
|
||||
clamp_to_unit_float(float x) {
|
||||
// Clamp value to suitable output range
|
||||
return clamp(x, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
float4 foreground_contrast_new(float4 over, float3 under, float text_contrast, float text_gamma_adjustment) {
|
||||
float4
|
||||
foreground_contrast_new(float4 over, float3 under, float text_contrast, float text_gamma_adjustment) {
|
||||
float under_luminance = dot(under, Y);
|
||||
float over_lumininace = dot(over.rgb, Y);
|
||||
// Apply additional gamma-adjustment scaled by the luminance difference, the darker the foreground the more adjustment we apply.
|
||||
// A multiplicative contrast is also available to increase saturation.
|
||||
over.a = clamp_to_unit_float(lerp(over.a, pow(over.a, text_gamma_adjustment), (1 - over_lumininace + under_luminance) * text_gamma_scaling) * text_contrast);
|
||||
over.a =
|
||||
clamp_to_unit_float(lerp(over.a, pow(over.a, text_gamma_adjustment), (1 - over_lumininace + under_luminance) * text_gamma_scaling) * text_contrast);
|
||||
return over;
|
||||
}
|
||||
|
||||
float4 foreground_contrast_old(float4 over, float3 under) {
|
||||
float4
|
||||
foreground_contrast_old(float4 over, float3 under) {
|
||||
// Simulation of gamma-incorrect blending
|
||||
float under_luminance = dot(under, Y);
|
||||
float over_lumininace = dot(over.rgb, Y);
|
||||
|
|
@ -225,27 +236,37 @@ float4 foreground_contrast_old(float4 over, float3 under) {
|
|||
//
|
||||
// linear2srgb(over * overA2 + under * (1 - overA2)) = linear2srgb(over) * over.a + linear2srgb(under) * (1 - over.a)
|
||||
// ^ gamma correct blending with new alpha ^ gamma incorrect blending with old alpha
|
||||
over.a = clamp_to_unit_float((srgb2linear(linear2srgb(over_lumininace) * over.a + linear2srgb(under_luminance) * (1.0f - over.a)) - under_luminance) / (over_lumininace - under_luminance));
|
||||
over.a = clamp_to_unit_float(
|
||||
(srgb2linear(linear2srgb(over_lumininace) * over.a + linear2srgb(under_luminance) * (1.0f - over.a)) - under_luminance) /
|
||||
(over_lumininace - under_luminance));
|
||||
return over;
|
||||
}
|
||||
|
||||
float4 foreground_contrast(float4 over, float3 under, float text_contrast, float text_gamma_adjustment) {
|
||||
float4
|
||||
foreground_contrast(float4 over, float3 under, float text_contrast, float text_gamma_adjustment) {
|
||||
if (TEXT_NEW_GAMMA) return foreground_contrast_new(over, under, text_contrast, text_gamma_adjustment);
|
||||
return foreground_contrast_old(over, under);
|
||||
}
|
||||
|
||||
float4 load_text_foreground_color(float3 sprite_pos, float colored_sprite, float3 cell_foreground) {
|
||||
float4
|
||||
load_text_foreground_color(float3 sprite_pos, float colored_sprite, float3 cell_foreground) {
|
||||
// For colored sprites use the color from the sprite rather than the text foreground
|
||||
// Return non-premultiplied foreground color
|
||||
float4 text_fg = sprites.Sample(sprite_pos);
|
||||
return float4(lerp(cell_foreground, text_fg.xyz, colored_sprite), text_fg.w);
|
||||
}
|
||||
|
||||
float4 calculate_premul_foreground_from_sprites(
|
||||
float3 sprite_pos, float3 underline_pos, float3 cursor_pos, float3 strike_pos, uint underline_exclusion_pos,
|
||||
float4 text_fg, float3 decoration_fg, float4 cursor_color_premult,
|
||||
float effective_text_alpha,
|
||||
) {
|
||||
float4
|
||||
calculate_premul_foreground_from_sprites(
|
||||
float3 sprite_pos,
|
||||
float3 underline_pos,
|
||||
float3 cursor_pos,
|
||||
float3 strike_pos,
|
||||
uint underline_exclusion_pos,
|
||||
float4 text_fg,
|
||||
float3 decoration_fg,
|
||||
float4 cursor_color_premult,
|
||||
float effective_text_alpha, ) {
|
||||
// Return premul foreground color from decorations (cursor, underline, strikethrough)
|
||||
int width, height, layer;
|
||||
sprites.GetDimensions(width, height, layer);
|
||||
|
|
@ -261,24 +282,20 @@ float4 calculate_premul_foreground_from_sprites(
|
|||
|
||||
float combined_alpha = min(text_fg.w + strike_alpha, 1.0);
|
||||
|
||||
float4 ans = alpha_blend(
|
||||
float4(text_fg.rgb, combined_alpha * effective_text_alpha),
|
||||
float4(decoration_fg, underline_alpha * effective_text_alpha)
|
||||
);
|
||||
float4 ans = alpha_blend(float4(text_fg.rgb, combined_alpha * effective_text_alpha), float4(decoration_fg, underline_alpha * effective_text_alpha));
|
||||
|
||||
return lerp(ans, cursor_color_premult, cursor_alpha * cursor_color_premult.w);
|
||||
}
|
||||
|
||||
float4 adjust_foreground_contrast_with_background(float4 text_fg, float3 bg, float text_contrast, float text_gamma_adjustment) {
|
||||
float4
|
||||
adjust_foreground_contrast_with_background(float4 text_fg, float3 bg, float text_contrast, float text_gamma_adjustment) {
|
||||
return foreground_contrast(text_fg, bg, text_contrast, text_gamma_adjustment);
|
||||
}
|
||||
|
||||
[shader("fragment")]
|
||||
float4 fragment_main(
|
||||
VertexOutput vo,
|
||||
uniform float text_contrast,
|
||||
uniform float text_gamma_adjustment,
|
||||
) : SV_Target {
|
||||
float4
|
||||
fragment_main(VertexOutput vo, uniform float text_contrast, uniform float text_gamma_adjustment, )
|
||||
: SV_Target {
|
||||
float4 ans_premul = 0;
|
||||
if (!ONLY_FOREGROUND) ans_premul = vo.effective_background_premul;
|
||||
|
||||
|
|
@ -287,8 +304,15 @@ float4 fragment_main(
|
|||
float4 text_fg = load_text_foreground_color(vo.sprite_pos, vo.colored_sprite, vo.cell_foreground);
|
||||
text_fg = adjust_foreground_contrast_with_background(text_fg, vo.background, text_contrast, text_gamma_adjustment);
|
||||
float4 text_fg_premul = calculate_premul_foreground_from_sprites(
|
||||
vo.sprite_pos, vo.underline_pos, vo.cursor_pos, vo.strike_pos, vo.underline_exclusion_pos,
|
||||
text_fg, vo.decoration_fg, vo.cursor_color_premult, vo.effective_text_alpha);
|
||||
vo.sprite_pos,
|
||||
vo.underline_pos,
|
||||
vo.cursor_pos,
|
||||
vo.strike_pos,
|
||||
vo.underline_exclusion_pos,
|
||||
text_fg,
|
||||
vo.decoration_fg,
|
||||
vo.cursor_color_premult,
|
||||
vo.effective_text_alpha);
|
||||
if (ONLY_FOREGROUND) ans_premul = text_fg_premul;
|
||||
else ans_premul = alpha_blend_premul(text_fg_premul, ans_premul);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,30 +10,30 @@ import kitty_custom_shader_types;
|
|||
|
||||
// Golden spiral samples [x, y, weight] — weight is inverse of distance
|
||||
static const float3 samples[24] = {
|
||||
float3(0.1693761725038636, 0.9855514761735895, 1.0),
|
||||
float3(-1.333070830962943, 0.4721463328627773, 0.7071067811865475),
|
||||
float3(-0.8464394909806497, -1.51113870578065, 0.5773502691896258),
|
||||
float3(1.554155680728463, -1.2588090085709776, 0.5),
|
||||
float3(1.681364377589461, 1.4741145918052656, 0.4472135954999579),
|
||||
float3(-1.2795157692199817, 2.088741103228784, 0.4082482904638631),
|
||||
float3(0.1693761725038636, 0.9855514761735895, 1.0),
|
||||
float3(-1.333070830962943, 0.4721463328627773, 0.7071067811865475),
|
||||
float3(-0.8464394909806497, -1.51113870578065, 0.5773502691896258),
|
||||
float3(1.554155680728463, -1.2588090085709776, 0.5),
|
||||
float3(1.681364377589461, 1.4741145918052656, 0.4472135954999579),
|
||||
float3(-1.2795157692199817, 2.088741103228784, 0.4082482904638631),
|
||||
float3(-2.4575847530631187, -0.9799373355024756, 0.3779644730092272),
|
||||
float3(0.5874641440200847, -2.7667464429345077, 0.35355339059327373),
|
||||
float3(2.997715703369726, 0.11704939884745152, 0.3333333333333333),
|
||||
float3(0.41360842451688395, 3.1351121305574803, 0.31622776601683794),
|
||||
float3(-3.167149933769243, 0.9844599011770256, 0.30151134457776363),
|
||||
float3(0.5874641440200847, -2.7667464429345077, 0.35355339059327373),
|
||||
float3(2.997715703369726, 0.11704939884745152, 0.3333333333333333),
|
||||
float3(0.41360842451688395, 3.1351121305574803, 0.31622776601683794),
|
||||
float3(-3.167149933769243, 0.9844599011770256, 0.30151134457776363),
|
||||
float3(-1.5736713846521535, -3.0860263079123245, 0.2886751345948129),
|
||||
float3(2.888202648340422, -2.1583061557896213, 0.2773500981126146),
|
||||
float3(2.7150778983300325, 2.5745586041105715, 0.2672612419124244),
|
||||
float3(-2.1504069972377464, 3.2211410627650165, 0.2581988897471611),
|
||||
float3(2.888202648340422, -2.1583061557896213, 0.2773500981126146),
|
||||
float3(2.7150778983300325, 2.5745586041105715, 0.2672612419124244),
|
||||
float3(-2.1504069972377464, 3.2211410627650165, 0.2581988897471611),
|
||||
float3(-3.6548858794907493, -1.6253643308191343, 0.25),
|
||||
float3(1.0130775986052671, -3.9967078676335834, 0.24253562503633297),
|
||||
float3(4.229723673607257, 0.33081361055181563, 0.23570226039551587),
|
||||
float3(0.40107790291173834, 4.340407413572593, 0.22941573387056174),
|
||||
float3(-4.319124570236028, 1.159811599693438, 0.22360679774997896),
|
||||
float3(-1.9209044802827355, -4.160543952132907, 0.2182178902359924),
|
||||
float3(3.8639122286635708, -2.6589814382925123, 0.21320071635561041),
|
||||
float3(3.3486228404946234, 3.4331800232609, 0.20851441405707477),
|
||||
float3(-2.8769733643574344, 3.9652268864187157, 0.20412414523193154)
|
||||
float3(1.0130775986052671, -3.9967078676335834, 0.24253562503633297),
|
||||
float3(4.229723673607257, 0.33081361055181563, 0.23570226039551587),
|
||||
float3(0.40107790291173834, 4.340407413572593, 0.22941573387056174),
|
||||
float3(-4.319124570236028, 1.159811599693438, 0.22360679774997896),
|
||||
float3(-1.9209044802827355, -4.160543952132907, 0.2182178902359924),
|
||||
float3(3.8639122286635708, -2.6589814382925123, 0.21320071635561041),
|
||||
float3(3.3486228404946234, 3.4331800232609, 0.20851441405707477),
|
||||
float3(-2.8769733643574344, 3.9652268864187157, 0.20412414523193154)
|
||||
};
|
||||
|
||||
// minimum luminance for a pixel to contribute bloom
|
||||
|
|
@ -41,15 +41,13 @@ static const float BLOOM_THRESHOLD = 0.2f;
|
|||
// strength of the bloom contribution
|
||||
static const float BLOOM_STRENGTH = 0.2f;
|
||||
|
||||
float lum(float4 c) {
|
||||
float
|
||||
lum(float4 c) {
|
||||
return 0.299f * c.r + 0.587f * c.g + 0.114f * c.b;
|
||||
}
|
||||
|
||||
public float4 fragment_main(
|
||||
float4 color,
|
||||
KittyTextures t,
|
||||
KittyCustomShaderData d
|
||||
) {
|
||||
public float4
|
||||
fragment_main(float4 color, KittyTextures t, KittyCustomShaderData d) {
|
||||
float2 uv = t.pos;
|
||||
|
||||
// One pixel in backbuffer UV space; scale by sqrt(2) to match original step
|
||||
|
|
|
|||
|
|
@ -9,15 +9,12 @@
|
|||
|
||||
import kitty_custom_shader_types;
|
||||
|
||||
static const float WARP = 0.25f; // simulates curvature of CRT monitor
|
||||
static const float SCAN = 0.50f; // simulates darkness between scanlines
|
||||
static const float4 TINT = float4(0, 0.8, 0.6, 0); // tint color set the fourth component to 1 to apply it fully
|
||||
static const float WARP = 0.25f; // simulates curvature of CRT monitor
|
||||
static const float SCAN = 0.50f; // simulates darkness between scanlines
|
||||
static const float4 TINT = float4(0, 0.8, 0.6, 0); // tint color set the fourth component to 1 to apply it fully
|
||||
|
||||
public float4 fragment_main(
|
||||
float4 color,
|
||||
KittyTextures t,
|
||||
KittyCustomShaderData d
|
||||
) {
|
||||
public float4
|
||||
fragment_main(float4 color, KittyTextures t, KittyCustomShaderData d) {
|
||||
// UV within the current viewport (0..1)
|
||||
float2 uv = t.pos;
|
||||
|
||||
|
|
@ -26,8 +23,12 @@ public float4 fragment_main(
|
|||
dc *= dc;
|
||||
|
||||
// Warp UV to simulate CRT screen curvature
|
||||
uv.x -= 0.5f; uv.x *= 1.0f + (dc.y * (0.3f * WARP)); uv.x += 0.5f;
|
||||
uv.y -= 0.5f; uv.y *= 1.0f + (dc.x * (0.4f * WARP)); uv.y += 0.5f;
|
||||
uv.x -= 0.5f;
|
||||
uv.x *= 1.0f + (dc.y * (0.3f * WARP));
|
||||
uv.x += 0.5f;
|
||||
uv.y -= 0.5f;
|
||||
uv.y *= 1.0f + (dc.x * (0.4f * WARP));
|
||||
uv.y += 0.5f;
|
||||
|
||||
// Original Y pixel coordinate within the viewport (for scanline phase)
|
||||
float fragCoordY = (t.pos.y - t.viewport.y) * float(d.viewport_size_pixels.y);
|
||||
|
|
|
|||
|
|
@ -9,49 +9,54 @@
|
|||
|
||||
import kitty_custom_shader_types;
|
||||
|
||||
static const float4 TRAIL_COLOR = float4(1.0, 0.725, 0.161, 1.0);
|
||||
static const float4 TRAIL_COLOR_ACCENT = float4(1.0, 0.0, 0.0, 1.0);
|
||||
static const float4 TRAIL_COLOR = float4(1.0, 0.725, 0.161, 1.0);
|
||||
static const float4 TRAIL_COLOR_ACCENT = float4(1.0, 0.0, 0.0, 1.0);
|
||||
// Trail lifetime in seconds.
|
||||
static const float DURATION = 0.5;
|
||||
static const float DURATION = 0.5;
|
||||
|
||||
// pow(1 - x, 10) via repeated squaring — branchless ease-out.
|
||||
static float ease_out10(float x) {
|
||||
float y = 1.0 - x;
|
||||
static float
|
||||
ease_out10(float x) {
|
||||
float y = 1.0 - x;
|
||||
float y2 = y * y;
|
||||
float y4 = y2 * y2;
|
||||
return y4 * y4 * y2;
|
||||
}
|
||||
|
||||
// Smooth blend curve for the progress value.
|
||||
static float blend_smooth(float t) {
|
||||
static float
|
||||
blend_smooth(float t) {
|
||||
float s = t * t;
|
||||
return s / (2.0 * (s - t) + 1.0);
|
||||
}
|
||||
|
||||
// SDF of an axis-aligned box. p = query point, center = box centre, hext = half-extents.
|
||||
static float sdBox(float2 p, float2 center, float2 hext) {
|
||||
static float
|
||||
sdBox(float2 p, float2 center, float2 hext) {
|
||||
float2 d = abs(p - center) - hext;
|
||||
return length(max(d, float2(0.0))) + min(max(d.x, d.y), 0.0);
|
||||
}
|
||||
|
||||
// Single edge contribution for the quadrilateral SDF (signed winding accumulation).
|
||||
static float seg(float2 p, float2 a, float2 b, inout float s, float d) {
|
||||
float2 e = b - a;
|
||||
float2 w = p - a;
|
||||
static float
|
||||
seg(float2 p, float2 a, float2 b, inout float s, float d) {
|
||||
float2 e = b - a;
|
||||
float2 w = p - a;
|
||||
float2 proj = a + e * clamp(dot(w, e) / dot(e, e), 0.0, 1.0);
|
||||
d = min(d, dot(p - proj, p - proj));
|
||||
|
||||
float c0 = step(0.0, p.y - a.y);
|
||||
float c1 = 1.0 - step(0.0, p.y - b.y);
|
||||
float c2 = 1.0 - step(0.0, e.x * w.y - e.y * w.x);
|
||||
float allCond = c0 * c1 * c2;
|
||||
float allCond = c0 * c1 * c2;
|
||||
float noneCond = (1.0 - c0) * (1.0 - c1) * (1.0 - c2);
|
||||
s *= lerp(1.0, -1.0, step(0.5, allCond + noneCond));
|
||||
return d;
|
||||
}
|
||||
|
||||
// SDF of an arbitrary quadrilateral (uses winding number via four edge contributions).
|
||||
static float sdQuad(float2 p, float2 v0, float2 v1, float2 v2, float2 v3) {
|
||||
static float
|
||||
sdQuad(float2 p, float2 v0, float2 v1, float2 v2, float2 v3) {
|
||||
float s = 1.0;
|
||||
float d = dot(p - v0, p - v0);
|
||||
d = seg(p, v0, v3, s, d);
|
||||
|
|
@ -63,17 +68,15 @@ static float sdQuad(float2 p, float2 v0, float2 v1, float2 v2, float2 v3) {
|
|||
|
||||
// Returns 0 for diagonal movement (up-left / down-right), 1 otherwise.
|
||||
// Selects which corner of the parallelogram aligns with the movement direction.
|
||||
static float movementVertexFactor(float2 a, float2 b) {
|
||||
static float
|
||||
movementVertexFactor(float2 a, float2 b) {
|
||||
float c1 = step(b.x, a.x) * step(a.y, b.y);
|
||||
float c2 = step(a.x, b.x) * step(b.y, a.y);
|
||||
return 1.0 - max(c1, c2);
|
||||
}
|
||||
|
||||
public float4 fragment_main(
|
||||
float4 color,
|
||||
KittyTextures t,
|
||||
KittyCustomShaderData d
|
||||
) {
|
||||
public float4
|
||||
fragment_main(float4 color, KittyTextures t, KittyCustomShaderData d) {
|
||||
if (d.cursor_trail_color.a <= 0.0) return color;
|
||||
|
||||
float age = clamp((d.timestamp - d.cursor_trail_change_time) / DURATION, 0.0, 1.0);
|
||||
|
|
@ -84,39 +87,38 @@ public float4 fragment_main(
|
|||
|
||||
// Work in pixel space for correct aspect-ratio distance measurements.
|
||||
float2 pixelDims = float2(d.viewport_size_pixels) * t.viewport.zw;
|
||||
float2 px = t.pos * pixelDims;
|
||||
float2 px = t.pos * pixelDims;
|
||||
|
||||
// Current cursor rect in pixel space (edge: .x=left .y=right .z=top .w=bottom, y-up).
|
||||
float curLeft = d.cursor_trail_edge.x * pixelDims.x;
|
||||
float curRight = d.cursor_trail_edge.y * pixelDims.x;
|
||||
float curTop = d.cursor_trail_edge.z * pixelDims.y;
|
||||
float curLeft = d.cursor_trail_edge.x * pixelDims.x;
|
||||
float curRight = d.cursor_trail_edge.y * pixelDims.x;
|
||||
float curTop = d.cursor_trail_edge.z * pixelDims.y;
|
||||
float curBottom = d.cursor_trail_edge.w * pixelDims.y;
|
||||
float curWidth = curRight - curLeft;
|
||||
float curHeight = curTop - curBottom;
|
||||
float curWidth = curRight - curLeft;
|
||||
float curHeight = curTop - curBottom;
|
||||
float2 curCenter = float2((curLeft + curRight) * 0.5, (curTop + curBottom) * 0.5);
|
||||
|
||||
float prevLeft = d.cursor_trail_prev_edge.x * pixelDims.x;
|
||||
float prevTop = d.cursor_trail_prev_edge.z * pixelDims.y;
|
||||
float prevLeft = d.cursor_trail_prev_edge.x * pixelDims.x;
|
||||
float prevTop = d.cursor_trail_prev_edge.z * pixelDims.y;
|
||||
float prevBottom = d.cursor_trail_prev_edge.w * pixelDims.y;
|
||||
float2 prevCenter = float2(
|
||||
(d.cursor_trail_prev_edge.x + d.cursor_trail_prev_edge.y) * 0.5 * pixelDims.x,
|
||||
(d.cursor_trail_prev_edge.z + d.cursor_trail_prev_edge.w) * 0.5 * pixelDims.y
|
||||
);
|
||||
(d.cursor_trail_prev_edge.z + d.cursor_trail_prev_edge.w) * 0.5 * pixelDims.y);
|
||||
|
||||
float lineLength = length(curCenter - prevCenter);
|
||||
// Alpha fades to 0 at the previous-cursor end, reaching full effect at the current cursor.
|
||||
float alphaModifier = min(length(px - curCenter) / (lineLength * easedProgress), 1.0);
|
||||
|
||||
// Build parallelogram vertices in pixel space.
|
||||
float vf = movementVertexFactor(curCenter, prevCenter);
|
||||
float vf = movementVertexFactor(curCenter, prevCenter);
|
||||
float ivf = 1.0 - vf;
|
||||
float2 v0 = float2(lerp(curLeft, curRight, vf), curBottom);
|
||||
float2 v0 = float2(lerp(curLeft, curRight, vf), curBottom);
|
||||
float2 v1 = float2(lerp(curLeft, curRight, ivf), curTop);
|
||||
float2 v2 = float2(prevLeft + curWidth * ivf, prevTop);
|
||||
float2 v3 = float2(prevLeft + curWidth * vf, prevBottom);
|
||||
float2 v2 = float2(prevLeft + curWidth * ivf, prevTop);
|
||||
float2 v3 = float2(prevLeft + curWidth * vf, prevBottom);
|
||||
|
||||
float sdfCursor = sdBox(px, curCenter, float2(curWidth, curHeight) * 0.5);
|
||||
float sdfTrail = sdQuad(px, v0, v1, v2, v3);
|
||||
float sdfTrail = sdQuad(px, v0, v1, v2, v3);
|
||||
|
||||
// ~2-pixel anti-aliasing range in pixel space.
|
||||
float aaRange = 2.0;
|
||||
|
|
|
|||
|
|
@ -20,8 +20,12 @@ import kitty_custom_shader_types;
|
|||
|
||||
// Returns true when uv is inside the convex quad c0→c1→c2→c3 (clockwise, y-up).
|
||||
// Corner order from cursor_trail_corners_*: 0=top-right, 1=bottom-right, 2=bottom-left, 3=top-left.
|
||||
bool inside_trail_quad(float2 uv, float2 c0, float2 c1, float2 c2, float2 c3) {
|
||||
float2 e0 = c1 - c0; float2 e1 = c2 - c1; float2 e2 = c3 - c2; float2 e3 = c0 - c3;
|
||||
bool
|
||||
inside_trail_quad(float2 uv, float2 c0, float2 c1, float2 c2, float2 c3) {
|
||||
float2 e0 = c1 - c0;
|
||||
float2 e1 = c2 - c1;
|
||||
float2 e2 = c3 - c2;
|
||||
float2 e3 = c0 - c3;
|
||||
float s0 = e0.x * (uv.y - c0.y) - e0.y * (uv.x - c0.x);
|
||||
float s1 = e1.x * (uv.y - c1.y) - e1.y * (uv.x - c1.x);
|
||||
float s2 = e2.x * (uv.y - c2.y) - e2.y * (uv.x - c2.x);
|
||||
|
|
@ -29,27 +33,24 @@ bool inside_trail_quad(float2 uv, float2 c0, float2 c1, float2 c2, float2 c3) {
|
|||
return s0 <= 0.0 && s1 <= 0.0 && s2 <= 0.0 && s3 <= 0.0;
|
||||
}
|
||||
|
||||
public float4 fragment_main(
|
||||
float4 color,
|
||||
KittyTextures t,
|
||||
KittyCustomShaderData d
|
||||
) {
|
||||
public float4
|
||||
fragment_main(float4 color, KittyTextures t, KittyCustomShaderData d) {
|
||||
float opacity = d.cursor_trail_color.a;
|
||||
if (opacity <= 0.0) return color;
|
||||
|
||||
float2 uv = t.pos;
|
||||
|
||||
float2 c0 = float2(d.cursor_trail_corners_x.x, d.cursor_trail_corners_y.x); // top-right
|
||||
float2 c1 = float2(d.cursor_trail_corners_x.y, d.cursor_trail_corners_y.y); // bottom-right
|
||||
float2 c2 = float2(d.cursor_trail_corners_x.z, d.cursor_trail_corners_y.z); // bottom-left
|
||||
float2 c3 = float2(d.cursor_trail_corners_x.w, d.cursor_trail_corners_y.w); // top-left
|
||||
float2 c0 = float2(d.cursor_trail_corners_x.x, d.cursor_trail_corners_y.x); // top-right
|
||||
float2 c1 = float2(d.cursor_trail_corners_x.y, d.cursor_trail_corners_y.y); // bottom-right
|
||||
float2 c2 = float2(d.cursor_trail_corners_x.z, d.cursor_trail_corners_y.z); // bottom-left
|
||||
float2 c3 = float2(d.cursor_trail_corners_x.w, d.cursor_trail_corners_y.w); // top-left
|
||||
|
||||
if (!inside_trail_quad(uv, c0, c1, c2, c3)) return color;
|
||||
|
||||
// Mask out the cursor's current rectangle so the real cursor renders cleanly on top.
|
||||
// cursor_trail_edge: .x=left, .y=right, .z=top, .w=bottom (UV, y-up)
|
||||
float inside_cursor = step(d.cursor_trail_edge.x, uv.x) * step(uv.x, d.cursor_trail_edge.y)
|
||||
* step(d.cursor_trail_edge.w, uv.y) * step(uv.y, d.cursor_trail_edge.z);
|
||||
float inside_cursor =
|
||||
step(d.cursor_trail_edge.x, uv.x) * step(uv.x, d.cursor_trail_edge.y) * step(d.cursor_trail_edge.w, uv.y) * step(uv.y, d.cursor_trail_edge.z);
|
||||
opacity *= 1.0 - inside_cursor;
|
||||
if (opacity <= 0.0) return color;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,27 +7,29 @@
|
|||
|
||||
import kitty_custom_shader_types;
|
||||
|
||||
static const float3 BOLT_COLOR = float3(1.00, 0.82, 0.72);
|
||||
static const float3 GLOW_COLOR = float3(0.74, 0.00, 0.00);
|
||||
static const float3 BOLT_COLOR = float3(1.00, 0.82, 0.72);
|
||||
static const float3 GLOW_COLOR = float3(0.74, 0.00, 0.00);
|
||||
// Bolt lifetime in seconds.
|
||||
static const float DURATION = 0.14;
|
||||
static const float DURATION = 0.14;
|
||||
// Sideways displacement relative to bolt length.
|
||||
static const float JAGGEDNESS = 0.085;
|
||||
static const float JAGGEDNESS = 0.085;
|
||||
// Core stroke width in pixels.
|
||||
static const float CORE_WIDTH = 1.15;
|
||||
static const float CORE_WIDTH = 1.15;
|
||||
// Glow radius in pixels.
|
||||
static const float GLOW_WIDTH = 5.5;
|
||||
static const float GLOW_WIDTH = 5.5;
|
||||
// Number of linear segments that make up the main bolt.
|
||||
static const int BOLT_SEGMENTS = 12;
|
||||
static const int BOLT_SEGMENTS = 12;
|
||||
|
||||
static float hash11(float p) {
|
||||
static float
|
||||
hash11(float p) {
|
||||
p = frac(p * 0.1031);
|
||||
p *= p + 33.33;
|
||||
p *= p + p;
|
||||
return frac(p);
|
||||
}
|
||||
|
||||
static float segDist(float2 p, float2 a, float2 b) {
|
||||
static float
|
||||
segDist(float2 p, float2 a, float2 b) {
|
||||
float2 ab = b - a;
|
||||
float t = clamp(dot(p - a, ab) / max(dot(ab, ab), 1e-7), 0.0, 1.0);
|
||||
return length(p - (a + ab * t));
|
||||
|
|
@ -35,23 +37,25 @@ static float segDist(float2 p, float2 a, float2 b) {
|
|||
|
||||
// A point on the piecewise-linear bolt. Endpoints stay fixed; interior nodes
|
||||
// are displaced perpendicular to the travel direction.
|
||||
static float2 boltPoint(float2 a, float2 b, float t, float seed) {
|
||||
float2 delta = b - a;
|
||||
float boltLength = length(delta);
|
||||
float2 perp = float2(-delta.y, delta.x) / max(boltLength, 1e-5);
|
||||
float node = floor(t * float(BOLT_SEGMENTS) + 0.5);
|
||||
float rnd = hash11(node * 17.17 + seed) * 2.0 - 1.0;
|
||||
float fade = sin(3.14159265 * t);
|
||||
static float2
|
||||
boltPoint(float2 a, float2 b, float t, float seed) {
|
||||
float2 delta = b - a;
|
||||
float boltLength = length(delta);
|
||||
float2 perp = float2(-delta.y, delta.x) / max(boltLength, 1e-5);
|
||||
float node = floor(t * float(BOLT_SEGMENTS) + 0.5);
|
||||
float rnd = hash11(node * 17.17 + seed) * 2.0 - 1.0;
|
||||
float fade = sin(3.14159265 * t);
|
||||
return lerp(a, b, t) + perp * rnd * boltLength * JAGGEDNESS * fade;
|
||||
}
|
||||
|
||||
// Minimum distance from p to the main bolt's piecewise-linear path.
|
||||
static float mainBoltDist(float2 p, float2 a, float2 b, float seed) {
|
||||
float minD = 1e5;
|
||||
static float
|
||||
mainBoltDist(float2 p, float2 a, float2 b, float seed) {
|
||||
float minD = 1e5;
|
||||
float2 prev = a;
|
||||
[ForceUnroll]
|
||||
for (int i = 1; i <= BOLT_SEGMENTS; i++) {
|
||||
float t = float(i) / float(BOLT_SEGMENTS);
|
||||
float t = float(i) / float(BOLT_SEGMENTS);
|
||||
float2 cur = boltPoint(a, b, t, seed);
|
||||
minD = min(minD, segDist(p, prev, cur));
|
||||
prev = cur;
|
||||
|
|
@ -60,49 +64,41 @@ static float mainBoltDist(float2 p, float2 a, float2 b, float seed) {
|
|||
}
|
||||
|
||||
// Three small forks growing out of alternating points on the main bolt.
|
||||
static float forkDist(float2 p, float2 a, float2 b, float seed) {
|
||||
float minD = 1e5;
|
||||
float2 delta = b - a;
|
||||
float boltLength = length(delta);
|
||||
float2 perp = float2(-delta.y, delta.x) / max(boltLength, 1e-5);
|
||||
float2 dir = normalize(delta);
|
||||
static float
|
||||
forkDist(float2 p, float2 a, float2 b, float seed) {
|
||||
float minD = 1e5;
|
||||
float2 delta = b - a;
|
||||
float boltLength = length(delta);
|
||||
float2 perp = float2(-delta.y, delta.x) / max(boltLength, 1e-5);
|
||||
float2 dir = normalize(delta);
|
||||
|
||||
[ForceUnroll]
|
||||
for (int i = 0; i < 3; i++) {
|
||||
float fi = float(i);
|
||||
float t = 0.28 + fi * 0.22;
|
||||
float2 root = boltPoint(a, b, t, seed);
|
||||
float side = lerp(-1.0, 1.0, step(0.5, hash11(seed + fi * 41.0)));
|
||||
float reach = boltLength * (0.055 + 0.035 * hash11(seed + fi * 53.0));
|
||||
float fi = float(i);
|
||||
float t = 0.28 + fi * 0.22;
|
||||
float2 root = boltPoint(a, b, t, seed);
|
||||
float side = lerp(-1.0, 1.0, step(0.5, hash11(seed + fi * 41.0)));
|
||||
float reach = boltLength * (0.055 + 0.035 * hash11(seed + fi * 53.0));
|
||||
float2 along = dir * reach * (hash11(seed + fi * 67.0) - 0.35);
|
||||
float2 tip = root + perp * side * reach + along;
|
||||
float2 elbow = lerp(root, tip, 0.52)
|
||||
- perp * side * reach * (0.12 + 0.18 * hash11(seed + fi * 79.0));
|
||||
float2 tip = root + perp * side * reach + along;
|
||||
float2 elbow = lerp(root, tip, 0.52) - perp * side * reach * (0.12 + 0.18 * hash11(seed + fi * 79.0));
|
||||
minD = min(minD, segDist(p, root, elbow));
|
||||
minD = min(minD, segDist(p, elbow, tip));
|
||||
}
|
||||
return minD;
|
||||
}
|
||||
|
||||
public float4 fragment_main(
|
||||
float4 color,
|
||||
KittyTextures t,
|
||||
KittyCustomShaderData d
|
||||
) {
|
||||
public float4
|
||||
fragment_main(float4 color, KittyTextures t, KittyCustomShaderData d) {
|
||||
float age = clamp((d.timestamp - d.cursor_trail_change_time) / DURATION, 0.0, 1.0);
|
||||
if (age >= 1.0) return color;
|
||||
|
||||
float2 pixelDims = float2(d.viewport_size_pixels) * t.viewport.zw;
|
||||
|
||||
// Cursor centres in pixel space (edge: .x=left .y=right .z=top .w=bottom, y-up).
|
||||
float2 curCenter = float2(
|
||||
(d.cursor_trail_edge.x + d.cursor_trail_edge.y) * 0.5,
|
||||
(d.cursor_trail_edge.z + d.cursor_trail_edge.w) * 0.5
|
||||
) * pixelDims;
|
||||
float2 prevCenter = float2(
|
||||
(d.cursor_trail_prev_edge.x + d.cursor_trail_prev_edge.y) * 0.5,
|
||||
(d.cursor_trail_prev_edge.z + d.cursor_trail_prev_edge.w) * 0.5
|
||||
) * pixelDims;
|
||||
float2 curCenter = float2((d.cursor_trail_edge.x + d.cursor_trail_edge.y) * 0.5, (d.cursor_trail_edge.z + d.cursor_trail_edge.w) * 0.5) * pixelDims;
|
||||
float2 prevCenter =
|
||||
float2((d.cursor_trail_prev_edge.x + d.cursor_trail_prev_edge.y) * 0.5, (d.cursor_trail_prev_edge.z + d.cursor_trail_prev_edge.w) * 0.5) * pixelDims;
|
||||
|
||||
float cursorWidth = (d.cursor_trail_edge.y - d.cursor_trail_edge.x) * pixelDims.x;
|
||||
|
||||
|
|
@ -114,25 +110,25 @@ public float4 fragment_main(
|
|||
float mainD = mainBoltDist(px, prevCenter, curCenter, seed);
|
||||
float forkD = forkDist(px, prevCenter, curCenter, seed);
|
||||
|
||||
float pixel = max(fwidth(mainD), 0.65);
|
||||
float core = 1.0 - smoothstep(CORE_WIDTH, CORE_WIDTH + pixel, mainD);
|
||||
float pixel = max(fwidth(mainD), 0.65);
|
||||
float core = 1.0 - smoothstep(CORE_WIDTH, CORE_WIDTH + pixel, mainD);
|
||||
float forkCore = 1.0 - smoothstep(CORE_WIDTH * 0.72, CORE_WIDTH * 0.72 + pixel, forkD);
|
||||
float glow = exp(-mainD * mainD / (GLOW_WIDTH * GLOW_WIDTH));
|
||||
float glow = exp(-mainD * mainD / (GLOW_WIDTH * GLOW_WIDTH));
|
||||
float forkGlow = exp(-forkD * forkD / (GLOW_WIDTH * GLOW_WIDTH * 0.55));
|
||||
|
||||
// Flash hard, then rapidly lose the core, leaving only glow.
|
||||
float flash = 1.0 - smoothstep(0.0, 1.0, age);
|
||||
float flash = 1.0 - smoothstep(0.0, 1.0, age);
|
||||
flash *= flash;
|
||||
float flicker = 0.82 + 0.18 * sin(age * 95.0 + seed);
|
||||
float glowAmt = max(glow, forkGlow * 0.55) * flash * flicker * 0.72;
|
||||
float coreAmt = max(core, forkCore * 0.82) * flash * flicker;
|
||||
float flicker = 0.82 + 0.18 * sin(age * 95.0 + seed);
|
||||
float glowAmt = max(glow, forkGlow * 0.55) * flash * flicker * 0.72;
|
||||
float coreAmt = max(core, forkCore * 0.82) * flash * flicker;
|
||||
|
||||
float3 rgb = lerp(color.rgb, GLOW_COLOR, clamp(glowAmt, 0.0, 1.0));
|
||||
rgb = lerp(rgb, BOLT_COLOR, clamp(coreAmt, 0.0, 1.0));
|
||||
rgb = lerp(rgb, BOLT_COLOR, clamp(coreAmt, 0.0, 1.0));
|
||||
|
||||
// Keep the cursor crisp above the effect.
|
||||
float insideCursor = step(d.cursor_trail_edge.x, t.pos.x) * step(t.pos.x, d.cursor_trail_edge.y)
|
||||
* step(d.cursor_trail_edge.w, t.pos.y) * step(t.pos.y, d.cursor_trail_edge.z);
|
||||
float insideCursor = step(d.cursor_trail_edge.x, t.pos.x) * step(t.pos.x, d.cursor_trail_edge.y) * step(d.cursor_trail_edge.w, t.pos.y) *
|
||||
step(t.pos.y, d.cursor_trail_edge.z);
|
||||
rgb = lerp(rgb, color.rgb, insideCursor);
|
||||
|
||||
return float4(rgb, color.a);
|
||||
|
|
|
|||
|
|
@ -7,32 +7,36 @@
|
|||
|
||||
import kitty_custom_shader_types;
|
||||
|
||||
static const int NUM_PARTICLES = 128;
|
||||
static const int NUM_PARTICLES = 128;
|
||||
static const float BLACK_BLEND_THRESHOLD = 0.4f;
|
||||
static const float CYCLE_TIME = 6.0f;
|
||||
static const float PARTICLE_PHASE = 2.0f;
|
||||
static const float CYCLE_TIME = 6.0f;
|
||||
static const float PARTICLE_PHASE = 2.0f;
|
||||
|
||||
// Pseudo-random in [-1, 1]
|
||||
float rand_val(float val, float seed) {
|
||||
float
|
||||
rand_val(float val, float seed) {
|
||||
return cos(val * sin(val * seed) * seed);
|
||||
}
|
||||
|
||||
float distance2(float2 a, float2 b) {
|
||||
float
|
||||
distance2(float2 a, float2 b) {
|
||||
float2 d = a - b;
|
||||
return dot(d, d);
|
||||
}
|
||||
|
||||
// Diagonal red-and-white barber-pole pattern — branchless
|
||||
float3 barberpole(float2 pos, float2 rocketpos) {
|
||||
float3
|
||||
barberpole(float2 pos, float2 rocketpos) {
|
||||
float d = fmod(((pos.x - rocketpos.x) + (pos.y - rocketpos.y)) * 20.0f, 2.0f);
|
||||
return lerp(float3(1.0f), float3(1.0f, 0.0f, 0.0f), step(1.0f, d));
|
||||
}
|
||||
|
||||
// Draw a single rocket at rocketpos in the supplied coordinate space — branchless
|
||||
float3 rocket(float2 pos, float2 rocketpos) {
|
||||
float3 col = float3(0.0f);
|
||||
float absx = abs(rocketpos.x - pos.x);
|
||||
float absy = abs(rocketpos.y - pos.y);
|
||||
float3
|
||||
rocket(float2 pos, float2 rocketpos) {
|
||||
float3 col = float3(0.0f);
|
||||
float absx = abs(rocketpos.x - pos.x);
|
||||
float absy = abs(rocketpos.y - pos.y);
|
||||
|
||||
// Wooden stick
|
||||
float stick = step(absx, 0.01f) * step(absy, 0.22f);
|
||||
|
|
@ -43,9 +47,9 @@ float3 rocket(float2 pos, float2 rocketpos) {
|
|||
col = lerp(col, barberpole(pos, rocketpos), pole);
|
||||
|
||||
// Pointed nose cone
|
||||
float pointw = (rocketpos.y - pos.y - 0.25f) * -0.7f;
|
||||
float pointw = (rocketpos.y - pos.y - 0.25f) * -0.7f;
|
||||
float has_point = step(0.1f, rocketpos.y - pos.y);
|
||||
float f_point = smoothstep(pointw - 0.001f, pointw + 0.001f, absx);
|
||||
float f_point = smoothstep(pointw - 0.001f, pointw + 0.001f, absx);
|
||||
col = lerp(col, lerp(float3(1.0f, 0.0f, 0.0f), col, f_point), has_point);
|
||||
|
||||
// Ambient shadow gradient
|
||||
|
|
@ -59,36 +63,35 @@ float3 rocket(float2 pos, float2 rocketpos) {
|
|||
// Particle direction for iteration i is the unit vector at angle i radians,
|
||||
// precomputed as (cos(i), sin(i)) — equivalent to iteratively applying the
|
||||
// original 1-radian rotation matrix but eliminates inter-iteration data dependency.
|
||||
float3 drawParticles(float2 pos, float3 particolor, float time,
|
||||
float2 cpos, float gravity, float seed, float timelength) {
|
||||
float3
|
||||
drawParticles(float2 pos, float3 particolor, float time, float2 cpos, float gravity, float seed, float timelength) {
|
||||
float3 col = float3(0.0f);
|
||||
|
||||
[ForceUnroll]
|
||||
for (int i = 0; i < NUM_PARTICLES; i++) {
|
||||
float fi = float(i + 1); // 1-indexed to match original
|
||||
float d = rand_val(fi, seed);
|
||||
float fade = (fi / float(NUM_PARTICLES)) * time;
|
||||
float2 pp = float2(cos(float(i)), sin(float(i))); // unit direction at angle i
|
||||
float fi = float(i + 1); // 1-indexed to match original
|
||||
float d = rand_val(fi, seed);
|
||||
float fade = (fi / float(NUM_PARTICLES)) * time;
|
||||
float2 pp = float2(cos(float(i)), sin(float(i))); // unit direction at angle i
|
||||
float2 particpos = cpos + time * pp * d;
|
||||
col = lerp(particolor / fade, col,
|
||||
smoothstep(0.0f, 0.0001f, distance2(particpos, pos)));
|
||||
col = lerp(particolor / fade, col, smoothstep(0.0f, 0.0001f, distance2(particpos, pos)));
|
||||
}
|
||||
col *= smoothstep(0.0f, 1.0f, (timelength - time) / timelength);
|
||||
return col;
|
||||
}
|
||||
|
||||
// Returns rocket or particles depending on which phase of the cycle we are in
|
||||
float3 drawFireworks(float time, float2 uv, float3 particolor, float seed) {
|
||||
float3
|
||||
drawFireworks(float time, float2 uv, float3 particolor, float seed) {
|
||||
float3 col = float3(0.0f);
|
||||
if (time <= 0.0f) return col;
|
||||
|
||||
float tmod = fmod(time, CYCLE_TIME);
|
||||
float tmod = fmod(time, CYCLE_TIME);
|
||||
float cycle_id = ceil(time / CYCLE_TIME);
|
||||
|
||||
if (tmod > PARTICLE_PHASE) {
|
||||
float2 cpos = float2(rand_val(cycle_id, seed), -0.5f);
|
||||
col = drawParticles(uv, particolor, tmod - PARTICLE_PHASE,
|
||||
cpos, 0.5f, cycle_id, seed);
|
||||
col = drawParticles(uv, particolor, tmod - PARTICLE_PHASE, cpos, 0.5f, cycle_id, seed);
|
||||
} else {
|
||||
float rx = 3.0f * rand_val(cycle_id, seed);
|
||||
float ry = 3.0f * (-0.5f + (PARTICLE_PHASE - tmod));
|
||||
|
|
@ -97,30 +100,27 @@ float3 drawFireworks(float time, float2 uv, float3 particolor, float seed) {
|
|||
return col;
|
||||
}
|
||||
|
||||
public float4 fragment_main(
|
||||
float4 color,
|
||||
KittyTextures t,
|
||||
KittyCustomShaderData d
|
||||
) {
|
||||
public float4
|
||||
fragment_main(float4 color, KittyTextures t, KittyCustomShaderData d) {
|
||||
float2 pixelDims = float2(d.viewport_size_pixels) * t.viewport.zw;
|
||||
float aspect = pixelDims.x / pixelDims.y;
|
||||
float aspect = pixelDims.x / pixelDims.y;
|
||||
|
||||
// Map to [-aspect, aspect] × [-1, 1] with y=1 at top (matching the original)
|
||||
float2 uv = 1.0f - 2.0f * t.pos;
|
||||
uv.x *= aspect;
|
||||
uv.y = -uv.y;
|
||||
uv.x *= aspect;
|
||||
uv.y = -uv.y;
|
||||
|
||||
float3 col = float3(0.1f, 0.1f, 0.2f);
|
||||
col += 0.1f * uv.y; // subtle sky gradient
|
||||
col += 0.1f * uv.y; // subtle sky gradient
|
||||
|
||||
float time = d.timestamp;
|
||||
col += drawFireworks(time, uv, float3(1.0f, 0.1f, 0.1f), 1.0f);
|
||||
col += drawFireworks(time, uv, float3(1.0f, 0.1f, 0.1f), 1.0f);
|
||||
col += drawFireworks(time - 2.0f, uv, float3(0.0f, 1.0f, 0.5f), 2.0f);
|
||||
col += drawFireworks(time - 4.0f, uv, float3(1.0f, 1.0f, 0.1f), 3.0f);
|
||||
|
||||
float4 terminalColor = t.backbuffer.Sample(t.pos);
|
||||
float alpha = step(length(terminalColor.rgb), BLACK_BLEND_THRESHOLD);
|
||||
float3 blended = lerp(terminalColor.rgb, col * 0.3f, alpha);
|
||||
float alpha = step(length(terminalColor.rgb), BLACK_BLEND_THRESHOLD);
|
||||
float3 blended = lerp(terminalColor.rgb, col * 0.3f, alpha);
|
||||
|
||||
return float4(blended, terminalColor.a);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,87 +8,82 @@
|
|||
|
||||
import kitty_custom_shader_types;
|
||||
|
||||
static const int NUM_EXPLOSIONS = 3;
|
||||
static const int NUM_PARTICLES = 42;
|
||||
static const int NUM_EXPLOSIONS = 3;
|
||||
static const int NUM_PARTICLES = 42;
|
||||
static const float BLACK_BLEND_THRESHOLD = 0.4f;
|
||||
static const float TIME_SCALE = 0.5f;
|
||||
static const float PI = 3.14159265359f;
|
||||
static const float TIME_SCALE = 0.5f;
|
||||
static const float PI = 3.14159265359f;
|
||||
|
||||
// Noise constant from Dave Hoskins — not user-tunable so kept as plain static const
|
||||
static const float3 MOD3 = float3(0.1031f, 0.11369f, 0.13787f);
|
||||
|
||||
float3 hash31(float p) {
|
||||
float3
|
||||
hash31(float p) {
|
||||
float3 p3 = frac(float3(p) * MOD3);
|
||||
p3 += dot(p3, p3.yzx + 19.19f);
|
||||
return frac(float3((p3.x + p3.y) * p3.z,
|
||||
(p3.x + p3.z) * p3.y,
|
||||
(p3.y + p3.z) * p3.x));
|
||||
return frac(float3((p3.x + p3.y) * p3.z, (p3.x + p3.z) * p3.y, (p3.y + p3.z) * p3.x));
|
||||
}
|
||||
|
||||
float hash12(float2 p) {
|
||||
float
|
||||
hash12(float2 p) {
|
||||
float3 p3 = frac(float3(p.xyx) * MOD3);
|
||||
p3 += dot(p3, p3.yzx + 19.19f);
|
||||
return frac((p3.x + p3.y) * p3.z);
|
||||
}
|
||||
|
||||
float light(float2 uv, float2 pos, float size) {
|
||||
uv -= pos;
|
||||
float
|
||||
light(float2 uv, float2 pos, float size) {
|
||||
uv -= pos;
|
||||
size *= size;
|
||||
return size / dot(uv, uv);
|
||||
}
|
||||
|
||||
float3 explosion(float2 uv, float2 p, float seed, float t) {
|
||||
float3 col = float3(0.0f);
|
||||
float3 en = hash31(seed);
|
||||
float3
|
||||
explosion(float2 uv, float2 p, float seed, float t) {
|
||||
float3 col = float3(0.0f);
|
||||
float3 en = hash31(seed);
|
||||
float3 baseCol = en;
|
||||
|
||||
// startP, pt, and b are loop-invariant; computed once outside
|
||||
float2 startP = p - float2(0.0f, t * t * 0.1f);
|
||||
float pt = 1.0f - pow(t - 1.0f, 2.0f);
|
||||
float pt = 1.0f - pow(t - 1.0f, 2.0f);
|
||||
// B(en.x, en.y, en.z, t) macro expansion
|
||||
float b = smoothstep(en.x - en.z, en.x + en.z, t)
|
||||
* smoothstep(en.y + en.z, en.y - en.z, t);
|
||||
float sizeBase = lerp(0.01f, 0.005f, smoothstep(0.0f, 0.1f, pt))
|
||||
* smoothstep(1.0f, 0.1f, pt);
|
||||
float b = smoothstep(en.x - en.z, en.x + en.z, t) * smoothstep(en.y + en.z, en.y - en.z, t);
|
||||
float sizeBase = lerp(0.01f, 0.005f, smoothstep(0.0f, 0.1f, pt)) * smoothstep(1.0f, 0.1f, pt);
|
||||
|
||||
[ForceUnroll]
|
||||
for (int i = 0; i < NUM_PARTICLES; i++) {
|
||||
float3 n = hash31(float(i)) - 0.5f;
|
||||
float3 n = hash31(float(i)) - 0.5f;
|
||||
float2 endP = startP + normalize(n.xy) * n.z - float2(0.0f, t * 0.2f);
|
||||
float2 pos = lerp(p, endP, pt);
|
||||
float2 pos = lerp(p, endP, pt);
|
||||
|
||||
float sparkle = sin((pt + n.z) * 21.0f) * 0.5f + 0.5f;
|
||||
sparkle = pow(sparkle, pow(en.x, 3.0f) * 50.0f)
|
||||
* lerp(0.01f, 0.01f, en.y * n.y);
|
||||
sparkle = pow(sparkle, pow(en.x, 3.0f) * 50.0f) * lerp(0.01f, 0.01f, en.y * n.y);
|
||||
|
||||
col += baseCol * light(uv, pos, sizeBase + sparkle * b);
|
||||
}
|
||||
return col;
|
||||
}
|
||||
|
||||
float3 rainbow(float3 c, float time) {
|
||||
float3
|
||||
rainbow(float3 c, float time) {
|
||||
float avg = (c.r + c.g + c.b) / 3.0f;
|
||||
c = avg + (c - avg) * sin(float3(0.0f, 0.333f, 0.666f) + time);
|
||||
c += sin(float3(0.4f, 0.3f, 0.3f) * time
|
||||
+ float3(1.1244f, 3.43215f, 6.435f))
|
||||
* float3(0.4f, 0.1f, 0.5f);
|
||||
c = avg + (c - avg) * sin(float3(0.0f, 0.333f, 0.666f) + time);
|
||||
c += sin(float3(0.4f, 0.3f, 0.3f) * time + float3(1.1244f, 3.43215f, 6.435f)) * float3(0.4f, 0.1f, 0.5f);
|
||||
return c;
|
||||
}
|
||||
|
||||
public float4 fragment_main(
|
||||
float4 color,
|
||||
KittyTextures t,
|
||||
KittyCustomShaderData d
|
||||
) {
|
||||
public float4
|
||||
fragment_main(float4 color, KittyTextures t, KittyCustomShaderData d) {
|
||||
float2 pixelDims = float2(d.viewport_size_pixels) * t.viewport.zw;
|
||||
float aspect = pixelDims.x / pixelDims.y;
|
||||
float time = fmod(d.timestamp, 3600.0f) * TIME_SCALE;
|
||||
float aspect = pixelDims.x / pixelDims.y;
|
||||
float time = fmod(d.timestamp, 3600.0f) * TIME_SCALE;
|
||||
|
||||
// Aspect-corrected UV with y=0 at top so gravity points downward
|
||||
float2 uv = t.pos;
|
||||
uv.x -= 0.5f;
|
||||
uv.x *= aspect;
|
||||
uv.y = -uv.y + 1.0f;
|
||||
uv.y = -uv.y + 1.0f;
|
||||
|
||||
float3 c = float3(0.0f);
|
||||
|
||||
|
|
@ -96,7 +91,7 @@ public float4 fragment_main(
|
|||
for (int i = 0; i < NUM_EXPLOSIONS; i++) {
|
||||
float et = time + float(i) * 1234.45235f;
|
||||
float id = floor(et);
|
||||
et -= id;
|
||||
et -= id;
|
||||
|
||||
float2 p = hash31(id).xy;
|
||||
p.x -= 0.5f;
|
||||
|
|
@ -106,8 +101,8 @@ public float4 fragment_main(
|
|||
c = rainbow(c, d.timestamp);
|
||||
|
||||
float4 terminalColor = t.backbuffer.Sample(t.pos);
|
||||
float alpha = step(length(terminalColor.rgb), BLACK_BLEND_THRESHOLD);
|
||||
float3 blended = lerp(terminalColor.rgb, c * 0.3f, alpha);
|
||||
float alpha = step(length(terminalColor.rgb), BLACK_BLEND_THRESHOLD);
|
||||
float3 blended = lerp(terminalColor.rgb, c * 0.3f, alpha);
|
||||
|
||||
return float4(blended, terminalColor.a);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,16 +19,13 @@ static const float BORDER_GLOW = 0.55;
|
|||
// Dim factor applied to pixels outside the active window (1.0 = unchanged, 0.0 = black).
|
||||
static const float INACTIVE_DIM = 0.3;
|
||||
|
||||
public float4 fragment_main(
|
||||
float4 color,
|
||||
KittyTextures t,
|
||||
KittyCustomShaderData d
|
||||
) {
|
||||
public float4
|
||||
fragment_main(float4 color, KittyTextures t, KittyCustomShaderData d) {
|
||||
float4 g = d.active_window_geometry;
|
||||
// Pass through unchanged if no active window geometry is known.
|
||||
if (g.z <= 0.0 || g.w <= 0.0) return color;
|
||||
|
||||
float2 uv = t.pos;
|
||||
float2 uv = t.pos;
|
||||
float2 winMin = g.xy;
|
||||
float2 winMax = g.xy + g.zw;
|
||||
|
||||
|
|
@ -39,8 +36,8 @@ public float4 fragment_main(
|
|||
|
||||
if (inWindow) {
|
||||
// Minimum distance from this pixel to any edge of the active window.
|
||||
float2 edgeDists = min(uv - winMin, winMax - uv);
|
||||
float nearestEdge = min(edgeDists.x, edgeDists.y);
|
||||
float2 edgeDists = min(uv - winMin, winMax - uv);
|
||||
float nearestEdge = min(edgeDists.x, edgeDists.y);
|
||||
|
||||
// Additive border glow: strongest at the edge, falls off over BORDER_WIDTH.
|
||||
float borderGlow = smoothstep(BORDER_WIDTH, 0.0, nearestEdge) * BORDER_GLOW;
|
||||
|
|
|
|||
|
|
@ -8,65 +8,68 @@
|
|||
|
||||
import kitty_custom_shader_types;
|
||||
|
||||
static const int ITERATIONS = 40;
|
||||
static const float SPEED = 0.5f;
|
||||
static const float STRIP_CHARS_MIN = 7.0f;
|
||||
static const float STRIP_CHARS_MAX = 40.0f;
|
||||
static const int ITERATIONS = 40;
|
||||
static const float SPEED = 0.5f;
|
||||
static const float STRIP_CHARS_MIN = 7.0f;
|
||||
static const float STRIP_CHARS_MAX = 40.0f;
|
||||
static const float STRIP_CHAR_HEIGHT = 0.15f;
|
||||
static const float STRIP_CHAR_WIDTH = 0.10f;
|
||||
static const float ZCELL_SIZE = STRIP_CHAR_HEIGHT * STRIP_CHARS_MAX;
|
||||
static const float XYCELL_SIZE = 12.0f * STRIP_CHAR_WIDTH;
|
||||
static const int BLOCK_SIZE = 10;
|
||||
static const int BLOCK_GAP = 2;
|
||||
static const float WALK_SPEED = 0.5f * XYCELL_SIZE;
|
||||
static const float STRIP_CHAR_WIDTH = 0.10f;
|
||||
static const float ZCELL_SIZE = STRIP_CHAR_HEIGHT * STRIP_CHARS_MAX;
|
||||
static const float XYCELL_SIZE = 12.0f * STRIP_CHAR_WIDTH;
|
||||
static const int BLOCK_SIZE = 10;
|
||||
static const int BLOCK_GAP = 2;
|
||||
static const float WALK_SPEED = 0.5f * XYCELL_SIZE;
|
||||
static const float BLOCKS_BEFORE_TURN = 3.0f;
|
||||
static const float PI = 3.14159265359f;
|
||||
static const float PI = 3.14159265359f;
|
||||
|
||||
// ---- random ----
|
||||
|
||||
float hash(float v) {
|
||||
float
|
||||
hash(float v) {
|
||||
return frac(sin(v) * 43758.5453123f);
|
||||
}
|
||||
|
||||
float hash(float2 v) {
|
||||
float
|
||||
hash(float2 v) {
|
||||
return hash(dot(v, float2(5.3983f, 5.4427f)));
|
||||
}
|
||||
|
||||
float2 hash2(float2 v) {
|
||||
float2
|
||||
hash2(float2 v) {
|
||||
// GLSL: v * mat2(127.1, 311.7, 269.5, 183.3) [column-major]
|
||||
// Slang float2x2 is row-major; transpose the GLSL column-major layout.
|
||||
v = mul(v, float2x2(127.1f, 269.5f,
|
||||
311.7f, 183.3f));
|
||||
v = mul(v, float2x2(127.1f, 269.5f, 311.7f, 183.3f));
|
||||
return frac(sin(v) * 43758.5453123f);
|
||||
}
|
||||
|
||||
float4 hash4(float2 v) {
|
||||
float4
|
||||
hash4(float2 v) {
|
||||
// GLSL: v * mat4x2(127.1,311.7, 269.5,183.3, 113.5,271.9, 246.1,124.6)
|
||||
// mat4x2 = 4 cols × 2 rows; transpose into float2x4 (2 rows × 4 cols).
|
||||
float4 p = mul(v, float2x4(127.1f, 269.5f, 113.5f, 246.1f,
|
||||
311.7f, 183.3f, 271.9f, 124.6f));
|
||||
float4 p = mul(v, float2x4(127.1f, 269.5f, 113.5f, 246.1f, 311.7f, 183.3f, 271.9f, 124.6f));
|
||||
return frac(sin(p) * 43758.5453123f);
|
||||
}
|
||||
|
||||
float4 hash4(float3 v) {
|
||||
float4
|
||||
hash4(float3 v) {
|
||||
// GLSL: v * mat4x3(127.1,311.7,74.7, 269.5,183.3,246.1, 113.5,271.9,124.6, 271.9,269.5,311.7)
|
||||
// mat4x3 = 4 cols × 3 rows; transpose into float3x4 (3 rows × 4 cols).
|
||||
float4 p = mul(v, float3x4(127.1f, 269.5f, 113.5f, 271.9f,
|
||||
311.7f, 183.3f, 271.9f, 269.5f,
|
||||
74.7f, 246.1f, 124.6f, 311.7f));
|
||||
float4 p = mul(v, float3x4(127.1f, 269.5f, 113.5f, 271.9f, 311.7f, 183.3f, 271.9f, 269.5f, 74.7f, 246.1f, 124.6f, 311.7f));
|
||||
return frac(sin(p) * 43758.5453123f);
|
||||
}
|
||||
|
||||
// ---- symbols ----
|
||||
|
||||
float rune_line(float2 p, float2 a, float2 b) {
|
||||
float
|
||||
rune_line(float2 p, float2 a, float2 b) {
|
||||
p -= a;
|
||||
b -= a;
|
||||
float h = clamp(dot(p, b) / dot(b, b), 0.0f, 1.0f);
|
||||
return length(p - b * h);
|
||||
}
|
||||
|
||||
float rune(float2 U, float2 seed, float highlight) {
|
||||
float
|
||||
rune(float2 U, float2 seed, float highlight) {
|
||||
float d = 1e5f;
|
||||
[ForceUnroll]
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
|
@ -75,29 +78,29 @@ float rune(float2 U, float2 seed, float highlight) {
|
|||
|
||||
// each rune touches the edge of its box on all 4 sides
|
||||
// with [ForceUnroll] these become compile-time constant selects
|
||||
pos.y = (i == 0) ? 0.0f : pos.y;
|
||||
pos.y = (i == 0) ? 0.0f : pos.y;
|
||||
pos.x = (i == 1) ? 0.999f : pos.x;
|
||||
pos.x = (i == 2) ? 0.0f : pos.x;
|
||||
pos.x = (i == 2) ? 0.0f : pos.x;
|
||||
pos.y = (i == 3) ? 0.999f : pos.y;
|
||||
|
||||
float4 snaps = float4(2.0f, 3.0f, 2.0f, 3.0f);
|
||||
pos = (floor(pos * snaps) + 0.5f) / snaps;
|
||||
|
||||
if (any(pos.xy != pos.zw))
|
||||
d = min(d, rune_line(U, pos.xy, pos.zw + 0.001f));
|
||||
if (any(pos.xy != pos.zw)) d = min(d, rune_line(U, pos.xy, pos.zw + 0.001f));
|
||||
}
|
||||
return smoothstep(0.1f, 0.0f, d) + highlight * smoothstep(0.4f, 0.0f, d);
|
||||
}
|
||||
|
||||
float random_char(float2 outer, float2 inner, float highlight) {
|
||||
float2 seed = float2(dot(outer, float2(269.5f, 183.3f)),
|
||||
dot(outer, float2(113.5f, 271.9f)));
|
||||
float
|
||||
random_char(float2 outer, float2 inner, float highlight) {
|
||||
float2 seed = float2(dot(outer, float2(269.5f, 183.3f)), dot(outer, float2(113.5f, 271.9f)));
|
||||
return rune(inner, seed, highlight);
|
||||
}
|
||||
|
||||
// ---- digital rain ----
|
||||
|
||||
float3 rain(float3 ro3, float3 rd3, float time) {
|
||||
float3
|
||||
rain(float3 ro3, float3 rd3, float time) {
|
||||
float4 result = float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
float2 ro2 = ro3.xy;
|
||||
|
|
@ -106,7 +109,7 @@ float3 rain(float3 ro3, float3 rd3, float time) {
|
|||
bool prefer_dx = abs(rd2.x) > abs(rd2.y);
|
||||
float t3_to_t2 = prefer_dx ? rd3.x / rd2.x : rd3.y / rd2.y;
|
||||
|
||||
int3 cell_side = int3(step(0.0f, rd3));
|
||||
int3 cell_side = int3(step(0.0f, rd3));
|
||||
int3 cell_shift = int3(sign(rd3));
|
||||
|
||||
float t2 = 0.0f;
|
||||
|
|
@ -114,48 +117,44 @@ float3 rain(float3 ro3, float3 rd3, float time) {
|
|||
|
||||
[ForceUnroll]
|
||||
for (int iter = 0; iter < ITERATIONS; iter++) {
|
||||
int2 cell = next_cell;
|
||||
float t2s = t2;
|
||||
int2 cell = next_cell;
|
||||
float t2s = t2;
|
||||
|
||||
float2 side = float2(next_cell + cell_side.xy) * XYCELL_SIZE;
|
||||
float2 side = float2(next_cell + cell_side.xy) * XYCELL_SIZE;
|
||||
float2 t2_side = (side - ro2) / rd2;
|
||||
|
||||
// branchless cell-side selection
|
||||
bool pick_x = t2_side.x < t2_side.y;
|
||||
t2 = pick_x ? t2_side.x : t2_side.y;
|
||||
bool pick_x = t2_side.x < t2_side.y;
|
||||
t2 = pick_x ? t2_side.x : t2_side.y;
|
||||
next_cell.x += pick_x ? cell_shift.x : 0;
|
||||
next_cell.y += pick_x ? 0 : cell_shift.y;
|
||||
|
||||
// skip gap cells
|
||||
float2 cell_in_block = frac(float2(cell) / float(BLOCK_SIZE));
|
||||
float gap = float(BLOCK_GAP) / float(BLOCK_SIZE);
|
||||
if (cell_in_block.x < gap || cell_in_block.y < gap ||
|
||||
(cell_in_block.x < (gap + 0.1f) && cell_in_block.y < (gap + 0.1f)))
|
||||
continue;
|
||||
float gap = float(BLOCK_GAP) / float(BLOCK_SIZE);
|
||||
if (cell_in_block.x < gap || cell_in_block.y < gap || (cell_in_block.x < (gap + 0.1f) && cell_in_block.y < (gap + 0.1f))) continue;
|
||||
|
||||
float t3s = t2s / t3_to_t2;
|
||||
float pos_z = ro3.z + rd3.z * t3s;
|
||||
float xh = hash(float2(cell));
|
||||
float t3s = t2s / t3_to_t2;
|
||||
float pos_z = ro3.z + rd3.z * t3s;
|
||||
float xh = hash(float2(cell));
|
||||
float z_shift = xh * 11.0f - time * (0.5f + xh + xh * xh + pow(xh, 16.0f) * 3.0f);
|
||||
float czs = floor(z_shift / STRIP_CHAR_HEIGHT);
|
||||
z_shift = czs * STRIP_CHAR_HEIGHT;
|
||||
int zcell = int(floor((pos_z - z_shift) / ZCELL_SIZE));
|
||||
float czs = floor(z_shift / STRIP_CHAR_HEIGHT);
|
||||
z_shift = czs * STRIP_CHAR_HEIGHT;
|
||||
int zcell = int(floor((pos_z - z_shift) / ZCELL_SIZE));
|
||||
|
||||
[ForceUnroll]
|
||||
for (int j = 0; j < 2; j++) {
|
||||
float4 ch = hash4(float3(int3(cell, zcell)));
|
||||
float4 ch = hash4(float3(int3(cell, zcell)));
|
||||
float4 ch2 = frac(ch * float4(127.1f, 311.7f, 271.9f, 124.6f));
|
||||
|
||||
float chars_count = ch.w * (STRIP_CHARS_MAX - STRIP_CHARS_MIN) + STRIP_CHARS_MIN;
|
||||
float chars_count = ch.w * (STRIP_CHARS_MAX - STRIP_CHARS_MIN) + STRIP_CHARS_MIN;
|
||||
float target_length = chars_count * STRIP_CHAR_HEIGHT;
|
||||
float target_rad = STRIP_CHAR_WIDTH * 0.5f;
|
||||
float target_z = float(zcell) * ZCELL_SIZE + z_shift
|
||||
+ ch.z * (ZCELL_SIZE - target_length);
|
||||
float2 target = float2(cell) * XYCELL_SIZE + target_rad
|
||||
+ ch.xy * (XYCELL_SIZE - target_rad * 2.0f);
|
||||
float target_rad = STRIP_CHAR_WIDTH * 0.5f;
|
||||
float target_z = float(zcell) * ZCELL_SIZE + z_shift + ch.z * (ZCELL_SIZE - target_length);
|
||||
float2 target = float2(cell) * XYCELL_SIZE + target_rad + ch.xy * (XYCELL_SIZE - target_rad * 2.0f);
|
||||
|
||||
float2 sv = target - ro2;
|
||||
float tmin = dot(sv, rd2);
|
||||
float2 sv = target - ro2;
|
||||
float tmin = dot(sv, rd2);
|
||||
if (tmin >= t2s && tmin <= t2) {
|
||||
float u = sv.x * rd2.y - sv.y * rd2.x;
|
||||
if (abs(u) < target_rad) {
|
||||
|
|
@ -163,28 +162,20 @@ float3 rain(float3 ro3, float3 rd3, float time) {
|
|||
float z = ro3.z + rd3.z * tmin / t3_to_t2;
|
||||
float v = (z - target_z) / target_length;
|
||||
if (v >= 0.0f && v < 1.0f) {
|
||||
float c = floor(v * chars_count);
|
||||
float q = frac(v * chars_count);
|
||||
float c = floor(v * chars_count);
|
||||
float q = frac(v * chars_count);
|
||||
float2 char_hash = hash2(float2(c + czs, ch2.x));
|
||||
if (char_hash.x >= 0.1f || c == 0.0f) {
|
||||
float time_factor = floor(
|
||||
c == 0.0f ? time
|
||||
: time * (ch2.z + ch2.w * ch2.w * 4.0f
|
||||
* pow(char_hash.y, 4.0f)));
|
||||
float a = random_char(float2(char_hash.x, time_factor),
|
||||
float2(u, q),
|
||||
max(1.0f, 3.0f - c * 0.5f) * 0.2f);
|
||||
float time_factor = floor(c == 0.0f ? time : time * (ch2.z + ch2.w * ch2.w * 4.0f * pow(char_hash.y, 4.0f)));
|
||||
float a = random_char(float2(char_hash.x, time_factor), float2(u, q), max(1.0f, 3.0f - c * 0.5f) * 0.2f);
|
||||
a *= clamp((chars_count - 0.5f - c) * 0.5f, 0.0f, 1.0f);
|
||||
if (a > 0.0f) {
|
||||
float attenuation = 1.0f + pow(0.06f * tmin / t3_to_t2, 2.0f);
|
||||
float3 col = (c == 0.0f
|
||||
? float3(0.67f, 1.0f, 0.82f)
|
||||
: float3(0.25f, 0.80f, 0.40f)) / attenuation;
|
||||
float a1 = result.a;
|
||||
result.a = a1 + (1.0f - a1) * a;
|
||||
float3 col = (c == 0.0f ? float3(0.67f, 1.0f, 0.82f) : float3(0.25f, 0.80f, 0.40f)) / attenuation;
|
||||
float a1 = result.a;
|
||||
result.a = a1 + (1.0f - a1) * a;
|
||||
result.xyz = (result.xyz * a1 + col * (1.0f - a1) * a) / result.a;
|
||||
if (result.a > 0.98f)
|
||||
return result.xyz;
|
||||
if (result.a > 0.98f) return result.xyz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -200,54 +191,52 @@ float3 rain(float3 ro3, float3 rd3, float time) {
|
|||
// For M*v in GLSL with column-major constructor, Slang needs the same values
|
||||
// re-read as row-major (i.e. transposed GLSL column-major == correct Slang row-major).
|
||||
|
||||
float2 rotate2D(float2 v, float angle) {
|
||||
float2
|
||||
rotate2D(float2 v, float angle) {
|
||||
float s = sin(angle), c = cos(angle);
|
||||
// GLSL: mat2(c,-s, s,c)*v → rows: (c,s),(-s,c)
|
||||
return mul(float2x2(c, s, -s, c), v);
|
||||
}
|
||||
|
||||
float3 rotateX(float3 v, float angle) {
|
||||
float3
|
||||
rotateX(float3 v, float angle) {
|
||||
float s = sin(angle), c = cos(angle);
|
||||
// GLSL: mat3(1,0,0, 0,c,-s, 0,s,c)*v → rows: (1,0,0),(0,c,s),(0,-s,c)
|
||||
return mul(float3x3(1.0f, 0.0f, 0.0f,
|
||||
0.0f, c, s,
|
||||
0.0f, -s, c), v);
|
||||
return mul(float3x3(1.0f, 0.0f, 0.0f, 0.0f, c, s, 0.0f, -s, c), v);
|
||||
}
|
||||
|
||||
float3 rotateY(float3 v, float angle) {
|
||||
float3
|
||||
rotateY(float3 v, float angle) {
|
||||
float s = sin(angle), c = cos(angle);
|
||||
// GLSL: mat3(c,0,-s, 0,1,0, s,0,c)*v → rows: (c,0,s),(0,1,0),(-s,0,c)
|
||||
return mul(float3x3( c, 0.0f, s,
|
||||
0.0f, 1.0f, 0.0f,
|
||||
-s, 0.0f, c), v);
|
||||
return mul(float3x3(c, 0.0f, s, 0.0f, 1.0f, 0.0f, -s, 0.0f, c), v);
|
||||
}
|
||||
|
||||
float3 rotateZ(float3 v, float angle) {
|
||||
float3
|
||||
rotateZ(float3 v, float angle) {
|
||||
float s = sin(angle), c = cos(angle);
|
||||
// GLSL: mat3(c,-s,0, s,c,0, 0,0,1)*v → rows: (c,s,0),(-s,c,0),(0,0,1)
|
||||
return mul(float3x3( c, s, 0.0f,
|
||||
-s, c, 0.0f,
|
||||
0.0f, 0.0f, 1.0f), v);
|
||||
return mul(float3x3(c, s, 0.0f, -s, c, 0.0f, 0.0f, 0.0f, 1.0f), v);
|
||||
}
|
||||
|
||||
float smoothstep1(float x) { return smoothstep(0.0f, 1.0f, x); }
|
||||
float
|
||||
smoothstep1(float x) {
|
||||
return smoothstep(0.0f, 1.0f, x);
|
||||
}
|
||||
|
||||
// ---- entry point ----
|
||||
|
||||
public float4 fragment_main(
|
||||
float4 color,
|
||||
KittyTextures t,
|
||||
KittyCustomShaderData d
|
||||
) {
|
||||
float2 uv = t.pos;
|
||||
float time = fmod(d.timestamp, 300.0f) * SPEED;
|
||||
public float4
|
||||
fragment_main(float4 color, KittyTextures t, KittyCustomShaderData d) {
|
||||
float2 uv = t.pos;
|
||||
float time = fmod(d.timestamp, 300.0f) * SPEED;
|
||||
|
||||
const float turn_rad = 0.25f / BLOCKS_BEFORE_TURN;
|
||||
const float turn_rad = 0.25f / BLOCKS_BEFORE_TURN;
|
||||
const float turn_abs_time = (PI * 0.5f * turn_rad) * 1.5f;
|
||||
const float turn_time = turn_abs_time / (1.0f - 2.0f * turn_rad + turn_abs_time);
|
||||
const float turn_time = turn_abs_time / (1.0f - 2.0f * turn_rad + turn_abs_time);
|
||||
|
||||
float level1_size = float(BLOCK_SIZE) * BLOCKS_BEFORE_TURN * XYCELL_SIZE;
|
||||
float gap_size = float(BLOCK_GAP) * XYCELL_SIZE;
|
||||
float gap_size = float(BLOCK_GAP) * XYCELL_SIZE;
|
||||
|
||||
float3 ro = float3(gap_size * 0.5f, gap_size * 0.5f, 0.0f);
|
||||
float3 rd = float3(uv.x, 2.0f, uv.y);
|
||||
|
|
@ -257,65 +246,90 @@ public float4 fragment_main(
|
|||
float t1 = frac(t8 * 8.0f);
|
||||
|
||||
float2 prev, dir;
|
||||
if (tq < 0.25f) { prev = float2(0.0f, 0.0f); dir = float2(0.0f, 1.0f); }
|
||||
else if (tq < 0.50f) { prev = float2(0.0f, 1.0f); dir = float2(1.0f, 0.0f); }
|
||||
else if (tq < 0.75f) { prev = float2(1.0f, 1.0f); dir = float2(0.0f, -1.0f); }
|
||||
else { prev = float2(1.0f, 0.0f); dir = float2(-1.0f, 0.0f); }
|
||||
if (tq < 0.25f) {
|
||||
prev = float2(0.0f, 0.0f);
|
||||
dir = float2(0.0f, 1.0f);
|
||||
} else if (tq < 0.50f) {
|
||||
prev = float2(0.0f, 1.0f);
|
||||
dir = float2(1.0f, 0.0f);
|
||||
} else if (tq < 0.75f) {
|
||||
prev = float2(1.0f, 1.0f);
|
||||
dir = float2(0.0f, -1.0f);
|
||||
} else {
|
||||
prev = float2(1.0f, 0.0f);
|
||||
dir = float2(-1.0f, 0.0f);
|
||||
}
|
||||
|
||||
float angle = floor(tq * 4.0f);
|
||||
prev *= 4.0f;
|
||||
|
||||
const float first_turn_look_angle = 0.4f;
|
||||
const float first_turn_look_angle = 0.4f;
|
||||
const float second_turn_drift_angle = 0.5f;
|
||||
const float fifth_turn_drift_angle = 0.25f;
|
||||
const float fifth_turn_drift_angle = 0.25f;
|
||||
|
||||
float2 dirL = rotate2D(dir, -PI * 0.5f);
|
||||
float2 dirR = -dirL;
|
||||
float2 turn;
|
||||
float turn_sign = 0.0f;
|
||||
float up_down = 0.0f;
|
||||
float rotate_on_turns = 1.0f;
|
||||
float roll_on_turns = 1.0f;
|
||||
float add_angel = 0.0f;
|
||||
float turn_sign = 0.0f;
|
||||
float up_down = 0.0f;
|
||||
float rotate_on_turns = 1.0f;
|
||||
float roll_on_turns = 1.0f;
|
||||
float add_angel = 0.0f;
|
||||
|
||||
if (t8 < 0.125f) {
|
||||
turn = dirL; turn_sign = -1.0f;
|
||||
angle -= first_turn_look_angle * (
|
||||
max(0.0f, t1 - (1.0f - turn_time * 2.0f)) / turn_time
|
||||
- max(0.0f, t1 - (1.0f - turn_time)) / turn_time * 2.5f);
|
||||
turn = dirL;
|
||||
turn_sign = -1.0f;
|
||||
angle -= first_turn_look_angle * (max(0.0f, t1 - (1.0f - turn_time * 2.0f)) / turn_time - max(0.0f, t1 - (1.0f - turn_time)) / turn_time * 2.5f);
|
||||
roll_on_turns = 0.0f;
|
||||
} else if (t8 < 0.250f) {
|
||||
prev += dir; turn = dir; dir = dirL;
|
||||
angle -= 1.0f; turn_sign = 1.0f;
|
||||
add_angel += first_turn_look_angle * 0.5f
|
||||
+ (-first_turn_look_angle * 0.5f + 1.0f + second_turn_drift_angle) * t1;
|
||||
rotate_on_turns = 0.0f; roll_on_turns = 0.0f;
|
||||
prev += dir;
|
||||
turn = dir;
|
||||
dir = dirL;
|
||||
angle -= 1.0f;
|
||||
turn_sign = 1.0f;
|
||||
add_angel += first_turn_look_angle * 0.5f + (-first_turn_look_angle * 0.5f + 1.0f + second_turn_drift_angle) * t1;
|
||||
rotate_on_turns = 0.0f;
|
||||
roll_on_turns = 0.0f;
|
||||
} else if (t8 < 0.375f) {
|
||||
prev += dir + dirL; turn = dirR; turn_sign = 1.0f;
|
||||
prev += dir + dirL;
|
||||
turn = dirR;
|
||||
turn_sign = 1.0f;
|
||||
add_angel += second_turn_drift_angle * sqrt(1.0f - t1);
|
||||
} else if (t8 < 0.500f) {
|
||||
prev += dir + dir + dirL; turn = dirR; dir = dirR;
|
||||
angle += 1.0f; turn_sign = 0.0f;
|
||||
prev += dir + dir + dirL;
|
||||
turn = dirR;
|
||||
dir = dirR;
|
||||
angle += 1.0f;
|
||||
turn_sign = 0.0f;
|
||||
up_down = sin(t1 * PI) * 0.37f;
|
||||
} else if (t8 < 0.625f) {
|
||||
prev += dir + dir; turn = dir; dir = dirR;
|
||||
angle += 1.0f; turn_sign = -1.0f;
|
||||
prev += dir + dir;
|
||||
turn = dir;
|
||||
dir = dirR;
|
||||
angle += 1.0f;
|
||||
turn_sign = -1.0f;
|
||||
up_down = sin(-min(1.0f, t1 / (1.0f - turn_time)) * PI) * 0.37f;
|
||||
} else if (t8 < 0.750f) {
|
||||
prev += dir + dir + dirR; turn = dirL; turn_sign = -1.0f;
|
||||
prev += dir + dir + dirR;
|
||||
turn = dirL;
|
||||
turn_sign = -1.0f;
|
||||
add_angel -= (fifth_turn_drift_angle + 1.0f) * smoothstep1(t1);
|
||||
rotate_on_turns = 0.0f; roll_on_turns = 0.0f;
|
||||
rotate_on_turns = 0.0f;
|
||||
roll_on_turns = 0.0f;
|
||||
} else if (t8 < 0.875f) {
|
||||
prev += dir + dir + dir + dirR; turn = dir; dir = dirL;
|
||||
angle -= 1.0f; turn_sign = 1.0f;
|
||||
add_angel -= fifth_turn_drift_angle
|
||||
- smoothstep1(t1) * (fifth_turn_drift_angle * 2.0f + 1.0f);
|
||||
rotate_on_turns = 0.0f; roll_on_turns = 0.0f;
|
||||
prev += dir + dir + dir + dirR;
|
||||
turn = dir;
|
||||
dir = dirL;
|
||||
angle -= 1.0f;
|
||||
turn_sign = 1.0f;
|
||||
add_angel -= fifth_turn_drift_angle - smoothstep1(t1) * (fifth_turn_drift_angle * 2.0f + 1.0f);
|
||||
rotate_on_turns = 0.0f;
|
||||
roll_on_turns = 0.0f;
|
||||
} else {
|
||||
prev += dir + dir + dir; turn = dirR; turn_sign = 1.0f;
|
||||
angle += fifth_turn_drift_angle * (
|
||||
1.5f * min(1.0f, (1.0f - t1) / turn_time)
|
||||
- 0.5f * smoothstep1(1.0f - min(1.0f, t1 / (1.0f - turn_time))));
|
||||
prev += dir + dir + dir;
|
||||
turn = dirR;
|
||||
turn_sign = 1.0f;
|
||||
angle += fifth_turn_drift_angle * (1.5f * min(1.0f, (1.0f - t1) / turn_time) - 0.5f * smoothstep1(1.0f - min(1.0f, t1 / (1.0f - turn_time))));
|
||||
}
|
||||
|
||||
if (d.mouse_button_pressed.x != 0) {
|
||||
|
|
@ -334,9 +348,9 @@ public float4 fragment_main(
|
|||
if (turn_sign == 0.0f) {
|
||||
p = prev + dir * (turn_rad + t1);
|
||||
} else if (t1 > (1.0f - turn_time)) {
|
||||
float tr = (t1 - (1.0f - turn_time)) / turn_time;
|
||||
float tr = (t1 - (1.0f - turn_time)) / turn_time;
|
||||
float2 ctr = prev + dir * (1.0f - turn_rad) + turn * turn_rad;
|
||||
p = ctr + turn_rad * rotate2D(dir, (tr - 1.0f) * turn_sign * PI * 0.5f);
|
||||
p = ctr + turn_rad * rotate2D(dir, (tr - 1.0f) * turn_sign * PI * 0.5f);
|
||||
angle += tr * turn_sign * rotate_on_turns;
|
||||
rd = rotateY(rd, sin(tr * turn_sign * PI) * 0.2f * roll_on_turns);
|
||||
} else {
|
||||
|
|
@ -352,8 +366,8 @@ public float4 fragment_main(
|
|||
float3 col = rain(ro, rd, time) * 0.25f;
|
||||
|
||||
float4 terminalColor = t.backbuffer.Sample(t.pos);
|
||||
float mask = 1.2f - step(0.5f, dot(terminalColor.rgb, float3(1.0f, 1.0f, 1.0f)));
|
||||
float3 blended = lerp(terminalColor.rgb * 1.2f, col, mask);
|
||||
float mask = 1.2f - step(0.5f, dot(terminalColor.rgb, float3(1.0f, 1.0f, 1.0f)));
|
||||
float3 blended = lerp(terminalColor.rgb * 1.2f, col, mask);
|
||||
|
||||
return float4(blended, terminalColor.a);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,7 @@
|
|||
|
||||
import kitty_custom_shader_types;
|
||||
|
||||
public float4 fragment_main(
|
||||
float4 color,
|
||||
KittyTextures t,
|
||||
KittyCustomShaderData d
|
||||
) {
|
||||
public float4
|
||||
fragment_main(float4 color, KittyTextures t, KittyCustomShaderData d) {
|
||||
return float4(1.0 - color.r, 1.0 - color.g, 1.0 - color.b, color.a);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,12 +39,11 @@ static const float VERTICAL_FADE = 25.0f;
|
|||
static const float CAMERA_DISTANCE = 9.7f;
|
||||
|
||||
// === PERSISTENCE & DECAY CONTROLS ===
|
||||
static const float ACCUMULATION_DECAY = 0.03f; // Decay per frame: 0.0 = infinite, 0.005 = slow fade
|
||||
static const float ACCUMULATION_DECAY = 0.03f; // Decay per frame: 0.0 = infinite, 0.005 = slow fade
|
||||
static const float MOUSE_PERSIST_INTENSITY = 1.1f; // Brightness multiplier for persistent rays
|
||||
|
||||
// === STAR FIELD CONTROLS ===
|
||||
static const float STAR_FIELD_ROTATIONS_SPEED =
|
||||
(2 * PI) / (86400 * TIME_SCALE);
|
||||
static const float STAR_FIELD_ROTATIONS_SPEED = (2 * PI) / (86400 * TIME_SCALE);
|
||||
static const float STAR_BRIGHTNESS = 0.7f;
|
||||
static const float STAR_SIZE = 1.6f;
|
||||
static const float STAR_TWINKLE_SPEED = 0.05f;
|
||||
|
|
@ -77,9 +76,9 @@ static const float DIP_LEVEL = 0.30f;
|
|||
// === MOUSE TRAIL & RADIAL RAY SHAPE CONTROLS ===
|
||||
static const float MOUSE_AURORA_INTENSITY = 0.15f;
|
||||
static const float MOUSE_TRAIL_WIDTH = 0.06f;
|
||||
static const float MOUSE_RAY_WIDTH = 0.015f; // Tangential ray width
|
||||
static const float MOUSE_RAY_LENGTH = 0.11f; // Radial ray length along center alignment
|
||||
static const float MOUSE_RAY_FREQUENCY = 160.0f; // Fine curtain thread streaking frequency
|
||||
static const float MOUSE_RAY_WIDTH = 0.015f; // Tangential ray width
|
||||
static const float MOUSE_RAY_LENGTH = 0.11f; // Radial ray length along center alignment
|
||||
static const float MOUSE_RAY_FREQUENCY = 160.0f; // Fine curtain thread streaking frequency
|
||||
static const float MOUSE_TRAIL_NOISE_SCALE = 3.0f;
|
||||
static const float MOUSE_PRESS_BOOST = 0.3f;
|
||||
static const float MOUSE_IGNORE_WHEN_HIDDEN = 0.0f;
|
||||
|
|
@ -88,8 +87,7 @@ static const float DEBUG_MOUSE_OVERLAY = 0.0f;
|
|||
static const float3 SKY_COLOR_TOP = float3(0.05f, 0.1f, 0.2f);
|
||||
static const float3 SKY_COLOR_BOTTOM = float3(0.1f, 0.05f, 0.2f);
|
||||
|
||||
static const float2x2 TRI_ROT_MATRIX =
|
||||
float2x2(0.95534f, 0.29552f, -0.29552f, 0.95534f);
|
||||
static const float2x2 TRI_ROT_MATRIX = float2x2(0.95534f, 0.29552f, -0.29552f, 0.95534f);
|
||||
|
||||
static const float LATITUDE_DEGREES = 61.2f;
|
||||
static const float LAT_RAD = LATITUDE_DEGREES * (3.14159265359f / 180.0f);
|
||||
|
|
@ -97,471 +95,479 @@ static const float3 CELESTIAL_POLE = float3(0.0f, sin(LAT_RAD), cos(LAT_RAD));
|
|||
static const float PERSPECTIVE_TILT = 0.12f;
|
||||
|
||||
static const int STAR_LAYERS = 4;
|
||||
static const float STAR_LAYER_DENSITY[STAR_LAYERS] = {0.0005f, 0.0015f, 0.0045f, 0.0125f};
|
||||
static const float STAR_LAYER_DENSITY[STAR_LAYERS] = { 0.0005f, 0.0015f, 0.0045f, 0.0125f };
|
||||
|
||||
static const float TWINKLE_FREQ_A = 1.618034f;
|
||||
static const float TWINKLE_FREQ_B = 2.414214f;
|
||||
|
||||
static const int STAGE = 0; // internal use only
|
||||
static const int STAGE = 0; // internal use only
|
||||
|
||||
// === TRIANGLE WAVE NOISE ===
|
||||
|
||||
float triWave(float x) { return clamp(abs(frac(x) - 0.5f), 0.01f, 0.49f); }
|
||||
|
||||
float2 triWave2(float2 p) {
|
||||
return float2(triWave(p.x) + triWave(p.y), triWave(p.y + triWave(p.x)));
|
||||
float
|
||||
triWave(float x) {
|
||||
return clamp(abs(frac(x) - 0.5f), 0.01f, 0.49f);
|
||||
}
|
||||
|
||||
float triNoise2d(float2 p, float spd, float timestamp, float sharpness) {
|
||||
float z = 1.8f;
|
||||
float z2 = 2.5f;
|
||||
float rz = 0.0f;
|
||||
float2
|
||||
triWave2(float2 p) {
|
||||
return float2(triWave(p.x) + triWave(p.y), triWave(p.y + triWave(p.x)));
|
||||
}
|
||||
|
||||
float c = cos(p.x * 0.06f);
|
||||
float s = sin(p.x * 0.06f);
|
||||
p = mul(float2x2(c, s, -s, c), p);
|
||||
float
|
||||
triNoise2d(float2 p, float spd, float timestamp, float sharpness) {
|
||||
float z = 1.8f;
|
||||
float z2 = 2.5f;
|
||||
float rz = 0.0f;
|
||||
|
||||
float2 bp = p;
|
||||
float c = cos(p.x * 0.06f);
|
||||
float s = sin(p.x * 0.06f);
|
||||
p = mul(float2x2(c, s, -s, c), p);
|
||||
|
||||
[ForceUnroll] for (int i = 0; i < 5; i++) {
|
||||
float2 dg = triWave2(bp * 1.85f) * 0.75f;
|
||||
float tc = cos(timestamp * spd);
|
||||
float ts = sin(timestamp * spd);
|
||||
dg = mul(float2x2(tc, ts, -ts, tc), dg);
|
||||
p -= dg / z2;
|
||||
float2 bp = p;
|
||||
|
||||
bp *= 1.3f;
|
||||
z2 *= 0.45f;
|
||||
z *= 0.42f;
|
||||
p *= 1.21f + (rz - 1.0f) * 0.02f;
|
||||
[ForceUnroll]
|
||||
for (int i = 0; i < 5; i++) {
|
||||
float2 dg = triWave2(bp * 1.85f) * 0.75f;
|
||||
float tc = cos(timestamp * spd);
|
||||
float ts = sin(timestamp * spd);
|
||||
dg = mul(float2x2(tc, ts, -ts, tc), dg);
|
||||
p -= dg / z2;
|
||||
|
||||
rz += triWave(p.x + triWave(p.y)) * z;
|
||||
p = mul(TRI_ROT_MATRIX, p) * -1.0f;
|
||||
}
|
||||
bp *= 1.3f;
|
||||
z2 *= 0.45f;
|
||||
z *= 0.42f;
|
||||
p *= 1.21f + (rz - 1.0f) * 0.02f;
|
||||
|
||||
return clamp(1.0f / pow(rz * sharpness, CURTAIN_SOFTNESS), 0.0f, 0.55f);
|
||||
rz += triWave(p.x + triWave(p.y)) * z;
|
||||
p = mul(TRI_ROT_MATRIX, p) * -1.0f;
|
||||
}
|
||||
|
||||
return clamp(1.0f / pow(rz * sharpness, CURTAIN_SOFTNESS), 0.0f, 0.55f);
|
||||
}
|
||||
|
||||
// === HASH FUNCTIONS ===
|
||||
|
||||
float hash21(float2 n) {
|
||||
return frac(sin(dot(n, float2(12.9898f, 4.1414f))) * 43758.5453f);
|
||||
float
|
||||
hash21(float2 n) {
|
||||
return frac(sin(dot(n, float2(12.9898f, 4.1414f))) * 43758.5453f);
|
||||
}
|
||||
|
||||
uint pcgHash(uint v) {
|
||||
v = v * 747796405u + 2891336453u;
|
||||
uint w = ((v >> ((v >> 28u) + 4u)) ^ v) * 277803737u;
|
||||
return (w >> 22u) ^ w;
|
||||
uint
|
||||
pcgHash(uint v) {
|
||||
v = v * 747796405u + 2891336453u;
|
||||
uint w = ((v >> ((v >> 28u) + 4u)) ^ v) * 277803737u;
|
||||
return (w >> 22u) ^ w;
|
||||
}
|
||||
|
||||
float epochRand(uint epoch, uint channel) {
|
||||
uint seed = epoch * 0x9E3779B9u ^ (channel * 0x85EBCA6Bu + 0x27D4EB2Fu);
|
||||
return float(pcgHash(seed)) * (1.0f / 4294967295.0f);
|
||||
float
|
||||
epochRand(uint epoch, uint channel) {
|
||||
uint seed = epoch * 0x9E3779B9u ^ (channel * 0x85EBCA6Bu + 0x27D4EB2Fu);
|
||||
return float(pcgHash(seed)) * (1.0f / 4294967295.0f);
|
||||
}
|
||||
|
||||
float3 pcgHash33(float3 q) {
|
||||
const uint STREAM_X = 0x9E3779B9u;
|
||||
const uint STREAM_Y = 0x85EBCA6Bu;
|
||||
const uint STREAM_Z = 0xC2B2AE35u;
|
||||
float3
|
||||
pcgHash33(float3 q) {
|
||||
const uint STREAM_X = 0x9E3779B9u;
|
||||
const uint STREAM_Y = 0x85EBCA6Bu;
|
||||
const uint STREAM_Z = 0xC2B2AE35u;
|
||||
|
||||
uint3 p = uint3(int3(floor(q)));
|
||||
uint3 p = uint3(int3(floor(q)));
|
||||
|
||||
const uint MULT = 0x5851F42Du;
|
||||
const uint MULT = 0x5851F42Du;
|
||||
|
||||
uint h = p.x * MULT + p.y * 0x27D4EB2Fu + p.z * 0x165667B1u + STREAM_X;
|
||||
h = ((h >> ((h >> 28u) + 4u)) ^ h) * 277803737u;
|
||||
uint outX = (h >> 22u) ^ h;
|
||||
uint h = p.x * MULT + p.y * 0x27D4EB2Fu + p.z * 0x165667B1u + STREAM_X;
|
||||
h = ((h >> ((h >> 28u) + 4u)) ^ h) * 277803737u;
|
||||
uint outX = (h >> 22u) ^ h;
|
||||
|
||||
h = p.y * MULT + p.z * 0x27D4EB2Fu + p.x * 0x165667B1u + STREAM_Y;
|
||||
h = ((h >> ((h >> 28u) + 4u)) ^ h) * 277803737u;
|
||||
uint outY = (h >> 22u) ^ h;
|
||||
h = p.y * MULT + p.z * 0x27D4EB2Fu + p.x * 0x165667B1u + STREAM_Y;
|
||||
h = ((h >> ((h >> 28u) + 4u)) ^ h) * 277803737u;
|
||||
uint outY = (h >> 22u) ^ h;
|
||||
|
||||
h = p.z * MULT + p.x * 0x27D4EB2Fu + p.y * 0x165667B1u + STREAM_Z;
|
||||
h = ((h >> ((h >> 28u) + 4u)) ^ h) * 277803737u;
|
||||
uint outZ = (h >> 22u) ^ h;
|
||||
h = p.z * MULT + p.x * 0x27D4EB2Fu + p.y * 0x165667B1u + STREAM_Z;
|
||||
h = ((h >> ((h >> 28u) + 4u)) ^ h) * 277803737u;
|
||||
uint outZ = (h >> 22u) ^ h;
|
||||
|
||||
return float3(outX, outY, outZ) * (1.0f / 4294967295.0f);
|
||||
return float3(outX, outY, outZ) * (1.0f / 4294967295.0f);
|
||||
}
|
||||
|
||||
// === PER-EPOCH RANDOM PARAMETERS ===
|
||||
|
||||
struct AuroraRandParams {
|
||||
float timeOffset;
|
||||
float2 startOffset;
|
||||
float waveSpeedMul;
|
||||
float scaleMul;
|
||||
float sharpMul;
|
||||
float colorJitter;
|
||||
float intensityMul;
|
||||
float timeOffset;
|
||||
float2 startOffset;
|
||||
float waveSpeedMul;
|
||||
float scaleMul;
|
||||
float sharpMul;
|
||||
float colorJitter;
|
||||
float intensityMul;
|
||||
};
|
||||
|
||||
AuroraRandParams identityParams() {
|
||||
AuroraRandParams rp;
|
||||
rp.timeOffset = 0.0f;
|
||||
rp.startOffset = float2(0.0f, 0.0f);
|
||||
rp.waveSpeedMul = 1.0f;
|
||||
rp.scaleMul = 1.0f;
|
||||
rp.sharpMul = 1.0f;
|
||||
rp.colorJitter = 0.0f;
|
||||
rp.intensityMul = 1.0f;
|
||||
return rp;
|
||||
AuroraRandParams
|
||||
identityParams() {
|
||||
AuroraRandParams rp;
|
||||
rp.timeOffset = 0.0f;
|
||||
rp.startOffset = float2(0.0f, 0.0f);
|
||||
rp.waveSpeedMul = 1.0f;
|
||||
rp.scaleMul = 1.0f;
|
||||
rp.sharpMul = 1.0f;
|
||||
rp.colorJitter = 0.0f;
|
||||
rp.intensityMul = 1.0f;
|
||||
return rp;
|
||||
}
|
||||
|
||||
AuroraRandParams epochParams(uint epoch) {
|
||||
AuroraRandParams rp;
|
||||
rp.timeOffset = epochRand(epoch, 1u) * 4096.0f;
|
||||
rp.startOffset = float2(0.0f, 0.0f);
|
||||
rp.waveSpeedMul = lerp(0.75f, 1.25f, epochRand(epoch, 6u));
|
||||
rp.scaleMul = lerp(0.85f, 1.15f, epochRand(epoch, 7u));
|
||||
rp.sharpMul = lerp(0.80f, 1.20f, epochRand(epoch, 8u));
|
||||
rp.colorJitter = lerp(-0.6f, 0.6f, epochRand(epoch, 9u));
|
||||
rp.intensityMul = lerp(0.85f, 1.15f, epochRand(epoch, 10u));
|
||||
return rp;
|
||||
AuroraRandParams
|
||||
epochParams(uint epoch) {
|
||||
AuroraRandParams rp;
|
||||
rp.timeOffset = epochRand(epoch, 1u) * 4096.0f;
|
||||
rp.startOffset = float2(0.0f, 0.0f);
|
||||
rp.waveSpeedMul = lerp(0.75f, 1.25f, epochRand(epoch, 6u));
|
||||
rp.scaleMul = lerp(0.85f, 1.15f, epochRand(epoch, 7u));
|
||||
rp.sharpMul = lerp(0.80f, 1.20f, epochRand(epoch, 8u));
|
||||
rp.colorJitter = lerp(-0.6f, 0.6f, epochRand(epoch, 9u));
|
||||
rp.intensityMul = lerp(0.85f, 1.15f, epochRand(epoch, 10u));
|
||||
return rp;
|
||||
}
|
||||
|
||||
AuroraRandParams lerpParams(AuroraRandParams a, AuroraRandParams b, float t) {
|
||||
AuroraRandParams rp;
|
||||
rp.timeOffset = lerp(a.timeOffset, b.timeOffset, t);
|
||||
rp.startOffset = lerp(a.startOffset, b.startOffset, t);
|
||||
rp.waveSpeedMul = lerp(a.waveSpeedMul, b.waveSpeedMul, t);
|
||||
rp.scaleMul = lerp(a.scaleMul, b.scaleMul, t);
|
||||
rp.sharpMul = lerp(a.sharpMul, b.sharpMul, t);
|
||||
rp.colorJitter = lerp(a.colorJitter, b.colorJitter, t);
|
||||
rp.intensityMul = lerp(a.intensityMul, b.intensityMul, t);
|
||||
return rp;
|
||||
AuroraRandParams
|
||||
lerpParams(AuroraRandParams a, AuroraRandParams b, float t) {
|
||||
AuroraRandParams rp;
|
||||
rp.timeOffset = lerp(a.timeOffset, b.timeOffset, t);
|
||||
rp.startOffset = lerp(a.startOffset, b.startOffset, t);
|
||||
rp.waveSpeedMul = lerp(a.waveSpeedMul, b.waveSpeedMul, t);
|
||||
rp.scaleMul = lerp(a.scaleMul, b.scaleMul, t);
|
||||
rp.sharpMul = lerp(a.sharpMul, b.sharpMul, t);
|
||||
rp.colorJitter = lerp(a.colorJitter, b.colorJitter, t);
|
||||
rp.intensityMul = lerp(a.intensityMul, b.intensityMul, t);
|
||||
return rp;
|
||||
}
|
||||
|
||||
AuroraRandParams getAuroraParams(float rawTimestamp, float randomFloat) {
|
||||
if (RANDOMIZE <= 0.001f)
|
||||
return identityParams();
|
||||
uint launchOffset = uint(randomFloat * 100000.0f);
|
||||
uint epoch = uint(floor(rawTimestamp / RESEED_INTERVAL)) + launchOffset;
|
||||
return lerpParams(identityParams(), epochParams(epoch), RANDOMIZE);
|
||||
AuroraRandParams
|
||||
getAuroraParams(float rawTimestamp, float randomFloat) {
|
||||
if (RANDOMIZE <= 0.001f) return identityParams();
|
||||
uint launchOffset = uint(randomFloat * 100000.0f);
|
||||
uint epoch = uint(floor(rawTimestamp / RESEED_INTERVAL)) + launchOffset;
|
||||
return lerpParams(identityParams(), epochParams(epoch), RANDOMIZE);
|
||||
}
|
||||
|
||||
float transitionBrightness(float rawTimestamp) {
|
||||
if (RANDOMIZE <= 0.001f)
|
||||
return 1.0f;
|
||||
float ph = frac(rawTimestamp / RESEED_INTERVAL);
|
||||
float dEpoch = min(ph, 1.0f - ph) * RESEED_INTERVAL;
|
||||
float halfDip = TRANSITION_DIP * 0.5f;
|
||||
if (dEpoch >= halfDip)
|
||||
return 1.0f;
|
||||
float u = dEpoch / max(halfDip, 1e-4f);
|
||||
return lerp(DIP_LEVEL, 1.0f, smoothstep(0.0f, 1.0f, u));
|
||||
float
|
||||
transitionBrightness(float rawTimestamp) {
|
||||
if (RANDOMIZE <= 0.001f) return 1.0f;
|
||||
float ph = frac(rawTimestamp / RESEED_INTERVAL);
|
||||
float dEpoch = min(ph, 1.0f - ph) * RESEED_INTERVAL;
|
||||
float halfDip = TRANSITION_DIP * 0.5f;
|
||||
if (dEpoch >= halfDip) return 1.0f;
|
||||
float u = dEpoch / max(halfDip, 1e-4f);
|
||||
return lerp(DIP_LEVEL, 1.0f, smoothstep(0.0f, 1.0f, u));
|
||||
}
|
||||
|
||||
// === PROCEDURAL STARS ===
|
||||
|
||||
float magnitudeToBrightness(float hashVal) {
|
||||
float mag = hashVal * STAR_BRIGHTNESS_VARIATION;
|
||||
return pow(10.0f, -0.4f * mag);
|
||||
float
|
||||
magnitudeToBrightness(float hashVal) {
|
||||
float mag = hashVal * STAR_BRIGHTNESS_VARIATION;
|
||||
return pow(10.0f, -0.4f * mag);
|
||||
}
|
||||
|
||||
float evalTwinkleWave(float3 pos, float seed, float horizonFactor) {
|
||||
float variance = 1.0f - STAR_TWINKLE_CORRELATION;
|
||||
float
|
||||
evalTwinkleWave(float3 pos, float seed, float horizonFactor) {
|
||||
float variance = 1.0f - STAR_TWINKLE_CORRELATION;
|
||||
|
||||
float seedPhaseA = seed * 6.2831853f * variance;
|
||||
float seedPhaseB = seed * 3.14159265f * variance;
|
||||
float seedPhaseC = seed * 4.71238898f * variance;
|
||||
float freqMod = 1.0f + (frac(seed * 17.13f) - 0.5f) * 0.6f * variance;
|
||||
float seedPhaseA = seed * 6.2831853f * variance;
|
||||
float seedPhaseB = seed * 3.14159265f * variance;
|
||||
float seedPhaseC = seed * 4.71238898f * variance;
|
||||
float freqMod = 1.0f + (frac(seed * 17.13f) - 0.5f) * 0.6f * variance;
|
||||
|
||||
float spd = STAR_TWINKLE_SPEED * freqMod * horizonFactor;
|
||||
float spd = STAR_TWINKLE_SPEED * freqMod * horizonFactor;
|
||||
|
||||
float waveA = sin(dot(pos, TWINKLE_WAVE_DIR_A) * spd + seedPhaseA);
|
||||
float waveB = cos(dot(pos, TWINKLE_WAVE_DIR_B) * spd * STAR_TWINKLE_WAVE_B_MULT +
|
||||
seedPhaseB + waveA * 0.7f);
|
||||
float waveC = sin(dot(pos, TWINKLE_WAVE_DIR_C) * spd * STAR_TWINKLE_WAVE_C_MULT +
|
||||
seedPhaseC);
|
||||
float microFlash = pow(clamp(waveC * 0.5f + 0.5f, 0.0f, 1.0f), 3.0f);
|
||||
float waveA = sin(dot(pos, TWINKLE_WAVE_DIR_A) * spd + seedPhaseA);
|
||||
float waveB = cos(dot(pos, TWINKLE_WAVE_DIR_B) * spd * STAR_TWINKLE_WAVE_B_MULT + seedPhaseB + waveA * 0.7f);
|
||||
float waveC = sin(dot(pos, TWINKLE_WAVE_DIR_C) * spd * STAR_TWINKLE_WAVE_C_MULT + seedPhaseC);
|
||||
float microFlash = pow(clamp(waveC * 0.5f + 0.5f, 0.0f, 1.0f), 3.0f);
|
||||
|
||||
float combined = waveA * 0.45f + waveB * 0.35f + (microFlash - 0.2f) * 0.4f;
|
||||
float combined = waveA * 0.45f + waveB * 0.35f + (microFlash - 0.2f) * 0.4f;
|
||||
|
||||
return max(0.0f, STAR_TWINKLE_BASE +
|
||||
STAR_TWINKLE_AMPLITUDE * combined * horizonFactor);
|
||||
return max(0.0f, STAR_TWINKLE_BASE + STAR_TWINKLE_AMPLITUDE * combined * horizonFactor);
|
||||
}
|
||||
|
||||
float3 continuousChromaticTwinkle(float3 rd, float time, float seed) {
|
||||
float3 turbulencePos = rd * STAR_TURBULENCE_SCALE;
|
||||
float3 windDrift = time * STAR_WIND_DRIFT_SPEED;
|
||||
float3 p = turbulencePos + windDrift;
|
||||
float3
|
||||
continuousChromaticTwinkle(float3 rd, float time, float seed) {
|
||||
float3 turbulencePos = rd * STAR_TURBULENCE_SCALE;
|
||||
float3 windDrift = time * STAR_WIND_DRIFT_SPEED;
|
||||
float3 p = turbulencePos + windDrift;
|
||||
|
||||
float horizonFactor = 1.0f + 0.8f * saturate(STAR_DISPERSION_HORIZON_FACTOR - rd.y);
|
||||
float dispersionScale = STAR_DISPERSION_SCALE * saturate(STAR_DISPERSION_HORIZON_FACTOR - rd.y);
|
||||
float horizonFactor = 1.0f + 0.8f * saturate(STAR_DISPERSION_HORIZON_FACTOR - rd.y);
|
||||
float dispersionScale = STAR_DISPERSION_SCALE * saturate(STAR_DISPERSION_HORIZON_FACTOR - rd.y);
|
||||
|
||||
float3 pR = p - STAR_DISPERSION_DIR * dispersionScale;
|
||||
float3 pG = p;
|
||||
float3 pB = p + STAR_DISPERSION_DIR * dispersionScale;
|
||||
float3 pR = p - STAR_DISPERSION_DIR * dispersionScale;
|
||||
float3 pG = p;
|
||||
float3 pB = p + STAR_DISPERSION_DIR * dispersionScale;
|
||||
|
||||
float twR = evalTwinkleWave(pR, seed, horizonFactor);
|
||||
float twG = evalTwinkleWave(pG, seed, horizonFactor);
|
||||
float twB = evalTwinkleWave(pB, seed, horizonFactor);
|
||||
float twR = evalTwinkleWave(pR, seed, horizonFactor);
|
||||
float twG = evalTwinkleWave(pG, seed, horizonFactor);
|
||||
float twB = evalTwinkleWave(pB, seed, horizonFactor);
|
||||
|
||||
return float3(twR, twG, twB);
|
||||
return float3(twR, twG, twB);
|
||||
}
|
||||
|
||||
float3 sampleStars(float3 rd, float2 res, float time) {
|
||||
if (STAR_BRIGHTNESS <= 0.0f)
|
||||
return float3(0.0f, 0.0f, 0.0f);
|
||||
float3
|
||||
sampleStars(float3 rd, float2 res, float time) {
|
||||
if (STAR_BRIGHTNESS <= 0.0f) return float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
float rotSpeed = STAR_FIELD_ROTATIONS_SPEED;
|
||||
float angle = time * rotSpeed;
|
||||
float ca = cos(angle);
|
||||
float sa = sin(angle);
|
||||
float rotSpeed = STAR_FIELD_ROTATIONS_SPEED;
|
||||
float angle = time * rotSpeed;
|
||||
float ca = cos(angle);
|
||||
float sa = sin(angle);
|
||||
|
||||
float3 rotRd = rd * ca + cross(CELESTIAL_POLE, rd) * sa +
|
||||
CELESTIAL_POLE * dot(CELESTIAL_POLE, rd) * (1.0f - ca);
|
||||
float3 rotRd = rd * ca + cross(CELESTIAL_POLE, rd) * sa + CELESTIAL_POLE * dot(CELESTIAL_POLE, rd) * (1.0f - ca);
|
||||
|
||||
float3 c = float3(0.0f, 0.0f, 0.0f);
|
||||
float3 c = float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
[ForceUnroll] for (int i = 0; i < STAR_LAYERS; i++) {
|
||||
float scale = (0.15f + float(i) * 0.02f) * res.x;
|
||||
[ForceUnroll]
|
||||
for (int i = 0; i < STAR_LAYERS; i++) {
|
||||
float scale = (0.15f + float(i) * 0.02f) * res.x;
|
||||
|
||||
float3 layerOffset = float3(float(i) * 0.371f, float(i) * 0.519f, float(i) * 0.163f);
|
||||
float3 scaledRd = rotRd * scale + layerOffset;
|
||||
float3 layerOffset = float3(float(i) * 0.371f, float(i) * 0.519f, float(i) * 0.163f);
|
||||
float3 scaledRd = rotRd * scale + layerOffset;
|
||||
|
||||
float3 q = frac(scaledRd) - 0.5f;
|
||||
float3 id = floor(scaledRd);
|
||||
float3 rn = pcgHash33(id);
|
||||
float3 q = frac(scaledRd) - 0.5f;
|
||||
float3 id = floor(scaledRd);
|
||||
float3 rn = pcgHash33(id);
|
||||
|
||||
float threshold = STAR_LAYER_DENSITY[i] * STAR_DENSITY;
|
||||
if (rn.x >= threshold)
|
||||
continue;
|
||||
float threshold = STAR_LAYER_DENSITY[i] * STAR_DENSITY;
|
||||
if (rn.x >= threshold) continue;
|
||||
|
||||
float c2 = 1.0f - smoothstep(0.0f, STAR_SIZE, length(q));
|
||||
float3 twinkleRGB = continuousChromaticTwinkle(rotRd, time, rn.y);
|
||||
float starFlux = magnitudeToBrightness(rn.y);
|
||||
float3 starCol = lerp(float3(1.0f, 0.49f, 0.1f), float3(0.75f, 0.9f, 1.0f), rn.z);
|
||||
float c2 = 1.0f - smoothstep(0.0f, STAR_SIZE, length(q));
|
||||
float3 twinkleRGB = continuousChromaticTwinkle(rotRd, time, rn.y);
|
||||
float starFlux = magnitudeToBrightness(rn.y);
|
||||
float3 starCol = lerp(float3(1.0f, 0.49f, 0.1f), float3(0.75f, 0.9f, 1.0f), rn.z);
|
||||
|
||||
c += c2 * starCol * starFlux * twinkleRGB;
|
||||
}
|
||||
return c * c * STAR_BRIGHTNESS;
|
||||
c += c2 * starCol * starFlux * twinkleRGB;
|
||||
}
|
||||
return c * c * STAR_BRIGHTNESS;
|
||||
}
|
||||
|
||||
// === MOUSE TRAIL FIELD ===
|
||||
|
||||
float mouseTrailField(float3 worldPos, float2 mouseWorld, float mouseValid,
|
||||
float strength) {
|
||||
if (strength <= 0.0f || mouseValid <= 0.5f)
|
||||
return 0.0f;
|
||||
float
|
||||
mouseTrailField(float3 worldPos, float2 mouseWorld, float mouseValid, float strength) {
|
||||
if (strength <= 0.0f || mouseValid <= 0.5f) return 0.0f;
|
||||
|
||||
float dist = length(worldPos.xz - mouseWorld);
|
||||
float dist = length(worldPos.xz - mouseWorld);
|
||||
|
||||
float falloff = saturate(1.0f - dist / MOUSE_TRAIL_WIDTH);
|
||||
falloff = falloff * falloff * (3.0f - 2.0f * falloff);
|
||||
float falloff = saturate(1.0f - dist / MOUSE_TRAIL_WIDTH);
|
||||
falloff = falloff * falloff * (3.0f - 2.0f * falloff);
|
||||
|
||||
return falloff * strength;
|
||||
return falloff * strength;
|
||||
}
|
||||
|
||||
// === ZENITH PROJECTION HELPER ===
|
||||
|
||||
float3 zenithRayDir(float2 centeredUV, float aspect, float horizonRadius,
|
||||
float spinCos, float spinSin) {
|
||||
float2 scaledUV = centeredUV * float2(aspect, 1.0f) * horizonRadius;
|
||||
float r2 = dot(scaledUV, scaledUV);
|
||||
float rd_y = 1.0f / sqrt(1.0f + r2);
|
||||
float3 rd = normalize(float3(scaledUV.x, rd_y, scaledUV.y));
|
||||
float3
|
||||
zenithRayDir(float2 centeredUV, float aspect, float horizonRadius, float spinCos, float spinSin) {
|
||||
float2 scaledUV = centeredUV * float2(aspect, 1.0f) * horizonRadius;
|
||||
float r2 = dot(scaledUV, scaledUV);
|
||||
float rd_y = 1.0f / sqrt(1.0f + r2);
|
||||
float3 rd = normalize(float3(scaledUV.x, rd_y, scaledUV.y));
|
||||
|
||||
float ct = cos(PERSPECTIVE_TILT);
|
||||
float st = sin(PERSPECTIVE_TILT);
|
||||
rd.yz = float2(rd.y * ct - rd.z * st, rd.y * st + rd.z * ct);
|
||||
float ct = cos(PERSPECTIVE_TILT);
|
||||
float st = sin(PERSPECTIVE_TILT);
|
||||
rd.yz = float2(rd.y * ct - rd.z * st, rd.y * st + rd.z * ct);
|
||||
|
||||
rd.xz = mul(float2x2(spinCos, spinSin, -spinSin, spinCos), rd.xz);
|
||||
return rd;
|
||||
rd.xz = mul(float2x2(spinCos, spinSin, -spinSin, spinCos), rd.xz);
|
||||
return rd;
|
||||
}
|
||||
|
||||
// === VOLUMETRIC AURORA RAY MARCH ===
|
||||
|
||||
float4 rayMarchAurora(float3 ro, float3 rd, float2 fragCoord, float noiseTime,
|
||||
AuroraRandParams rp, float2 mouseWorld, float mouseValid,
|
||||
float genStrength, float persistentTrail) {
|
||||
float stepCount = MARCH_STEPS;
|
||||
float4
|
||||
rayMarchAurora(
|
||||
float3 ro,
|
||||
float3 rd,
|
||||
float2 fragCoord,
|
||||
float noiseTime,
|
||||
AuroraRandParams rp,
|
||||
float2 mouseWorld,
|
||||
float mouseValid,
|
||||
float genStrength,
|
||||
float persistentTrail) {
|
||||
float stepCount = MARCH_STEPS;
|
||||
|
||||
float effSpeed = WAVE_SPEED * rp.waveSpeedMul;
|
||||
float effSharpness = CURTAIN_SHARPNESS * rp.sharpMul;
|
||||
float effScale = AURORA_SCALE * rp.scaleMul;
|
||||
float effSpeed = WAVE_SPEED * rp.waveSpeedMul;
|
||||
float effSharpness = CURTAIN_SHARPNESS * rp.sharpMul;
|
||||
float effScale = AURORA_SCALE * rp.scaleMul;
|
||||
|
||||
float3 accColor = float3(0.0f);
|
||||
float accAlpha = 0.0f;
|
||||
float3 accColor = float3(0.0f);
|
||||
float accAlpha = 0.0f;
|
||||
|
||||
[ForceUnroll] for (int i = 0; i < 60; i++) {
|
||||
if (float(i) >= stepCount)
|
||||
break;
|
||||
[ForceUnroll]
|
||||
for (int i = 0; i < 60; i++) {
|
||||
if (float(i) >= stepCount) break;
|
||||
|
||||
float of = 0.006f * hash21(fragCoord) * smoothstep(0.0f, 15.0f, float(i));
|
||||
float pt = ((AURORA_ALTITUDE + pow(float(i), 1.4f) * 0.002f) - ro.y) /
|
||||
(rd.y * 2.0f + 0.4f);
|
||||
pt -= of;
|
||||
float of = 0.006f * hash21(fragCoord) * smoothstep(0.0f, 15.0f, float(i));
|
||||
float pt = ((AURORA_ALTITUDE + pow(float(i), 1.4f) * 0.002f) - ro.y) / (rd.y * 2.0f + 0.4f);
|
||||
pt -= of;
|
||||
|
||||
if (pt < 0.0f)
|
||||
continue;
|
||||
if (pt < 0.0f) continue;
|
||||
|
||||
float3 bpos = ro + pt * rd;
|
||||
float2 p = bpos.zx * effScale + rp.startOffset;
|
||||
float density = triNoise2d(p, effSpeed, noiseTime, effSharpness);
|
||||
float3 bpos = ro + pt * rd;
|
||||
float2 p = bpos.zx * effScale + rp.startOffset;
|
||||
float density = triNoise2d(p, effSpeed, noiseTime, effSharpness);
|
||||
|
||||
float trailField = mouseTrailField(bpos, mouseWorld, mouseValid, genStrength) + persistentTrail;
|
||||
float trailNoise = triNoise2d(p * MOUSE_TRAIL_NOISE_SCALE + mouseWorld * 0.5f,
|
||||
effSpeed * 1.5f, noiseTime, effSharpness * 0.8f);
|
||||
density = saturate(density + trailField * (trailNoise + 0.6f));
|
||||
float trailField = mouseTrailField(bpos, mouseWorld, mouseValid, genStrength) + persistentTrail;
|
||||
float trailNoise = triNoise2d(p * MOUSE_TRAIL_NOISE_SCALE + mouseWorld * 0.5f, effSpeed * 1.5f, noiseTime, effSharpness * 0.8f);
|
||||
density = saturate(density + trailField * (trailNoise + 0.6f));
|
||||
|
||||
float h = float(i) / MARCH_STEPS;
|
||||
float3 colLow = float3(0.1f, 0.95f, 0.4f);
|
||||
float3 colMid = float3(0.1f, 0.85f, 0.85f);
|
||||
float3 colHigh = float3(0.65f, 0.25f, 0.95f);
|
||||
float t1 = smoothstep(0.0f, 0.45f, h);
|
||||
float t2 = smoothstep(0.35f, 1.0f, h);
|
||||
float3 baseCol = lerp(lerp(colLow, colMid, t1), colHigh, t2);
|
||||
baseCol += sin(float3(0.0f, 1.0f, 2.0f) + h * 6.0f + rp.colorJitter) * 0.06f;
|
||||
baseCol = max(baseCol, float3(0.0f));
|
||||
float h = float(i) / MARCH_STEPS;
|
||||
float3 colLow = float3(0.1f, 0.95f, 0.4f);
|
||||
float3 colMid = float3(0.1f, 0.85f, 0.85f);
|
||||
float3 colHigh = float3(0.65f, 0.25f, 0.95f);
|
||||
float t1 = smoothstep(0.0f, 0.45f, h);
|
||||
float t2 = smoothstep(0.35f, 1.0f, h);
|
||||
float3 baseCol = lerp(lerp(colLow, colMid, t1), colHigh, t2);
|
||||
baseCol += sin(float3(0.0f, 1.0f, 2.0f) + h * 6.0f + rp.colorJitter) * 0.06f;
|
||||
baseCol = max(baseCol, float3(0.0f));
|
||||
|
||||
float3 mouseCol = float3(0.15f, 0.75f, 1.0f);
|
||||
float3 stepColor = lerp(baseCol, mouseCol, saturate(trailField * 1.5f));
|
||||
float3 mouseCol = float3(0.15f, 0.75f, 1.0f);
|
||||
float3 stepColor = lerp(baseCol, mouseCol, saturate(trailField * 1.5f));
|
||||
|
||||
float absorption = exp(-accAlpha * 2.0f);
|
||||
accColor += stepColor * density * absorption;
|
||||
accAlpha += density * 0.05f;
|
||||
}
|
||||
float absorption = exp(-accAlpha * 2.0f);
|
||||
accColor += stepColor * density * absorption;
|
||||
accAlpha += density * 0.05f;
|
||||
}
|
||||
|
||||
accColor *= AURORA_INTENSITY * rp.intensityMul;
|
||||
accColor *= AURORA_INTENSITY * rp.intensityMul;
|
||||
|
||||
return float4(accColor, saturate(accAlpha));
|
||||
return float4(accColor, saturate(accAlpha));
|
||||
}
|
||||
|
||||
// === SMOOTH CUTOFF ===
|
||||
|
||||
float smoothCutoff(float value, float floor_, float ceiling) {
|
||||
float t = saturate((value - floor_) / max(ceiling - floor_, 0.001f));
|
||||
return t * t * (3.0f - 2.0f * t);
|
||||
float
|
||||
smoothCutoff(float value, float floor_, float ceiling) {
|
||||
float t = saturate((value - floor_) / max(ceiling - floor_, 0.001f));
|
||||
return t * t * (3.0f - 2.0f * t);
|
||||
}
|
||||
|
||||
// === ENTRY POINT ===
|
||||
|
||||
public
|
||||
float4 fragment_main(float4 color, KittyTextures t, KittyCustomShaderData d) {
|
||||
float2 pixelDims = float2(d.viewport_size_pixels) * t.viewport.zw;
|
||||
float timestamp = fmod(d.timestamp, 86400.0f) * TIME_SCALE;
|
||||
public float4
|
||||
fragment_main(float4 color, KittyTextures t, KittyCustomShaderData d) {
|
||||
float2 pixelDims = float2(d.viewport_size_pixels) * t.viewport.zw;
|
||||
float timestamp = fmod(d.timestamp, 86400.0f) * TIME_SCALE;
|
||||
|
||||
float2 uv = t.pos;
|
||||
float aspect = pixelDims.x / max(pixelDims.y, 1.0f);
|
||||
float2 uv = t.pos;
|
||||
float aspect = pixelDims.x / max(pixelDims.y, 1.0f);
|
||||
|
||||
float2 mouseUV = (d.mouse_pos.xy - t.viewport.xy) / max(t.viewport.zw, float2(1e-5f, 1e-5f));
|
||||
bool inWindow = all(mouseUV >= float2(0.0f)) && all(mouseUV <= float2(1.0f));
|
||||
float mouseValid = float(inWindow);
|
||||
if (MOUSE_IGNORE_WHEN_HIDDEN > 0.5f && d.mouse_pointer_hidden > 0.5f)
|
||||
mouseValid = 0.0f;
|
||||
float2 mouseUV = (d.mouse_pos.xy - t.viewport.xy) / max(t.viewport.zw, float2(1e-5f, 1e-5f));
|
||||
bool inWindow = all(mouseUV >= float2(0.0f)) && all(mouseUV <= float2(1.0f));
|
||||
float mouseValid = float(inWindow);
|
||||
if (MOUSE_IGNORE_WHEN_HIDDEN > 0.5f && d.mouse_pointer_hidden > 0.5f) mouseValid = 0.0f;
|
||||
|
||||
// First group: Accumulate radial aurora rays cast from sky center into scratch texture 'a'
|
||||
if (STAGE == 0) {
|
||||
float prev = t.persist.Sample(uv).r;
|
||||
float decayed = prev * saturate(1.0f - ACCUMULATION_DECAY);
|
||||
// First group: Accumulate radial aurora rays cast from sky center into scratch texture 'a'
|
||||
if (STAGE == 0) {
|
||||
float prev = t.persist.Sample(uv).r;
|
||||
float decayed = prev * saturate(1.0f - ACCUMULATION_DECAY);
|
||||
|
||||
float deposit = 0.0f;
|
||||
if (mouseValid > 0.5f && d.mouse_button_pressed.x > 0.5f) {
|
||||
// Aspect-corrected UVs relative to screen center (0.5, 0.5)
|
||||
float2 cUV = (uv - 0.5f) * float2(aspect, 1.0f);
|
||||
float2 mUV = (mouseUV - 0.5f) * float2(aspect, 1.0f);
|
||||
float deposit = 0.0f;
|
||||
if (mouseValid > 0.5f && d.mouse_button_pressed.x > 0.5f) {
|
||||
// Aspect-corrected UVs relative to screen center (0.5, 0.5)
|
||||
float2 cUV = (uv - 0.5f) * float2(aspect, 1.0f);
|
||||
float2 mUV = (mouseUV - 0.5f) * float2(aspect, 1.0f);
|
||||
|
||||
// Radial direction vector from sky center through the mouse click
|
||||
float mLen = length(mUV);
|
||||
float2 mDir = (mLen > 0.0001f) ? (mUV / mLen) : float2(0.0f, 1.0f);
|
||||
float2 mTangent = float2(-mDir.y, mDir.x); // Perpendicular to radial ray
|
||||
// Radial direction vector from sky center through the mouse click
|
||||
float mLen = length(mUV);
|
||||
float2 mDir = (mLen > 0.0001f) ? (mUV / mLen) : float2(0.0f, 1.0f);
|
||||
float2 mTangent = float2(-mDir.y, mDir.x); // Perpendicular to radial ray
|
||||
|
||||
// Difference vector from click point to current pixel
|
||||
float2 diff = cUV - mUV;
|
||||
// Difference vector from click point to current pixel
|
||||
float2 diff = cUV - mUV;
|
||||
|
||||
// Project onto radial (along) and tangential (across) axes
|
||||
float distAlongRay = dot(diff, mDir);
|
||||
float distAcrossRay = dot(diff, mTangent);
|
||||
// Project onto radial (along) and tangential (across) axes
|
||||
float distAlongRay = dot(diff, mDir);
|
||||
float distAcrossRay = dot(diff, mTangent);
|
||||
|
||||
// Asymmetric ray length extending outward from the click point
|
||||
float yMax = (distAlongRay >= 0.0f) ? MOUSE_RAY_LENGTH : (MOUSE_RAY_LENGTH * 0.25f);
|
||||
// Asymmetric ray length extending outward from the click point
|
||||
float yMax = (distAlongRay >= 0.0f) ? MOUSE_RAY_LENGTH : (MOUSE_RAY_LENGTH * 0.25f);
|
||||
|
||||
float hDist = abs(distAcrossRay) / max(MOUSE_RAY_WIDTH, 0.001f);
|
||||
float vDist = abs(distAlongRay) / max(yMax, 0.001f);
|
||||
float hDist = abs(distAcrossRay) / max(MOUSE_RAY_WIDTH, 0.001f);
|
||||
float vDist = abs(distAlongRay) / max(yMax, 0.001f);
|
||||
|
||||
// High-frequency curtain thread streaking along the ray width
|
||||
float streaks1 = sin(distAcrossRay * MOUSE_RAY_FREQUENCY) * 0.35f + 0.65f;
|
||||
float streaks2 = cos(distAcrossRay * MOUSE_RAY_FREQUENCY * 2.3f) * 0.25f + 0.75f;
|
||||
// High-frequency curtain thread streaking along the ray width
|
||||
float streaks1 = sin(distAcrossRay * MOUSE_RAY_FREQUENCY) * 0.35f + 0.65f;
|
||||
float streaks2 = cos(distAcrossRay * MOUSE_RAY_FREQUENCY * 2.3f) * 0.25f + 0.75f;
|
||||
|
||||
float hFalloff = smoothstep(1.0f, 0.0f, hDist);
|
||||
float vFalloff = smoothstep(1.0f, 0.0f, vDist);
|
||||
float hFalloff = smoothstep(1.0f, 0.0f, hDist);
|
||||
float vFalloff = smoothstep(1.0f, 0.0f, vDist);
|
||||
|
||||
deposit = hFalloff * vFalloff * streaks1 * streaks2 * MOUSE_PRESS_BOOST;
|
||||
deposit = hFalloff * vFalloff * streaks1 * streaks2 * MOUSE_PRESS_BOOST;
|
||||
}
|
||||
|
||||
return float4(saturate(decayed + deposit), 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
return float4(saturate(decayed + deposit), 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
// Second group: Copy scratch texture 'a' to 'persist'
|
||||
if (STAGE == 1) { return t.a.Sample(uv); }
|
||||
|
||||
// Second group: Copy scratch texture 'a' to 'persist'
|
||||
if (STAGE == 1) {
|
||||
return t.a.Sample(uv);
|
||||
}
|
||||
// Third group: Main composite pass
|
||||
AuroraRandParams rp = getAuroraParams(d.timestamp, INITIAL_RANDOM_SEED);
|
||||
float epochBrightness = transitionBrightness(d.timestamp);
|
||||
float noiseTime = timestamp + rp.timeOffset;
|
||||
|
||||
// Third group: Main composite pass
|
||||
AuroraRandParams rp = getAuroraParams(d.timestamp, INITIAL_RANDOM_SEED);
|
||||
float epochBrightness = transitionBrightness(d.timestamp);
|
||||
float noiseTime = timestamp + rp.timeOffset;
|
||||
float2 fragCoord = uv * pixelDims;
|
||||
|
||||
float2 fragCoord = uv * pixelDims;
|
||||
float persistentTrail = t.persist.Sample(uv).r * MOUSE_PERSIST_INTENSITY;
|
||||
|
||||
float persistentTrail = t.persist.Sample(uv).r * MOUSE_PERSIST_INTENSITY;
|
||||
float3 ro = float3(0.0f, 0.0f, -CAMERA_DISTANCE);
|
||||
float2 centeredUV = uv - 0.5f;
|
||||
|
||||
float3 ro = float3(0.0f, 0.0f, -CAMERA_DISTANCE);
|
||||
float2 centeredUV = uv - 0.5f;
|
||||
float horizonRadius = 1.5f;
|
||||
|
||||
float horizonRadius = 1.5f;
|
||||
float spinAngle = timestamp * 0.02f;
|
||||
float cs = cos(spinAngle), ss = sin(spinAngle);
|
||||
|
||||
float spinAngle = timestamp * 0.02f;
|
||||
float cs = cos(spinAngle), ss = sin(spinAngle);
|
||||
float3 rd = zenithRayDir(centeredUV, aspect, horizonRadius, cs, ss);
|
||||
|
||||
float3 rd = zenithRayDir(centeredUV, aspect, horizonRadius, cs, ss);
|
||||
float3 bgCol = lerp(SKY_COLOR_TOP, SKY_COLOR_BOTTOM, 1.0f - rd.y) * 0.63f;
|
||||
float3 col = bgCol;
|
||||
|
||||
float3 bgCol = lerp(SKY_COLOR_TOP, SKY_COLOR_BOTTOM, 1.0f - rd.y) * 0.63f;
|
||||
float3 col = bgCol;
|
||||
float2 mouseWorld = float2(0.0f, 0.0f);
|
||||
|
||||
float2 mouseWorld = float2(0.0f, 0.0f);
|
||||
if (mouseValid > 0.5f) {
|
||||
float2 mCenteredUV = mouseUV - 0.5f;
|
||||
float3 mrd = zenithRayDir(mCenteredUV, aspect, horizonRadius, cs, ss);
|
||||
|
||||
if (mouseValid > 0.5f) {
|
||||
float2 mCenteredUV = mouseUV - 0.5f;
|
||||
float3 mrd = zenithRayDir(mCenteredUV, aspect, horizonRadius, cs, ss);
|
||||
|
||||
float denom = mrd.y * 2.0f + 0.4f;
|
||||
if (denom > 0.001f) {
|
||||
float dist = (AURORA_ALTITUDE - ro.y) / denom;
|
||||
mouseWorld = (ro + mrd * dist).xz;
|
||||
float denom = mrd.y * 2.0f + 0.4f;
|
||||
if (denom > 0.001f) {
|
||||
float dist = (AURORA_ALTITUDE - ro.y) / denom;
|
||||
mouseWorld = (ro + mrd * dist).xz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float genStrength = MOUSE_AURORA_INTENSITY *
|
||||
(1.0f + d.mouse_button_pressed.x * MOUSE_PRESS_BOOST);
|
||||
float genStrength = MOUSE_AURORA_INTENSITY * (1.0f + d.mouse_button_pressed.x * MOUSE_PRESS_BOOST);
|
||||
|
||||
float4 aur = smoothstep(0.0f, 1.5f,
|
||||
rayMarchAurora(ro, rd, fragCoord, noiseTime, rp,
|
||||
mouseWorld, mouseValid, genStrength, persistentTrail));
|
||||
col += sampleStars(rd, pixelDims, timestamp);
|
||||
col = col * (1.0f - aur.a) + aur.rgb;
|
||||
float4 aur = smoothstep(0.0f, 1.5f, rayMarchAurora(ro, rd, fragCoord, noiseTime, rp, mouseWorld, mouseValid, genStrength, persistentTrail));
|
||||
col += sampleStars(rd, pixelDims, timestamp);
|
||||
col = col * (1.0f - aur.a) + aur.rgb;
|
||||
|
||||
col *= EFFECT_INTENSITY * epochBrightness;
|
||||
col *= EFFECT_INTENSITY * epochBrightness;
|
||||
|
||||
float effectLum = dot(col, float3(0.299f, 0.587f, 0.114f));
|
||||
float gate = smoothCutoff(effectLum, EFFECT_FLOOR, EFFECT_CEILING);
|
||||
col *= gate;
|
||||
float effectLum = dot(col, float3(0.299f, 0.587f, 0.114f));
|
||||
float gate = smoothCutoff(effectLum, EFFECT_FLOOR, EFFECT_CEILING);
|
||||
col *= gate;
|
||||
|
||||
float4 terminalColor = t.backbuffer.Sample(t.pos);
|
||||
float termLum = dot(terminalColor.rgb, float3(0.299f, 0.587f, 0.114f));
|
||||
float isBlack = step(termLum, 0.001f);
|
||||
float textPreserve = 1.0f - smoothstep(BLACK_BLEND_THRESHOLD,
|
||||
BLACK_BLEND_THRESHOLD + 0.2f, termLum);
|
||||
float blendFactor = lerp(textPreserve * EFFECT_INTENSITY, 1.0f, isBlack);
|
||||
float3 blendedColor = terminalColor.rgb + col * blendFactor;
|
||||
float4 terminalColor = t.backbuffer.Sample(t.pos);
|
||||
float termLum = dot(terminalColor.rgb, float3(0.299f, 0.587f, 0.114f));
|
||||
float isBlack = step(termLum, 0.001f);
|
||||
float textPreserve = 1.0f - smoothstep(BLACK_BLEND_THRESHOLD, BLACK_BLEND_THRESHOLD + 0.2f, termLum);
|
||||
float blendFactor = lerp(textPreserve * EFFECT_INTENSITY, 1.0f, isBlack);
|
||||
float3 blendedColor = terminalColor.rgb + col * blendFactor;
|
||||
|
||||
if (DEBUG_MOUSE_OVERLAY > 0.5f && mouseValid > 0.5f) {
|
||||
float ptProxy = (AURORA_ALTITUDE - ro.y) / (rd.y * 2.0f + 0.4f);
|
||||
float g = mouseTrailField(ro + rd * ptProxy, mouseWorld, 1.0f, genStrength);
|
||||
blendedColor =
|
||||
lerp(blendedColor, float3(1.0f, 0.25f, 0.05f), saturate(g * 2.0f));
|
||||
}
|
||||
if (DEBUG_MOUSE_OVERLAY > 0.5f && mouseValid > 0.5f) {
|
||||
float ptProxy = (AURORA_ALTITUDE - ro.y) / (rd.y * 2.0f + 0.4f);
|
||||
float g = mouseTrailField(ro + rd * ptProxy, mouseWorld, 1.0f, genStrength);
|
||||
blendedColor = lerp(blendedColor, float3(1.0f, 0.25f, 0.05f), saturate(g * 2.0f));
|
||||
}
|
||||
|
||||
return float4(blendedColor, terminalColor.a);
|
||||
return float4(blendedColor, terminalColor.a);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,14 +17,10 @@ public struct BlitOutput {
|
|||
#define bottom 3
|
||||
|
||||
// Static constant array mapping vertex IDs
|
||||
static const int2 vertex_pos_map[4] = {
|
||||
{right, top},
|
||||
{right, bottom},
|
||||
{left, bottom},
|
||||
{left, top}
|
||||
};
|
||||
static const int2 vertex_pos_map[4] = { { right, top }, { right, bottom }, { left, bottom }, { left, top } };
|
||||
|
||||
BlitOutput get_coords_for_blit(uint vertex_id, float4 src_rect, float4 dest_rect) {
|
||||
BlitOutput
|
||||
get_coords_for_blit(uint vertex_id, float4 src_rect, float4 dest_rect) {
|
||||
int2 pos = vertex_pos_map[vertex_id];
|
||||
BlitOutput output;
|
||||
output.texcoord = float2(src_rect[pos.x], src_rect[pos.y]);
|
||||
|
|
@ -36,23 +32,27 @@ BlitOutput get_coords_for_blit(uint vertex_id, float4 src_rect, float4 dest_rect
|
|||
public ConstantBuffer<KittyCustomShaderData> csd;
|
||||
|
||||
|
||||
public float4 pipeline_vertex_main(uint vertex_id) {
|
||||
public float4
|
||||
pipeline_vertex_main(uint vertex_id) {
|
||||
BlitOutput ans = get_coords_for_blit(vertex_id, csd.src_rect, csd.dest_rect);
|
||||
return float4(ans.texcoord[0], ans.texcoord[1], ans.position[0], ans.position[1]);
|
||||
}
|
||||
|
||||
float4 vec4_premul(float3 rgb, float a) {
|
||||
float4
|
||||
vec4_premul(float3 rgb, float a) {
|
||||
return float4(rgb * a, a);
|
||||
}
|
||||
|
||||
float linear2srgb(float x) { // scalar
|
||||
float
|
||||
linear2srgb(float x) { // scalar
|
||||
float lower = 12.92 * x;
|
||||
float upper = 1.055 * pow(x, 1.0f / 2.4f) - 0.055f;
|
||||
|
||||
return lerp(lower, upper, step(0.0031308f, x));
|
||||
}
|
||||
|
||||
float3 linear2srgb(float3 x) { // vector
|
||||
float3
|
||||
linear2srgb(float3 x) { // vector
|
||||
float3 lower = 12.92 * x;
|
||||
float3 upper = 1.055 * pow(x, float3(1.0f / 2.4f)) - 0.055f;
|
||||
|
||||
|
|
@ -61,11 +61,11 @@ float3 linear2srgb(float3 x) { // vector
|
|||
|
||||
uniform Sampler2D backbuffer, a, b, persist;
|
||||
|
||||
public float4 pipeline_fragment_main(float2 backbuffer_pos, int group, float4 viewport, float animation_progress, bool convert_to_srgb) {
|
||||
float4 color = backbuffer.Sample(backbuffer_pos); // pre multiplied linear RGB
|
||||
color = float4(color.rgb / color.a, color.a); // un pre multiplied color passed through pipeline
|
||||
KittyTextures t = {backbuffer, a, b, persist, backbuffer_pos, viewport, animation_progress, group};
|
||||
public float4
|
||||
pipeline_fragment_main(float2 backbuffer_pos, int group, float4 viewport, float animation_progress, bool convert_to_srgb) {
|
||||
float4 color = backbuffer.Sample(backbuffer_pos); // pre multiplied linear RGB
|
||||
color = float4(color.rgb / color.a, color.a); // un pre multiplied color passed through pipeline
|
||||
KittyTextures t = { backbuffer, a, b, persist, backbuffer_pos, viewport, animation_progress, group };
|
||||
// PIPELINE
|
||||
return vec4_premul(color.rgb, color.a);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,37 +9,34 @@
|
|||
import kitty_custom_shader_types;
|
||||
|
||||
// Maximum wavefront radius at animation_progress=1 (aspect-corrected UV units).
|
||||
static const float WAVE_SPEED = 0.45;
|
||||
static const float WAVE_SPEED = 0.45;
|
||||
// Spatial frequency of the rings (cycles per aspect-corrected UV unit).
|
||||
static const float WAVE_FREQUENCY = 14.0;
|
||||
static const float WAVE_FREQUENCY = 14.0;
|
||||
// Starting half-width of the Gaussian envelope (expands as animation_progress increases).
|
||||
static const float WAVE_WIDTH = 0.055;
|
||||
static const float WAVE_WIDTH = 0.055;
|
||||
// Peak radial UV displacement at the wavecrest.
|
||||
static const float AMPLITUDE = 0.010;
|
||||
static const float AMPLITUDE = 0.010;
|
||||
// Scale applied to the wave gradient when constructing the surface normal.
|
||||
static const float NORMAL_SCALE = 8.0;
|
||||
static const float NORMAL_SCALE = 8.0;
|
||||
// Blinn-Phong shininess exponent — higher values give a sharper, more mirror-like glint.
|
||||
static const float SHININESS = 64.0;
|
||||
static const float SHININESS = 64.0;
|
||||
// Peak specular contribution at the wave crest facing the light.
|
||||
static const float SPECULAR_STRENGTH = 0.40;
|
||||
// Subtle diffuse shading that rounds each ring into a 3D ridge.
|
||||
static const float DIFFUSE_STRENGTH = 0.10;
|
||||
static const float DIFFUSE_STRENGTH = 0.10;
|
||||
|
||||
public float4 fragment_main(
|
||||
float4 color,
|
||||
KittyTextures t,
|
||||
KittyCustomShaderData d
|
||||
) {
|
||||
public float4
|
||||
fragment_main(float4 color, KittyTextures t, KittyCustomShaderData d) {
|
||||
float2 pixelDims = float2(d.viewport_size_pixels) * t.viewport.zw;
|
||||
float aspect = pixelDims.x / pixelDims.y;
|
||||
float aspect = pixelDims.x / pixelDims.y;
|
||||
|
||||
// d.mouse_pos.zw is the UV position of the last left-button press (y=0 at bottom).
|
||||
float2 center = d.mouse_pos.zw;
|
||||
|
||||
// Aspect-corrected vector from the click center to this pixel.
|
||||
float2 delta = (t.pos - center) * float2(aspect, 1.0);
|
||||
float dist = length(delta);
|
||||
float2 dir = delta / max(dist, 1e-5);
|
||||
float dist = length(delta);
|
||||
float2 dir = delta / max(dist, 1e-5);
|
||||
|
||||
// Wavefront radius advances linearly with animation_progress.
|
||||
float front = WAVE_SPEED * t.animation_progress;
|
||||
|
|
@ -49,7 +46,7 @@ public float4 fragment_main(
|
|||
|
||||
// Gaussian spatial envelope centered at the wavefront; grows in width over time.
|
||||
float sigma = WAVE_WIDTH * (1.0 + t.animation_progress);
|
||||
float env = exp(-behind * behind / (2.0 * sigma * sigma));
|
||||
float env = exp(-behind * behind / (2.0 * sigma * sigma));
|
||||
|
||||
// Causality: suppress any energy ahead of the wavefront.
|
||||
env *= 1.0 - smoothstep(-0.01, 0.02, behind);
|
||||
|
|
@ -57,7 +54,7 @@ public float4 fragment_main(
|
|||
// Temporal amplitude decay as the wave expands outward.
|
||||
float decay = pow(1.0 - t.animation_progress, 0.7);
|
||||
|
||||
float k = WAVE_FREQUENCY * 6.28318530718;
|
||||
float k = WAVE_FREQUENCY * 6.28318530718;
|
||||
float wave = sin(behind * k);
|
||||
|
||||
// Analytic derivative of wave height h = wave * env * decay w.r.t. dist.
|
||||
|
|
@ -77,22 +74,17 @@ public float4 fragment_main(
|
|||
// Blinn-Phong half-vector.
|
||||
float3 H = normalize(L + V);
|
||||
|
||||
float diffuse = max(dot(N, L), 0.0);
|
||||
float diffuse = max(dot(N, L), 0.0);
|
||||
float specular = pow(max(dot(N, H), 0.0), SHININESS);
|
||||
|
||||
// Radial UV displacement: push pixels away from center at crests, pull inward at troughs.
|
||||
float2 warpedUV = clamp(
|
||||
t.pos + dir * (wave * env * decay * AMPLITUDE),
|
||||
float2(0.0), float2(1.0)
|
||||
);
|
||||
float2 warpedUV = clamp(t.pos + dir * (wave * env * decay * AMPLITUDE), float2(0.0), float2(1.0));
|
||||
|
||||
// Sample the terminal backbuffer at the displaced position.
|
||||
float4 result = t.backbuffer.Sample(warpedUV);
|
||||
|
||||
// 3D lighting: diffuse rounds each ring into a ridge, specular gives directional glints.
|
||||
float lighting = 1.0
|
||||
+ diffuse * DIFFUSE_STRENGTH * env * decay
|
||||
+ specular * SPECULAR_STRENGTH * env * decay;
|
||||
float lighting = 1.0 + diffuse * DIFFUSE_STRENGTH * env * decay + specular * SPECULAR_STRENGTH * env * decay;
|
||||
result.rgb *= lighting;
|
||||
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@
|
|||
|
||||
import kitty_custom_shader_types;
|
||||
|
||||
public float4 fragment_main(
|
||||
static const float FACTOR = 2;
|
||||
|
||||
// START_FUNCTION_SIGNATURE
|
||||
public float4
|
||||
fragment_main(
|
||||
// The color from the previous custom shader in this group or from the
|
||||
// backbuffer if this is the first shader in the group
|
||||
float4 color,
|
||||
|
|
@ -13,8 +17,7 @@ public float4 fragment_main(
|
|||
KittyTextures t,
|
||||
|
||||
// See types.slang for details on the data in this structure
|
||||
KittyCustomShaderData d
|
||||
)
|
||||
{ // END_FUNCTION_SIGNATURE
|
||||
return float4(color.r, min(max(0.1, color.g) * 2, 1), color.b, color.a);
|
||||
KittyCustomShaderData d) {
|
||||
// END_FUNCTION_SIGNATURE
|
||||
return float4(color.r, min(max(0.1, color.g) * FACTOR, 1), color.b, color.a);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,42 +7,36 @@
|
|||
|
||||
import kitty_custom_shader_types;
|
||||
|
||||
static const float SPOTLIGHT_RADIUS = 0.25; // spotlight radius in UV units
|
||||
static const float SPOTLIGHT_SOFTNESS = 20.0; // edge sharpness; higher = sharper
|
||||
static const float AMBIENT_LIGHT = 0.5; // minimum brightness outside the spotlight
|
||||
static const float SPOTLIGHT_SPEED = 1.0; // oscillation speed in random-motion mode
|
||||
static const float SPOTLIGHT_RADIUS = 0.25; // spotlight radius in UV units
|
||||
static const float SPOTLIGHT_SOFTNESS = 20.0; // edge sharpness; higher = sharper
|
||||
static const float AMBIENT_LIGHT = 0.5; // minimum brightness outside the spotlight
|
||||
static const float SPOTLIGHT_SPEED = 1.0; // oscillation speed in random-motion mode
|
||||
// Set to 1 to follow the mouse, 0 to use random oscillation
|
||||
static const int USE_MOUSE = 1;
|
||||
static const int USE_MOUSE = 1;
|
||||
// When USE_MOUSE=1 and the mouse leaves the window:
|
||||
// 0 = fall back to random oscillation
|
||||
// 1 = clamp spotlight to the nearest window edge
|
||||
// 2 = disable spotlight (pass through unchanged pixels)
|
||||
static const int MOUSE_LEAVE_BEHAVIOR = 2;
|
||||
static const int MOUSE_LEAVE_BEHAVIOR = 2;
|
||||
// Set to 1 to pass through unchanged pixels when the mouse pointer is hidden
|
||||
static const int HIDE_WHEN_POINTER_HIDDEN = 1;
|
||||
static const int HIDE_WHEN_POINTER_HIDDEN = 1;
|
||||
|
||||
public float4 fragment_main(
|
||||
float4 color,
|
||||
KittyTextures t,
|
||||
KittyCustomShaderData d
|
||||
) {
|
||||
public float4
|
||||
fragment_main(float4 color, KittyTextures t, KittyCustomShaderData d) {
|
||||
if (HIDE_WHEN_POINTER_HIDDEN == 1 && d.mouse_pointer_hidden != 0.0) return color;
|
||||
float2 uv = t.pos;
|
||||
|
||||
// Viewport pixel dimensions for aspect-ratio correction
|
||||
float2 pixelDims = float2(d.viewport_size_pixels) * t.viewport.zw;
|
||||
float aspectRatio = pixelDims.x / pixelDims.y;
|
||||
float2 pixelDims = float2(d.viewport_size_pixels) * t.viewport.zw;
|
||||
float aspectRatio = pixelDims.x / pixelDims.y;
|
||||
|
||||
// Random oscillating center (different frequencies and phases on each axis)
|
||||
float time = d.timestamp * SPOTLIGHT_SPEED;
|
||||
float2 randomCenter = float2(
|
||||
0.5 + 0.4 * sin(time),
|
||||
0.5 + 0.4 * sin(time * 1.3 + 3.14159)
|
||||
);
|
||||
float time = d.timestamp * SPOTLIGHT_SPEED;
|
||||
float2 randomCenter = float2(0.5 + 0.4 * sin(time), 0.5 + 0.4 * sin(time * 1.3 + 3.14159));
|
||||
|
||||
// Mouse is valid only when both coords are inside the OS window [0, 1]
|
||||
float2 mp = d.mouse_pos.xy;
|
||||
float mouseInWindow = float(all(mp >= float2(0.0)) && all(mp <= float2(1.0)));
|
||||
float2 mp = d.mouse_pos.xy;
|
||||
float mouseInWindow = float(all(mp >= float2(0.0)) && all(mp <= float2(1.0)));
|
||||
|
||||
// Disable spotlight entirely when mouse leaves the window
|
||||
if (USE_MOUSE == 1 && MOUSE_LEAVE_BEHAVIOR == 2 && mouseInWindow == 0.0) return color;
|
||||
|
|
@ -51,18 +45,14 @@ public float4 fragment_main(
|
|||
float2 outsideFallback = lerp(randomCenter, clamp(mp, float2(0.0), float2(1.0)), float(MOUSE_LEAVE_BEHAVIOR == 1 ? 1 : 0));
|
||||
|
||||
// Branchless center selection
|
||||
float2 mouseCenter = lerp(outsideFallback, mp, mouseInWindow);
|
||||
float2 mouseCenter = lerp(outsideFallback, mp, mouseInWindow);
|
||||
float2 spotlightCenter = lerp(randomCenter, mouseCenter, float(USE_MOUSE));
|
||||
|
||||
// Euclidean distance in aspect-ratio-corrected space (produces a circular spotlight)
|
||||
float distToCenter = length((uv - spotlightCenter) * float2(aspectRatio, 1.0));
|
||||
|
||||
// Soft spotlight edge
|
||||
float spotlightIntensity = smoothstep(
|
||||
SPOTLIGHT_RADIUS,
|
||||
SPOTLIGHT_RADIUS - (1.0 / SPOTLIGHT_SOFTNESS),
|
||||
distToCenter
|
||||
);
|
||||
float spotlightIntensity = smoothstep(SPOTLIGHT_RADIUS, SPOTLIGHT_RADIUS - (1.0 / SPOTLIGHT_SOFTNESS), distToCenter);
|
||||
|
||||
// Blend between ambient and full illumination
|
||||
float3 result = color.rgb * lerp(float3(AMBIENT_LIGHT), float3(1.0), spotlightIntensity);
|
||||
|
|
|
|||
|
|
@ -27,12 +27,13 @@ static const float EDGE_SOFTNESS = 0.04;
|
|||
|
||||
// Returns a value in [0, 1] for this pixel: 0 at the tab-bar edge of the
|
||||
// content area, 1 at the opposite edge. The wipe sweeps from 0 toward 1.
|
||||
float wipe_pixel_pos(float2 uv, float4 ca) {
|
||||
float gap_left = ca.x;
|
||||
float gap_right = 1.0 - (ca.x + ca.z);
|
||||
float
|
||||
wipe_pixel_pos(float2 uv, float4 ca) {
|
||||
float gap_left = ca.x;
|
||||
float gap_right = 1.0 - (ca.x + ca.z);
|
||||
float gap_bottom = ca.y;
|
||||
float gap_top = 1.0 - (ca.y + ca.w);
|
||||
float max_gap = max(max(gap_left, gap_right), max(gap_bottom, gap_top));
|
||||
float gap_top = 1.0 - (ca.y + ca.w);
|
||||
float max_gap = max(max(gap_left, gap_right), max(gap_bottom, gap_top));
|
||||
|
||||
float pos;
|
||||
if (max_gap == gap_top) {
|
||||
|
|
@ -51,11 +52,8 @@ float wipe_pixel_pos(float2 uv, float4 ca) {
|
|||
return clamp(pos, 0.0, 1.0);
|
||||
}
|
||||
|
||||
public float4 fragment_main(
|
||||
float4 color,
|
||||
KittyTextures t,
|
||||
KittyCustomShaderData d
|
||||
) {
|
||||
public float4
|
||||
fragment_main(float4 color, KittyTextures t, KittyCustomShaderData d) {
|
||||
float4 ca = d.central_area;
|
||||
if (ca.z <= 0.0 || ca.w <= 0.0) return color;
|
||||
|
||||
|
|
@ -73,20 +71,20 @@ public float4 fragment_main(
|
|||
} else if (ANIMATION_TYPE == 2) {
|
||||
// BLINDS: strips opening in sequence from the tab-bar side
|
||||
float pixel_pos = wipe_pixel_pos(t.pos, ca);
|
||||
float inv_n = 1.0 / float(NUM_BLINDS);
|
||||
float inv_n = 1.0 / float(NUM_BLINDS);
|
||||
float strip_idx = floor(pixel_pos * float(NUM_BLINDS));
|
||||
float strip_start = strip_idx * inv_n;
|
||||
// Progress local to this strip: 0 when it starts opening, 1 when fully open
|
||||
float strip_p = clamp((p - strip_start) / inv_n, 0.0, 1.0);
|
||||
float strip_p = clamp((p - strip_start) / inv_n, 0.0, 1.0);
|
||||
// Position within the strip (0 at tab-bar side, 1 at far side)
|
||||
float local = fract(pixel_pos * float(NUM_BLINDS));
|
||||
float soft = 0.1;
|
||||
float local = fract(pixel_pos * float(NUM_BLINDS));
|
||||
float soft = 0.1;
|
||||
brightness = 1.0 - smoothstep(strip_p - soft, strip_p + soft, local);
|
||||
} else {
|
||||
// IRIS: circular reveal expanding from the centre of the content area
|
||||
float2 ca_center = ca.xy + ca.zw * 0.5;
|
||||
float half_diag = length(ca.zw * 0.5);
|
||||
float dist = length(t.pos - ca_center) / max(half_diag, 0.001);
|
||||
float half_diag = length(ca.zw * 0.5);
|
||||
float dist = length(t.pos - ca_center) / max(half_diag, 0.001);
|
||||
brightness = 1.0 - smoothstep(p - EDGE_SOFTNESS, p + EDGE_SOFTNESS, dist);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,17 +12,15 @@ static const float RESOLUTION = 4.0;
|
|||
// strength of the effect
|
||||
static const float STRENGTH = 0.5;
|
||||
|
||||
void scanline(inout float3 color, float2 pixel_pos) {
|
||||
void
|
||||
scanline(inout float3 color, float2 pixel_pos) {
|
||||
float scanline = step(1.2, fmod(pixel_pos.y, RESOLUTION));
|
||||
float grille = step(1.2, fmod(pixel_pos.x, RESOLUTION));
|
||||
float grille = step(1.2, fmod(pixel_pos.x, RESOLUTION));
|
||||
color *= max(1.0 - STRENGTH, scanline * grille);
|
||||
}
|
||||
|
||||
public float4 fragment_main(
|
||||
float4 color,
|
||||
KittyTextures t,
|
||||
KittyCustomShaderData d
|
||||
) {
|
||||
public float4
|
||||
fragment_main(float4 color, KittyTextures t, KittyCustomShaderData d) {
|
||||
float2 pixel_pos = t.pos * float2(d.viewport_size_pixels);
|
||||
float3 c = color.rgb;
|
||||
scanline(c, pixel_pos);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
|
||||
public struct KittyCustomShaderData {
|
||||
public float4 src_rect, dest_rect; // used by the vertex shader internally
|
||||
public float4 src_rect, dest_rect; // used by the vertex shader internally
|
||||
|
||||
// global background/foreground colors from kitty options (linear RGB, alpha=1)
|
||||
public float4 background, foreground;
|
||||
|
|
@ -39,8 +39,8 @@ public struct KittyCustomShaderData {
|
|||
// Corner order: 0=top-right, 1=bottom-right, 2=bottom-left, 3=top-left.
|
||||
// Use animation_start cursor-trail-move / animation_stop cursor-trail-stop to activate.
|
||||
// animation_progress is NOT tied to trail duration; use cursor_trail_state.x for opacity instead.
|
||||
public float4 cursor_trail_corners_x; // UV x-coordinates of the 4 animated trail quad corners
|
||||
public float4 cursor_trail_corners_y; // UV y-coordinates of the 4 animated trail quad corners
|
||||
public float4 cursor_trail_corners_x; // UV x-coordinates of the 4 animated trail quad corners
|
||||
public float4 cursor_trail_corners_y; // UV y-coordinates of the 4 animated trail quad corners
|
||||
// .x=left, .y=right, .z=top, .w=bottom UV edges of the current cursor rectangle
|
||||
public float4 cursor_trail_edge;
|
||||
// .x=left, .y=right, .z=top, .w=bottom UV edges of the cursor rectangle before the most recent move.
|
||||
|
|
@ -61,12 +61,12 @@ public struct KittyCustomShaderData {
|
|||
// viewport currently being rendered too.
|
||||
public uint2 viewport_size_pixels;
|
||||
|
||||
public float mouse_pointer_hidden; // 1.0 if the mouse pointer is currently hidden, 0.0 if visible
|
||||
public float cursor_trail_state; // 1.0 if the cursor trail is actively animating, 0.0 otherwise
|
||||
public float mouse_pointer_hidden; // 1.0 if the mouse pointer is currently hidden, 0.0 if visible
|
||||
public float cursor_trail_state; // 1.0 if the cursor trail is actively animating, 0.0 otherwise
|
||||
|
||||
public float timestamp; // time in seconds since kitty was started (millisecond precision)
|
||||
public float last_rendered_at; // time of previous render in seconds since kitty was started (millisecond precision)
|
||||
public uint frame_counter; // cumulative frame counter increments by one every time a frame is fully rendered, first frame is zero
|
||||
public float timestamp; // time in seconds since kitty was started (millisecond precision)
|
||||
public float last_rendered_at; // time of previous render in seconds since kitty was started (millisecond precision)
|
||||
public uint frame_counter; // cumulative frame counter increments by one every time a frame is fully rendered, first frame is zero
|
||||
// Time (same epoch as `timestamp`) of the most recent cursor position change that triggered a trail.
|
||||
// Zero until the cursor has moved at least twice. Pair with cursor_trail_prev_edge.
|
||||
public float cursor_trail_change_time;
|
||||
|
|
@ -84,7 +84,7 @@ public struct KittyTextures {
|
|||
public Sampler2D b;
|
||||
public Sampler2D persist;
|
||||
|
||||
public float2 pos; // the position of this pixel in the textures (UV coordinates)
|
||||
public float2 pos; // the position of this pixel in the textures (UV coordinates)
|
||||
|
||||
// Some group related uniforms
|
||||
|
||||
|
|
|
|||
|
|
@ -11,87 +11,75 @@ import kitty_custom_shader_types;
|
|||
static const float BLACK_BLEND_THRESHOLD = 0.4;
|
||||
|
||||
// Ray 1 source position (as fractions of viewport dimensions)
|
||||
static const float RAY1_SRC_X = 0.7;
|
||||
static const float RAY1_SRC_Y = 1.1;
|
||||
static const float RAY1_SRC_X = 0.7;
|
||||
static const float RAY1_SRC_Y = 1.1;
|
||||
// Y component of ray 1 reference direction (X component is always 1.0)
|
||||
static const float RAY1_DIR_Y = 0.116;
|
||||
static const float RAY1_DIR_Y = 0.116;
|
||||
static const float RAY1_SEED_A = 36.2214;
|
||||
static const float RAY1_SEED_B = 21.11349;
|
||||
static const float RAY1_SPEED = 1.1;
|
||||
static const float RAY1_WEIGHT = 0.5; // contribution weight in final blend
|
||||
static const float RAY1_SPEED = 1.1;
|
||||
static const float RAY1_WEIGHT = 0.5; // contribution weight in final blend
|
||||
|
||||
// Ray 2 source position (as fractions of viewport dimensions)
|
||||
static const float RAY2_SRC_X = 0.8;
|
||||
static const float RAY2_SRC_Y = 1.2;
|
||||
static const float RAY2_DIR_Y = -0.241;
|
||||
static const float RAY2_SRC_X = 0.8;
|
||||
static const float RAY2_SRC_Y = 1.2;
|
||||
static const float RAY2_DIR_Y = -0.241;
|
||||
static const float RAY2_SEED_A = 22.39910;
|
||||
static const float RAY2_SEED_B = 18.0234;
|
||||
static const float RAY2_SPEED = 0.9;
|
||||
static const float RAY2_SPEED = 0.9;
|
||||
static const float RAY2_WEIGHT = 0.4;
|
||||
|
||||
// Per-channel depth-attenuation: channel *= BASE + brightness * SCALE
|
||||
static const float DEPTH_R_BASE = 0.05;
|
||||
static const float DEPTH_R_BASE = 0.05;
|
||||
static const float DEPTH_R_SCALE = 0.8;
|
||||
static const float DEPTH_G_BASE = 0.15;
|
||||
static const float DEPTH_G_BASE = 0.15;
|
||||
static const float DEPTH_G_SCALE = 0.6;
|
||||
static const float DEPTH_B_BASE = 0.3;
|
||||
static const float DEPTH_B_BASE = 0.3;
|
||||
static const float DEPTH_B_SCALE = 0.5;
|
||||
|
||||
// Overall strength of the ray overlay on dark terminal content
|
||||
static const float OVERLAY_STRENGTH = 0.3;
|
||||
|
||||
float hash21(float2 p) {
|
||||
float
|
||||
hash21(float2 p) {
|
||||
p = frac(p * float2(233.34, 851.73));
|
||||
p += dot(p, p + 23.45);
|
||||
return frac(p.x * p.y);
|
||||
}
|
||||
|
||||
float rayStrength(
|
||||
float2 raySource, float2 rayRefDir, float2 coord,
|
||||
float seedA, float seedB, float speed,
|
||||
float iTime, float resX
|
||||
) {
|
||||
float
|
||||
rayStrength(float2 raySource, float2 rayRefDir, float2 coord, float seedA, float seedB, float speed, float iTime, float resX) {
|
||||
float2 sourceToCoord = coord - raySource;
|
||||
float cosAngle = dot(normalize(sourceToCoord), rayRefDir);
|
||||
float dither = hash21(coord) * 0.015 - 0.0075;
|
||||
float ray = clamp(
|
||||
(0.45 + 0.15 * sin( cosAngle * seedA + iTime * speed)) +
|
||||
(0.30 + 0.20 * cos(-cosAngle * seedB + iTime * speed)) + dither,
|
||||
0.0, 1.0);
|
||||
float cosAngle = dot(normalize(sourceToCoord), rayRefDir);
|
||||
float dither = hash21(coord) * 0.015 - 0.0075;
|
||||
float ray = clamp((0.45 + 0.15 * sin(cosAngle * seedA + iTime * speed)) + (0.30 + 0.20 * cos(-cosAngle * seedB + iTime * speed)) + dither, 0.0, 1.0);
|
||||
float distFade = smoothstep(0.0, resX, resX - length(sourceToCoord));
|
||||
return ray * lerp(0.5, 1.0, distFade);
|
||||
}
|
||||
|
||||
public float4 fragment_main(
|
||||
float4 color,
|
||||
KittyTextures t,
|
||||
KittyCustomShaderData d
|
||||
) {
|
||||
public float4
|
||||
fragment_main(float4 color, KittyTextures t, KittyCustomShaderData d) {
|
||||
float2 iResolution = float2(d.viewport_size_pixels) * t.viewport.zw;
|
||||
float iTime = d.timestamp;
|
||||
float iTime = d.timestamp;
|
||||
|
||||
// Convert kitty UV (y=0 at bottom) to a top-left-origin pixel coordinate,
|
||||
// matching the original shader's internal coordinate system.
|
||||
float2 coord = float2(t.pos.x, 1.0 - t.pos.y) * iResolution;
|
||||
|
||||
float2 rayPos1 = float2(iResolution.x * RAY1_SRC_X, iResolution.y * RAY1_SRC_Y);
|
||||
float2 rayPos1 = float2(iResolution.x * RAY1_SRC_X, iResolution.y * RAY1_SRC_Y);
|
||||
float2 rayRefDir1 = normalize(float2(1.0, RAY1_DIR_Y));
|
||||
|
||||
float2 rayPos2 = float2(iResolution.x * RAY2_SRC_X, iResolution.y * RAY2_SRC_Y);
|
||||
float2 rayPos2 = float2(iResolution.x * RAY2_SRC_X, iResolution.y * RAY2_SRC_Y);
|
||||
float2 rayRefDir2 = normalize(float2(1.0, RAY2_DIR_Y));
|
||||
|
||||
float4 rays1 = float4(1.0, 1.0, 1.0, 0.0) *
|
||||
rayStrength(rayPos1, rayRefDir1, coord,
|
||||
RAY1_SEED_A, RAY1_SEED_B, RAY1_SPEED, iTime, iResolution.x);
|
||||
float4 rays1 = float4(1.0, 1.0, 1.0, 0.0) * rayStrength(rayPos1, rayRefDir1, coord, RAY1_SEED_A, RAY1_SEED_B, RAY1_SPEED, iTime, iResolution.x);
|
||||
|
||||
float4 rays2 = float4(1.0, 1.0, 1.0, 0.0) *
|
||||
rayStrength(rayPos2, rayRefDir2, coord,
|
||||
RAY2_SEED_A, RAY2_SEED_B, RAY2_SPEED, iTime, iResolution.x);
|
||||
float4 rays2 = float4(1.0, 1.0, 1.0, 0.0) * rayStrength(rayPos2, rayRefDir2, coord, RAY2_SEED_A, RAY2_SEED_B, RAY2_SPEED, iTime, iResolution.x);
|
||||
|
||||
float4 col = rays1 * RAY1_WEIGHT + rays2 * RAY2_WEIGHT;
|
||||
|
||||
// Attenuate toward the bottom (depth) with a blue-green tint
|
||||
float brightness = t.pos.y; // 0 at screen bottom (deep), 1 at top (surface)
|
||||
float brightness = t.pos.y; // 0 at screen bottom (deep), 1 at top (surface)
|
||||
col.r *= DEPTH_R_BASE + brightness * DEPTH_R_SCALE;
|
||||
col.g *= DEPTH_G_BASE + brightness * DEPTH_G_SCALE;
|
||||
col.b *= DEPTH_B_BASE + brightness * DEPTH_B_SCALE;
|
||||
|
|
@ -99,7 +87,7 @@ public float4 fragment_main(
|
|||
float4 terminalColor = t.backbuffer.Sample(t.pos);
|
||||
|
||||
// Overlay rays onto dark (near-black) terminal pixels; preserve bright content
|
||||
float alpha = step(length(terminalColor.rgb), BLACK_BLEND_THRESHOLD);
|
||||
float alpha = step(length(terminalColor.rgb), BLACK_BLEND_THRESHOLD);
|
||||
float3 blendedColor = lerp(terminalColor.rgb, col.rgb * OVERLAY_STRENGTH, alpha);
|
||||
|
||||
return float4(blendedColor, terminalColor.a);
|
||||
|
|
|
|||
|
|
@ -6,31 +6,26 @@
|
|||
|
||||
import kitty_custom_shader_types;
|
||||
|
||||
static const float TAU = 6.28318530718;
|
||||
static const int MAX_ITER = 6;
|
||||
static const float3 WATER_COLOR = float3(0.5, 0.5, 0.5); // water overlay tint
|
||||
static const float CAUSTIC_INTEN = 0.005; // caustic ripple intensity
|
||||
static const float UV_DISPLACEMENT = 0.04; // UV warp magnitude from caustics
|
||||
static const float TAU = 6.28318530718;
|
||||
static const int MAX_ITER = 6;
|
||||
static const float3 WATER_COLOR = float3(0.5, 0.5, 0.5); // water overlay tint
|
||||
static const float CAUSTIC_INTEN = 0.005; // caustic ripple intensity
|
||||
static const float UV_DISPLACEMENT = 0.04; // UV warp magnitude from caustics
|
||||
|
||||
public float4 fragment_main(
|
||||
float4 color,
|
||||
KittyTextures t,
|
||||
KittyCustomShaderData d
|
||||
) {
|
||||
float wtime = d.timestamp * 0.5 + 23.0;
|
||||
float2 uv = t.pos;
|
||||
public float4
|
||||
fragment_main(float4 color, KittyTextures t, KittyCustomShaderData d) {
|
||||
float wtime = d.timestamp * 0.5 + 23.0;
|
||||
float2 uv = t.pos;
|
||||
|
||||
float2 p = fmod(uv * TAU, TAU) - 250.0;
|
||||
float2 i = p;
|
||||
float c = 1.0;
|
||||
float c = 1.0;
|
||||
|
||||
[ForceUnroll]
|
||||
for (int n = 0; n < MAX_ITER; n++) {
|
||||
float tval = wtime * (1.0 - (3.5 / float(n + 1)));
|
||||
i = p + float2(cos(tval - i.x) + sin(tval + i.y),
|
||||
sin(tval - i.y) + cos(tval + i.x));
|
||||
c += 1.0 / length(float2(p.x / (sin(i.x + tval) / CAUSTIC_INTEN),
|
||||
p.y / (cos(i.y + tval) / CAUSTIC_INTEN)));
|
||||
i = p + float2(cos(tval - i.x) + sin(tval + i.y), sin(tval - i.y) + cos(tval + i.x));
|
||||
c += 1.0 / length(float2(p.x / (sin(i.x + tval) / CAUSTIC_INTEN), p.y / (cos(i.y + tval) / CAUSTIC_INTEN)));
|
||||
}
|
||||
c /= float(MAX_ITER);
|
||||
c = 1.17 - pow(c, 1.4);
|
||||
|
|
|
|||
|
|
@ -10,32 +10,25 @@ extern static const bool is_alpha_mask = false;
|
|||
extern static const bool texture_is_not_premultiplied = true;
|
||||
|
||||
|
||||
struct VSOutput
|
||||
{
|
||||
struct VSOutput {
|
||||
float2 texcoord : TEXCOORD;
|
||||
float4 position : SV_Position;
|
||||
};
|
||||
|
||||
|
||||
[shader("vertex")]
|
||||
VSOutput vertex_main(
|
||||
uint vertex_id : SV_VertexID,
|
||||
uniform float4 src_rect,
|
||||
uniform float4 dest_rect,
|
||||
) {
|
||||
VSOutput
|
||||
vertex_main(uint vertex_id: SV_VertexID, uniform float4 src_rect, uniform float4 dest_rect, ) {
|
||||
BlitOutput ans = get_coords_for_blit(vertex_id, src_rect, dest_rect);
|
||||
return {ans.texcoord, float4(ans.position[0], ans.position[1], 0.0, 1.0)};
|
||||
return { ans.texcoord, float4(ans.position[0], ans.position[1], 0.0, 1.0) };
|
||||
}
|
||||
|
||||
uniform Sampler2D image;
|
||||
|
||||
[shader("fragment")]
|
||||
float4 fragment_main(
|
||||
float2 texcoord : TEXCOORD,
|
||||
uniform float3 amask_fg,
|
||||
uniform float4 amask_bg_premult,
|
||||
uniform float extra_alpha
|
||||
) : SV_Target {
|
||||
float4
|
||||
fragment_main(float2 texcoord: TEXCOORD, uniform float3 amask_fg, uniform float4 amask_bg_premult, uniform float extra_alpha)
|
||||
: SV_Target {
|
||||
float4 color = image.Sample(texcoord);
|
||||
if (is_alpha_mask) {
|
||||
color = float4(amask_fg, color.r);
|
||||
|
|
|
|||
|
|
@ -5,48 +5,59 @@
|
|||
module hsluv;
|
||||
|
||||
// Helper Functions
|
||||
float divide(float num, float denom) {
|
||||
float
|
||||
divide(float num, float denom) {
|
||||
return num / (abs(denom) + 1e-15) * sign(denom);
|
||||
}
|
||||
|
||||
float3 divide(float3 num, float3 denom) {
|
||||
float3
|
||||
divide(float3 num, float3 denom) {
|
||||
return num / (abs(denom) + 1e-15) * sign(denom);
|
||||
}
|
||||
|
||||
float3 hsluv_intersectLineLine(float3 line1x, float3 line1y, float3 line2x, float3 line2y) {
|
||||
float3
|
||||
hsluv_intersectLineLine(float3 line1x, float3 line1y, float3 line2x, float3 line2y) {
|
||||
return (line1y - line2y) / (line2x - line1x);
|
||||
}
|
||||
|
||||
float3 hsluv_distanceFromPole(float3 pointx, float3 pointy) {
|
||||
float3
|
||||
hsluv_distanceFromPole(float3 pointx, float3 pointy) {
|
||||
return sqrt(pointx * pointx + pointy * pointy);
|
||||
}
|
||||
|
||||
float3 hsluv_lengthOfRayUntilIntersect(float theta, float3 x, float3 y) {
|
||||
float3
|
||||
hsluv_lengthOfRayUntilIntersect(float theta, float3 x, float3 y) {
|
||||
float3 len = divide(y, sin(theta) - x * cos(theta));
|
||||
len = lerp(len, (float3)1000.0, step(len, (float3)0.0));
|
||||
return len;
|
||||
}
|
||||
|
||||
float hsluv_maxSafeChromaForL(float L) {
|
||||
float
|
||||
hsluv_maxSafeChromaForL(float L) {
|
||||
// Transposed from GLSL column-major constructor to Slang row-major layout
|
||||
float3x3 m2 = float3x3(
|
||||
3.2409699419045214, -1.5373831775700935, -0.49861076029300328,
|
||||
-0.96924363628087983, 1.8759675015077207, 0.041555057407175613,
|
||||
0.055630079696993609,-0.20397695888897657, 1.0569715142428786
|
||||
);
|
||||
3.2409699419045214,
|
||||
-1.5373831775700935,
|
||||
-0.49861076029300328,
|
||||
-0.96924363628087983,
|
||||
1.8759675015077207,
|
||||
0.041555057407175613,
|
||||
0.055630079696993609,
|
||||
-0.20397695888897657,
|
||||
1.0569715142428786);
|
||||
|
||||
float sub0 = L + 16.0;
|
||||
float sub1 = sub0 * sub0 * sub0 * 0.000000641;
|
||||
float sub2 = lerp(L / 903.2962962962963, sub1, step(0.0088564516790356308, sub1));
|
||||
|
||||
float3 top1 = (284517.0 * m2[0] - 94839.0 * m2[2]) * sub2;
|
||||
float3 top1 = (284517.0 * m2[0] - 94839.0 * m2[2]) * sub2;
|
||||
float3 bottom = (632260.0 * m2[2] - 126452.0 * m2[1]) * sub2;
|
||||
float3 top2 = (838422.0 * m2[2] + 769860.0 * m2[1] + 731718.0 * m2[0]) * L * sub2;
|
||||
float3 top2 = (838422.0 * m2[2] + 769860.0 * m2[1] + 731718.0 * m2[0]) * L * sub2;
|
||||
|
||||
float3 bounds0x = top1 / bottom;
|
||||
float3 bounds0y = top2 / bottom;
|
||||
|
||||
float3 bounds1x = top1 / (bottom + 126452.0);
|
||||
float3 bounds1x = top1 / (bottom + 126452.0);
|
||||
float3 bounds1y = (top2 - 769860.0 * L) / (bottom + 126452.0);
|
||||
|
||||
float3 xs0 = hsluv_intersectLineLine(bounds0x, bounds0y, -1.0 / bounds0x, (float3)0.0);
|
||||
|
|
@ -55,87 +66,100 @@ float hsluv_maxSafeChromaForL(float L) {
|
|||
float3 lengths0 = hsluv_distanceFromPole(xs0, bounds0y + xs0 * bounds0x);
|
||||
float3 lengths1 = hsluv_distanceFromPole(xs1, bounds1y + xs1 * bounds1x);
|
||||
|
||||
return min(lengths0.x,
|
||||
min(lengths1.x,
|
||||
min(lengths0.y,
|
||||
min(lengths1.y,
|
||||
min(lengths0.z,
|
||||
lengths1.z)))));
|
||||
return min(lengths0.x, min(lengths1.x, min(lengths0.y, min(lengths1.y, min(lengths0.z, lengths1.z)))));
|
||||
}
|
||||
|
||||
float hsluv_maxChromaForLH(float L, float H) {
|
||||
float
|
||||
hsluv_maxChromaForLH(float L, float H) {
|
||||
float hrad = radians(H);
|
||||
|
||||
// Transposed from GLSL column-major constructor to Slang row-major layout
|
||||
float3x3 m2 = float3x3(
|
||||
3.2409699419045214, -1.5373831775700935, -0.49861076029300328,
|
||||
-0.96924363628087983, 1.8759675015077207, 0.041555057407175613,
|
||||
0.055630079696993609,-0.20397695888897657, 1.0569715142428786
|
||||
);
|
||||
3.2409699419045214,
|
||||
-1.5373831775700935,
|
||||
-0.49861076029300328,
|
||||
-0.96924363628087983,
|
||||
1.8759675015077207,
|
||||
0.041555057407175613,
|
||||
0.055630079696993609,
|
||||
-0.20397695888897657,
|
||||
1.0569715142428786);
|
||||
|
||||
float sub1 = pow(L + 16.0, 3.0) / 1560896.0;
|
||||
float sub2 = lerp(L / 903.2962962962963, sub1, step(0.0088564516790356308, sub1));
|
||||
|
||||
float3 top1 = (284517.0 * m2[0] - 94839.0 * m2[2]) * sub2;
|
||||
float3 top1 = (284517.0 * m2[0] - 94839.0 * m2[2]) * sub2;
|
||||
float3 bottom = (632260.0 * m2[2] - 126452.0 * m2[1]) * sub2;
|
||||
float3 top2 = (838422.0 * m2[2] + 769860.0 * m2[1] + 731718.0 * m2[0]) * L * sub2;
|
||||
float3 top2 = (838422.0 * m2[2] + 769860.0 * m2[1] + 731718.0 * m2[0]) * L * sub2;
|
||||
|
||||
float3 bound0x = top1 / bottom;
|
||||
float3 bound0y = top2 / bottom;
|
||||
|
||||
float3 bound1x = top1 / (bottom + 126452.0);
|
||||
float3 bound1x = top1 / (bottom + 126452.0);
|
||||
float3 bound1y = (top2 - 769860.0 * L) / (bottom + 126452.0);
|
||||
|
||||
float3 lengths0 = hsluv_lengthOfRayUntilIntersect(hrad, bound0x, bound0y);
|
||||
float3 lengths1 = hsluv_lengthOfRayUntilIntersect(hrad, bound1x, bound1y);
|
||||
|
||||
return min(lengths0.x,
|
||||
min(lengths1.x,
|
||||
min(lengths0.y,
|
||||
min(lengths1.y,
|
||||
min(lengths0.z,
|
||||
lengths1.z)))));
|
||||
return min(lengths0.x, min(lengths1.x, min(lengths0.y, min(lengths1.y, min(lengths0.z, lengths1.z)))));
|
||||
}
|
||||
|
||||
float3 hsluv_fromLinear(float3 c) {
|
||||
float3
|
||||
hsluv_fromLinear(float3 c) {
|
||||
return lerp(c * 12.92, 1.055 * pow(max(c, (float3)0), (float3)(1.0 / 2.4)) - 0.055, step(0.0031308, c));
|
||||
}
|
||||
|
||||
float3 hsluv_toLinear(float3 c) {
|
||||
float3
|
||||
hsluv_toLinear(float3 c) {
|
||||
return lerp(c / 12.92, pow(max((c + 0.055) / (1.0 + 0.055), (float3)0), (float3)2.4), step(0.04045, c));
|
||||
}
|
||||
|
||||
float hsluv_yToL(float Y) {
|
||||
float
|
||||
hsluv_yToL(float Y) {
|
||||
return lerp(Y * 903.2962962962963, 116.0 * pow(max(Y, 0), 1.0 / 3.0) - 16.0, step(0.0088564516790356308, Y));
|
||||
}
|
||||
|
||||
float hsluv_lToY(float L) {
|
||||
float
|
||||
hsluv_lToY(float L) {
|
||||
return lerp(L / 903.2962962962963, pow((max(L, 0) + 16.0) / 116.0, 3.0), step(8.0, L));
|
||||
}
|
||||
|
||||
float3 xyzToRgb(float3 tuple) {
|
||||
float3
|
||||
xyzToRgb(float3 tuple) {
|
||||
// Transposed layout from GLSL column-major matrix construction
|
||||
const float3x3 m = float3x3(
|
||||
3.2409699419045214, -0.96924363628087983, 0.055630079696993609,
|
||||
-1.5373831775700935, 1.8759675015077207, -0.20397695888897657,
|
||||
-0.49861076029300328, 0.041555057407175613, 1.0569715142428786
|
||||
);
|
||||
3.2409699419045214,
|
||||
-0.96924363628087983,
|
||||
0.055630079696993609,
|
||||
-1.5373831775700935,
|
||||
1.8759675015077207,
|
||||
-0.20397695888897657,
|
||||
-0.49861076029300328,
|
||||
0.041555057407175613,
|
||||
1.0569715142428786);
|
||||
// GLSL `tuple * m` is transformed to Slang/HLSL `mul(m, tuple)`
|
||||
return hsluv_fromLinear(mul(m, tuple));
|
||||
}
|
||||
|
||||
float3 rgbToXyz(float3 tuple) {
|
||||
float3
|
||||
rgbToXyz(float3 tuple) {
|
||||
// Transposed layout from GLSL column-major matrix construction
|
||||
const float3x3 m = float3x3(
|
||||
0.41239079926595948, 0.21263900587151036, 0.019330818715591851,
|
||||
0.35758433938387796, 0.71516867876775593, 0.11919477979462599,
|
||||
0.18048078840183429, 0.072192315360733715, 0.95053215224966058
|
||||
);
|
||||
0.41239079926595948,
|
||||
0.21263900587151036,
|
||||
0.019330818715591851,
|
||||
0.35758433938387796,
|
||||
0.71516867876775593,
|
||||
0.11919477979462599,
|
||||
0.18048078840183429,
|
||||
0.072192315360733715,
|
||||
0.95053215224966058);
|
||||
// GLSL `tuple * m` is transformed to Slang/HLSL `mul(m, tuple)`
|
||||
return mul(m, hsluv_toLinear(tuple));
|
||||
}
|
||||
|
||||
float3 xyzToLuv(float3 tuple) {
|
||||
float3
|
||||
xyzToLuv(float3 tuple) {
|
||||
float X = tuple.x;
|
||||
float Y = tuple.y;
|
||||
float Z = tuple.z;
|
||||
|
|
@ -143,14 +167,11 @@ float3 xyzToLuv(float3 tuple) {
|
|||
float L = hsluv_yToL(Y);
|
||||
float div = 1.0 / max(dot(tuple, float3(1, 15, 3)), 1e-15);
|
||||
|
||||
return float3(
|
||||
1.0,
|
||||
(52.0 * (X * div) - 2.57179),
|
||||
(117.0 * (Y * div) - 6.08816)
|
||||
) * L;
|
||||
return float3(1.0, (52.0 * (X * div) - 2.57179), (117.0 * (Y * div) - 6.08816)) * L;
|
||||
}
|
||||
|
||||
float3 luvToXyz(float3 tuple) {
|
||||
float3
|
||||
luvToXyz(float3 tuple) {
|
||||
float L = tuple.x;
|
||||
|
||||
float U = divide(tuple.y, 13.0 * L) + 0.19783000664283681;
|
||||
|
|
@ -163,7 +184,8 @@ float3 luvToXyz(float3 tuple) {
|
|||
return float3(X, Y, Z);
|
||||
}
|
||||
|
||||
float3 luvToLch(float3 tuple) {
|
||||
float3
|
||||
luvToLch(float3 tuple) {
|
||||
float L = tuple.x;
|
||||
float U = tuple.y;
|
||||
float V = tuple.z;
|
||||
|
|
@ -175,42 +197,45 @@ float3 luvToLch(float3 tuple) {
|
|||
return float3(L, C, H);
|
||||
}
|
||||
|
||||
float3 lchToLuv(float3 tuple) {
|
||||
float3
|
||||
lchToLuv(float3 tuple) {
|
||||
float hrad = radians(tuple.z);
|
||||
return float3(
|
||||
tuple.x,
|
||||
cos(hrad) * tuple.y,
|
||||
sin(hrad) * tuple.y
|
||||
);
|
||||
return float3(tuple.x, cos(hrad) * tuple.y, sin(hrad) * tuple.y);
|
||||
}
|
||||
|
||||
float3 hsluvToLch(float3 tuple) {
|
||||
float3
|
||||
hsluvToLch(float3 tuple) {
|
||||
tuple.y *= hsluv_maxChromaForLH(tuple.z, tuple.x) * 0.01;
|
||||
return tuple.zyx;
|
||||
}
|
||||
|
||||
float3 lchToHsluv(float3 tuple) {
|
||||
float3
|
||||
lchToHsluv(float3 tuple) {
|
||||
tuple.y = divide(tuple.y, hsluv_maxChromaForLH(tuple.x, tuple.z) * 0.01);
|
||||
return tuple.zyx;
|
||||
}
|
||||
|
||||
float3 lchToRgb(float3 tuple) {
|
||||
float3
|
||||
lchToRgb(float3 tuple) {
|
||||
return xyzToRgb(luvToXyz(lchToLuv(tuple)));
|
||||
}
|
||||
|
||||
float3 rgbToLch(float3 tuple) {
|
||||
float3
|
||||
rgbToLch(float3 tuple) {
|
||||
return luvToLch(xyzToLuv(rgbToXyz(tuple)));
|
||||
}
|
||||
|
||||
public float3 hsluvToRgb(float3 tuple) {
|
||||
public float3
|
||||
hsluvToRgb(float3 tuple) {
|
||||
return lchToRgb(hsluvToLch(tuple));
|
||||
}
|
||||
|
||||
public float3 rgbToHsluv(float3 tuple) {
|
||||
public float3
|
||||
rgbToHsluv(float3 tuple) {
|
||||
return lchToHsluv(rgbToLch(tuple));
|
||||
}
|
||||
|
||||
float3 luvToRgb(float3 tuple) {
|
||||
float3
|
||||
luvToRgb(float3 tuple) {
|
||||
return xyzToRgb(luvToXyz(tuple));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@
|
|||
module linear2srgb;
|
||||
|
||||
// Scalar sRGB to Linear conversion
|
||||
public float srgb2linear(float x) {
|
||||
public float
|
||||
srgb2linear(float x) {
|
||||
float lower = x / 12.92;
|
||||
float upper = pow((x + 0.055f) / 1.055f, 2.4f);
|
||||
|
||||
|
|
@ -14,7 +15,8 @@ public float srgb2linear(float x) {
|
|||
}
|
||||
|
||||
// Scalar Linear to sRGB conversion
|
||||
public float linear2srgb(float x) {
|
||||
public float
|
||||
linear2srgb(float x) {
|
||||
float lower = 12.92 * x;
|
||||
float upper = 1.055 * pow(x, 1.0f / 2.4f) - 0.055f;
|
||||
|
||||
|
|
@ -22,7 +24,8 @@ public float linear2srgb(float x) {
|
|||
}
|
||||
|
||||
// Vector Linear to sRGB conversion
|
||||
public float3 linear2srgb(float3 x) {
|
||||
public float3
|
||||
linear2srgb(float3 x) {
|
||||
float3 lower = 12.92 * x;
|
||||
float3 upper = 1.055 * pow(x, float3(1.0f / 2.4f)) - 0.055f;
|
||||
|
||||
|
|
@ -30,9 +33,9 @@ public float3 linear2srgb(float3 x) {
|
|||
}
|
||||
|
||||
// Vector sRGB to Linear conversion
|
||||
public float3 srgb2linear(float3 c) {
|
||||
public float3
|
||||
srgb2linear(float3 c) {
|
||||
// You can call the scalar version per-component,
|
||||
// or pass the whole vector if you overload it for float3.
|
||||
return float3(srgb2linear(c.r), srgb2linear(c.g), srgb2linear(c.b));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,10 +23,10 @@ import background;
|
|||
// Corner indicator per quad vertex, matching cell_pos_map in background.slang.
|
||||
// .x: 0 -> left, 1 -> right ; .y: 0 -> top, 1 -> bottom
|
||||
static const uint2 pad_pos_map[4] = {
|
||||
uint2(1u, 0u), // right, top
|
||||
uint2(1u, 1u), // right, bottom
|
||||
uint2(0u, 1u), // left, bottom
|
||||
uint2(0u, 0u) // left, top
|
||||
uint2(1u, 0u), // right, top
|
||||
uint2(1u, 1u), // right, bottom
|
||||
uint2(0u, 1u), // left, bottom
|
||||
uint2(0u, 0u) // left, top
|
||||
};
|
||||
|
||||
struct VertexOutput {
|
||||
|
|
@ -35,12 +35,13 @@ struct VertexOutput {
|
|||
};
|
||||
|
||||
[shader("vertex")]
|
||||
VertexOutput vertex_main(
|
||||
VertexOutput
|
||||
vertex_main(
|
||||
[[vk::location(0)]] uint3 colors,
|
||||
[[vk::location(1)]] uint2 sprite_idx,
|
||||
[[vk::location(2)]] uint is_selected,
|
||||
uint vertex_id : SV_VertexID,
|
||||
uint instance_id : SV_InstanceID,
|
||||
[[vk::location(2)]] uint is_selected,
|
||||
uint vertex_id: SV_VertexID,
|
||||
uint instance_id: SV_InstanceID,
|
||||
// The true cell index (into the cell grid) for strip 0's first instance.
|
||||
uniform uint base_instance,
|
||||
uniform uint instance_step,
|
||||
|
|
@ -62,18 +63,17 @@ VertexOutput vertex_main(
|
|||
// Strip-1 parameters. Equal to strip-0 values for single-strip draws so
|
||||
// the lerp below is always correct regardless of strip count.
|
||||
uniform uint base_instance2,
|
||||
uniform float2 across2,
|
||||
) {
|
||||
uniform float2 across2, ) {
|
||||
VertexOutput vo;
|
||||
|
||||
// Branchless strip selector: 0.0 for strip 0, 1.0 for strip 1.
|
||||
float strip_f = float(instance_id / along_count);
|
||||
uint strip_i = instance_id % along_count;
|
||||
uint strip_i = instance_id % along_count;
|
||||
|
||||
// Select the base cell and across extents for whichever strip this
|
||||
// instance belongs to, using lerp so no divergent branch is emitted.
|
||||
float fbase = lerp(float(base_instance), float(base_instance2), strip_f);
|
||||
uint real_id = uint(fbase) + strip_i * instance_step;
|
||||
float fbase = lerp(float(base_instance), float(base_instance2), strip_f);
|
||||
uint real_id = uint(fbase) + strip_i * instance_step;
|
||||
float2 chosen_across = lerp(across, across2, strip_f);
|
||||
|
||||
vo.color_premul = padding_background_premul(colors, sprite_idx, is_selected, real_id);
|
||||
|
|
@ -89,7 +89,7 @@ VertexOutput vertex_main(
|
|||
float a = lerp(float(p.x), float(p.y), h);
|
||||
// 1 when this is the first/last instance within its strip, else 0.
|
||||
float is_first = 1.0 - min(float(strip_i), 1.0);
|
||||
float is_last = 1.0 - min(float(along_count - 1u - strip_i), 1.0);
|
||||
float is_last = 1.0 - min(float(along_count - 1u - strip_i), 1.0);
|
||||
|
||||
float along = lerp(along_lo, along_hi, s);
|
||||
// Extend the first cell's near corner and the last cell's far corner out to
|
||||
|
|
@ -104,6 +104,8 @@ VertexOutput vertex_main(
|
|||
}
|
||||
|
||||
[shader("fragment")]
|
||||
float4 fragment_main(float4 color_premul : COLOR_PREMUL) : SV_Target {
|
||||
float4
|
||||
fragment_main(float4 color_premul: COLOR_PREMUL)
|
||||
: SV_Target {
|
||||
return color_premul;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,23 +9,21 @@ import alpha_blend;
|
|||
#define right 2
|
||||
#define bottom 3
|
||||
|
||||
static const int2 vertex_pos_map[4] = {
|
||||
int2(right, top),
|
||||
int2(right, bottom),
|
||||
int2(left, bottom),
|
||||
int2(left, top)
|
||||
};
|
||||
static const int2 vertex_pos_map[4] = { int2(right, top), int2(right, bottom), int2(left, bottom), int2(left, top) };
|
||||
|
||||
static const float4 dest_rect = float4(-1, 1, 1, -1);
|
||||
|
||||
[shader("vertex")]
|
||||
float4 vertex_main(uint vertex_id : SV_VertexID) : SV_Position {
|
||||
float4
|
||||
vertex_main(uint vertex_id: SV_VertexID)
|
||||
: SV_Position {
|
||||
int2 pos = vertex_pos_map[vertex_id];
|
||||
return float4(dest_rect[pos.x], dest_rect[pos.y], 0, 1);
|
||||
}
|
||||
|
||||
// Signed distance function for a rounded rectangle
|
||||
float rounded_rectangle_sdf(float2 p, float2 b, float r) {
|
||||
float
|
||||
rounded_rectangle_sdf(float2 p, float2 b, float r) {
|
||||
// signed distance field
|
||||
// first term is used for points outside the rectangle
|
||||
float2 q = abs(p) - b;
|
||||
|
|
@ -33,13 +31,15 @@ float rounded_rectangle_sdf(float2 p, float2 b, float r) {
|
|||
}
|
||||
|
||||
[shader("fragment")]
|
||||
float4 fragment_main(
|
||||
float4
|
||||
fragment_main(
|
||||
uniform float4 rect,
|
||||
uniform float2 params,
|
||||
uniform float4 color,
|
||||
uniform float4 background_color,
|
||||
float4 frag_coord : SV_Position // SV_Position provides gl_FragCoord equivalent in Slang
|
||||
) : SV_Target {
|
||||
float4 frag_coord: SV_Position // SV_Position provides gl_FragCoord equivalent in Slang
|
||||
)
|
||||
: SV_Target {
|
||||
float2 size = rect.zw; // GLSL .ba maps to .zw or .ba in Slang (using .zw is typical)
|
||||
float2 origin = rect.xy;
|
||||
float thickness = params[0];
|
||||
|
|
|
|||
|
|
@ -12,18 +12,16 @@ struct VSOutput {
|
|||
|
||||
|
||||
[shader("vertex")]
|
||||
VSOutput vertex_main(
|
||||
uint vertex_id : SV_VertexID,
|
||||
uniform float4 src_rect,
|
||||
uniform float4 dest_rect,
|
||||
) {
|
||||
VSOutput
|
||||
vertex_main(uint vertex_id: SV_VertexID, uniform float4 src_rect, uniform float4 dest_rect, ) {
|
||||
BlitOutput ans = get_coords_for_blit(vertex_id, src_rect, dest_rect);
|
||||
return {ans.texcoord, float4(ans.position[0], ans.position[1], 0.0, 1.0)};
|
||||
return { ans.texcoord, float4(ans.position[0], ans.position[1], 0.0, 1.0) };
|
||||
}
|
||||
|
||||
uniform Sampler2D image;
|
||||
|
||||
float3 safe_unpremult_to_linear(float4 s) {
|
||||
float3
|
||||
safe_unpremult_to_linear(float4 s) {
|
||||
// Avoid division by zero by replacing 0.0 alpha with 1.0.
|
||||
// If alpha is 0.0, the division is safe, and lerp masks the result to 0.0 anyway.
|
||||
float safe_alpha = lerp(1.0f, s.a, step(0.00001f, s.a));
|
||||
|
|
@ -33,34 +31,37 @@ float3 safe_unpremult_to_linear(float4 s) {
|
|||
}
|
||||
|
||||
[shader("fragment")]
|
||||
float4 fragment_main(float2 texcoord : TEXCOORD, uniform float2 src_size) : SV_Target {
|
||||
float4
|
||||
fragment_main(float2 texcoord: TEXCOORD, uniform float2 src_size)
|
||||
: SV_Target {
|
||||
float4 s00, s10, s01, s11;
|
||||
float2 texel_size = 1.0 / src_size;
|
||||
|
||||
// Use Slang target switches to dynamically compile for specific backend features
|
||||
__target_switch
|
||||
{
|
||||
// Modern backends with full texture gathering capabilities
|
||||
case spirv: case hlsl: case metal: {
|
||||
float2 gather_coord = texcoord - (0.5 * texel_size);
|
||||
__target_switch {
|
||||
// Modern backends with full texture gathering capabilities
|
||||
case spirv:
|
||||
case hlsl:
|
||||
case metal: {
|
||||
float2 gather_coord = texcoord - (0.5 * texel_size);
|
||||
|
||||
float4 r_gather = image.GatherRed(gather_coord);
|
||||
float4 g_gather = image.GatherGreen(gather_coord);
|
||||
float4 b_gather = image.GatherBlue(gather_coord);
|
||||
float4 a_gather = image.GatherAlpha(gather_coord);
|
||||
float4 r_gather = image.GatherRed(gather_coord);
|
||||
float4 g_gather = image.GatherGreen(gather_coord);
|
||||
float4 b_gather = image.GatherBlue(gather_coord);
|
||||
float4 a_gather = image.GatherAlpha(gather_coord);
|
||||
|
||||
s00 = float4(r_gather.w, g_gather.w, b_gather.w, a_gather.w); // Bottom-Left
|
||||
s10 = float4(r_gather.z, g_gather.z, b_gather.z, a_gather.z); // Bottom-Right
|
||||
s01 = float4(r_gather.x, g_gather.x, b_gather.x, a_gather.x); // Top-Left
|
||||
s11 = float4(r_gather.y, g_gather.y, b_gather.y, a_gather.y); // Top-Right
|
||||
}
|
||||
// Fallback for older targets or legacy GLSL versions
|
||||
default: {
|
||||
s00 = image.Sample(texcoord + float2(-0.25, -0.25) * texel_size);
|
||||
s10 = image.Sample(texcoord + float2( 0.25, -0.25) * texel_size);
|
||||
s01 = image.Sample(texcoord + float2(-0.25, 0.25) * texel_size);
|
||||
s11 = image.Sample(texcoord + float2( 0.25, 0.25) * texel_size);
|
||||
}
|
||||
s00 = float4(r_gather.w, g_gather.w, b_gather.w, a_gather.w); // Bottom-Left
|
||||
s10 = float4(r_gather.z, g_gather.z, b_gather.z, a_gather.z); // Bottom-Right
|
||||
s01 = float4(r_gather.x, g_gather.x, b_gather.x, a_gather.x); // Top-Left
|
||||
s11 = float4(r_gather.y, g_gather.y, b_gather.y, a_gather.y); // Top-Right
|
||||
}
|
||||
// Fallback for older targets or legacy GLSL versions
|
||||
default: {
|
||||
s00 = image.Sample(texcoord + float2(-0.25, -0.25) * texel_size);
|
||||
s10 = image.Sample(texcoord + float2(0.25, -0.25) * texel_size);
|
||||
s01 = image.Sample(texcoord + float2(-0.25, 0.25) * texel_size);
|
||||
s11 = image.Sample(texcoord + float2(0.25, 0.25) * texel_size);
|
||||
}
|
||||
}
|
||||
|
||||
// Unpremultiply and convert to linear for each sample
|
||||
|
|
|
|||
|
|
@ -406,8 +406,8 @@ def parse_slang_text(src_code: str, path: str = '') -> SlangFile:
|
|||
entry_points.append(EntryPoint(Stage.vertex, name))
|
||||
case 'fragment' | 'pixel':
|
||||
entry_points.append(EntryPoint(Stage.fragment, name))
|
||||
found_entry_point = ''
|
||||
break
|
||||
found_entry_point = ''
|
||||
else:
|
||||
match words[0]:
|
||||
case 'module':
|
||||
|
|
|
|||
|
|
@ -4,29 +4,28 @@
|
|||
|
||||
// Main Vertex Shader Entry Point
|
||||
[shader("vertex")]
|
||||
float4 vertex_main(
|
||||
uint vertex_id : SV_VertexID,
|
||||
float4
|
||||
vertex_main(
|
||||
uint vertex_id: SV_VertexID,
|
||||
uniform float4 edges, // [ left, top, right, bottom ]
|
||||
) : SV_Position {
|
||||
)
|
||||
: SV_Position {
|
||||
// Extract boundaries from the edges vector
|
||||
float left = edges[0];
|
||||
float top = edges[1];
|
||||
float right = edges[2];
|
||||
float left = edges[0];
|
||||
float top = edges[1];
|
||||
float right = edges[2];
|
||||
float bottom = edges[3];
|
||||
|
||||
// Static mapping table for vertex positions
|
||||
const float2 pos_map[4] = {
|
||||
float2(left, top),
|
||||
float2(left, bottom),
|
||||
float2(right, bottom),
|
||||
float2(right, top)
|
||||
};
|
||||
const float2 pos_map[4] = { float2(left, top), float2(left, bottom), float2(right, bottom), float2(right, top) };
|
||||
|
||||
// Calculate final position
|
||||
return float4(pos_map[vertex_id], 0.0, 1.0);
|
||||
}
|
||||
|
||||
[shader("fragment")]
|
||||
float4 fragment_main(uniform float4 tint_color) : SV_Target {
|
||||
float4
|
||||
fragment_main(uniform float4 tint_color)
|
||||
: SV_Target {
|
||||
return tint_color;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,15 +2,15 @@
|
|||
// Copyright (C) 2026 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
// Distributed under terms of the GPLv3 license.
|
||||
|
||||
struct VertexOutput
|
||||
{
|
||||
struct VertexOutput {
|
||||
float2 frag_pos : TEXCOORD;
|
||||
float4 position : SV_Position;
|
||||
};
|
||||
|
||||
// Main Vertex Shader Entry Point
|
||||
[shader("vertex")]
|
||||
VertexOutput vertex_main(uint vertex_id : SV_VertexID, uniform float4 x_coords, uniform float4 y_coords) {
|
||||
VertexOutput
|
||||
vertex_main(uint vertex_id: SV_VertexID, uniform float4 x_coords, uniform float4 y_coords) {
|
||||
VertexOutput output;
|
||||
float2 pos = float2(x_coords[vertex_id], y_coords[vertex_id]);
|
||||
output.position = float4(pos, 1.0, 1.0);
|
||||
|
|
@ -21,13 +21,9 @@ VertexOutput vertex_main(uint vertex_id : SV_VertexID, uniform float4 x_coords,
|
|||
|
||||
// Main Fragment Shader Entry Point
|
||||
[shader("fragment")]
|
||||
float4 fragment_main(
|
||||
float2 frag_pos : TEXCOORD,
|
||||
uniform float2 cursor_edge_x,
|
||||
uniform float2 cursor_edge_y,
|
||||
uniform float3 trail_color,
|
||||
uniform float trail_opacity
|
||||
) : SV_Target {
|
||||
float4
|
||||
fragment_main(float2 frag_pos: TEXCOORD, uniform float2 cursor_edge_x, uniform float2 cursor_edge_y, uniform float3 trail_color, uniform float trail_opacity)
|
||||
: SV_Target {
|
||||
float opacity = trail_opacity;
|
||||
// Evaluate if the fragment falls inside the bounding box of the cursor
|
||||
float in_x = step(cursor_edge_x[0], frag_pos.x) * step(frag_pos.x, cursor_edge_x[1]);
|
||||
|
|
|
|||
|
|
@ -5,30 +5,31 @@
|
|||
module utils;
|
||||
|
||||
// Return 0 if x < 1 otherwise 1
|
||||
public __generic<T : __BuiltinFloatingPointType, int N = 1>
|
||||
vector<T, N> zero_or_one(vector<T, N> x) {
|
||||
public __generic<T : __BuiltinFloatingPointType, int N = 1> vector<T, N>
|
||||
zero_or_one(vector<T, N> x) {
|
||||
return step((vector<T, N>)1.0f, x);
|
||||
}
|
||||
|
||||
// condition must be zero or one. When 1 thenval is returned otherwise elseval
|
||||
public __generic<T : __BuiltinFloatingPointType, int N = 1>
|
||||
vector<T, N> if_one_then(vector<T, N> condition, vector<T, N> thenval, vector<T, N> elseval) {
|
||||
public __generic<T : __BuiltinFloatingPointType, int N = 1> vector<T, N>
|
||||
if_one_then(vector<T, N> condition, vector<T, N> thenval, vector<T, N> elseval) {
|
||||
return lerp(elseval, thenval, condition);
|
||||
}
|
||||
|
||||
// a < b ? thenval : elseval
|
||||
public __generic<T : __BuiltinFloatingPointType, int N = 1>
|
||||
vector<T, N> if_less_than(vector<T, N> a, vector<T, N> b, vector<T, N> thenval, vector<T, N> elseval) {
|
||||
public __generic<T : __BuiltinFloatingPointType, int N = 1> vector<T, N>
|
||||
if_less_than(vector<T, N> a, vector<T, N> b, vector<T, N> thenval, vector<T, N> elseval) {
|
||||
return lerp(thenval, elseval, step(b, a));
|
||||
}
|
||||
|
||||
// Replaces vec4(rgb * a, a)
|
||||
public float4 vec4_premul(float3 rgb, float a) {
|
||||
public float4
|
||||
vec4_premul(float3 rgb, float a) {
|
||||
return float4(rgb * a, a);
|
||||
}
|
||||
|
||||
// Overloaded variation replacing vec4(rgba.rgb * rgba.a, rgba.a)
|
||||
public float4 vec4_premul(float4 rgba) {
|
||||
public float4
|
||||
vec4_premul(float4 rgba) {
|
||||
return float4(rgba.rgb * rgba.a, rgba.a);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -152,6 +152,58 @@ void vsMain() {}
|
|||
SlangFile('', '', frozenset({'common'}), frozenset({EntryPoint(Stage.vertex, 'vsMain')}), 'myshader'),
|
||||
)
|
||||
|
||||
# Autoformat style: return type on its own line before function name
|
||||
check(
|
||||
"""
|
||||
[shader("vertex")]
|
||||
VertexOutput
|
||||
vertex_main(uint vertex_id : SV_VertexID) {}
|
||||
""",
|
||||
SlangFile('', '', frozenset(), frozenset({EntryPoint(Stage.vertex, 'vertex_main')})),
|
||||
)
|
||||
|
||||
# Autoformat style: return type on own line, function name + open-paren on next, params on following lines
|
||||
check(
|
||||
"""
|
||||
[shader("fragment")]
|
||||
float4
|
||||
fragment_main(
|
||||
float2 texcoord : TEXCOORD
|
||||
) : SV_Target { return float4(0); }
|
||||
""",
|
||||
SlangFile('', '', frozenset(), frozenset({EntryPoint(Stage.fragment, 'fragment_main')})),
|
||||
)
|
||||
|
||||
# Autoformat style: attribute lines between [shader] and split return-type/name declaration
|
||||
check(
|
||||
"""
|
||||
[shader("fragment")]
|
||||
[numthreads(1, 1, 1)]
|
||||
float4
|
||||
psMain() : SV_Target { return float4(1, 0, 0, 1); }
|
||||
""",
|
||||
SlangFile('', '', frozenset(), frozenset({EntryPoint(Stage.fragment, 'psMain')})),
|
||||
)
|
||||
|
||||
# Autoformat style: vertex and fragment both split across lines
|
||||
check(
|
||||
"""
|
||||
[shader("vertex")]
|
||||
VertexOutput
|
||||
vsMain(uint id : SV_VertexID) {}
|
||||
|
||||
[shader("fragment")]
|
||||
float4
|
||||
fsMain(VertexOutput vo) : SV_Target { return float4(0); }
|
||||
""",
|
||||
SlangFile(
|
||||
'',
|
||||
'',
|
||||
frozenset(),
|
||||
frozenset({EntryPoint(Stage.vertex, 'vsMain'), EntryPoint(Stage.fragment, 'fsMain')}),
|
||||
),
|
||||
)
|
||||
|
||||
def test_slang_ordering(self):
|
||||
# Test topological_sort with a manually constructed linear chain: a <- b <- c
|
||||
graph: dict[str, SlangFile] = {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue