broadfield-dev/stack-overflow-game
0
1import Phaser from 'phaser';2 3const fragShader = `4precision mediump float;5 6uniform sampler2D uMainSampler;7uniform vec2 resolution;8uniform float time;9 10varying vec2 outTexCoord;11 12#define PI 3.1415926535913 14vec4 permute(vec4 t) {15 return mod(((t * 34.0) + 1.0) * t, 289.0);16}17 18float noise3d(vec3 p) {19 vec3 a = floor(p);20 vec3 d = p - a;21 d = d * d * (3.0 - 2.0 * d);22 23 vec4 b = a.xxyy + vec4(0.0, 1.0, 0.0, 1.0);24 vec4 k1 = permute(b.xyxy);25 vec4 k2 = permute(k1.xyxy + b.zzww);26 27 vec4 c = k2 + a.zzzz;28 vec4 k3 = permute(c);29 vec4 k4 = permute(c + 1.0);30 31 vec4 o1 = fract(k3 * (1.0 / 41.0));32 vec4 o2 = fract(k4 * (1.0 / 41.0));33 34 vec4 o3_interp_z = o2 * d.z + o1 * (1.0 - d.z);35 vec2 o4_interp_xy = o3_interp_z.yw * d.x + o3_interp_z.xz * (1.0 - d.x);36 37 return o4_interp_xy.y * d.y + o4_interp_xy.x * (1.0 - d.y);38}39 40void main() {41 float brightness = 2.5;42 float red_balance = 1.0;43 float green_balance = 0.85;44 float blue_balance = 1.0;45 46 float phosphorWidth = 2.50;47 float phosphorHeight = 4.50;48 float internalHorizontalGap = 1.0;49 float columnGap = 0.2;50 float verticalCellGap = 0.2;51 float phosphorPower = 0.9;52 53 float cell_noise_variation_amount = 0.025;54 float cell_noise_scale_xy = 240.0;55 float cell_noise_speed = 24.0;56 float curvature_amount = 0.0;57 58 vec2 fragCoord = gl_FragCoord.xy;59 vec2 uv = outTexCoord;60 vec2 centered_uv_output = uv - 0.5;61 float r = length(centered_uv_output);62 float distort_factor = 1.0 + curvature_amount * r * r;63 vec2 centered_uv_source = centered_uv_output * distort_factor;64 vec2 source_uv = centered_uv_source + 0.5;65 vec2 fragCoord_warped = source_uv * resolution;66 67 bool is_on_original_flat_screen = source_uv.x >= 0.0 && source_uv.x <= 1.0 &&68 source_uv.y >= 0.0 && source_uv.y <= 1.0;69 70 if (!is_on_original_flat_screen) {71 gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);72 return;73 }74 75 float fullCellWidth = 3.0 * phosphorWidth + 3.0 * internalHorizontalGap + columnGap;76 float fullRowHeight = phosphorHeight + verticalCellGap;77 78 float logical_cell_index_x = floor(fragCoord_warped.x / fullCellWidth);79 float shift_y_offset = 0.0;80 81 if (mod(logical_cell_index_x, 2.0) != 0.0) {82 shift_y_offset = fullRowHeight / 2.0;83 }84 85 float effective_y_warped = fragCoord_warped.y + shift_y_offset;86 float logical_row_index = floor(effective_y_warped / fullRowHeight);87 88 float uv_cell_x = mod(fragCoord_warped.x, fullCellWidth);89 if (uv_cell_x < 0.0) {90 uv_cell_x += fullCellWidth;91 }92 93 float uv_row_y = mod(effective_y_warped, fullRowHeight);94 if (uv_row_y < 0.0) {95 uv_row_y += fullRowHeight;96 }97 98 vec3 video_color = texture2D(uMainSampler, source_uv).rgb;99 video_color.r *= red_balance;100 video_color.g *= green_balance;101 video_color.b *= blue_balance;102 103 vec3 final_color = vec3(0.0);104 bool in_column_gap = uv_cell_x >= (3.0 * phosphorWidth + 3.0 * internalHorizontalGap);105 bool in_vertical_gap = uv_row_y >= phosphorHeight;106 107 if (!in_column_gap && !in_vertical_gap) {108 float uv_cell_x_within_block = uv_cell_x;109 vec3 phosphor_base_color = vec3(0.0);110 float video_component_intensity = 0.0;111 float current_phosphor_startX_in_block = -1.0;112 float current_x_tracker = 0.0;113 114 if (uv_cell_x_within_block >= current_x_tracker && uv_cell_x_within_block < current_x_tracker + phosphorWidth) {115 phosphor_base_color = vec3(1.0, 0.0, 0.0);116 video_component_intensity = video_color.r;117 current_phosphor_startX_in_block = current_x_tracker;118 }119 current_x_tracker += phosphorWidth + internalHorizontalGap;120 121 if (uv_cell_x_within_block >= current_x_tracker && uv_cell_x_within_block < current_x_tracker + phosphorWidth) {122 phosphor_base_color = vec3(0.0, 1.0, 0.0);123 video_component_intensity = video_color.g;124 current_phosphor_startX_in_block = current_x_tracker;125 }126 current_x_tracker += phosphorWidth + internalHorizontalGap;127 128 if (uv_cell_x_within_block >= current_x_tracker && uv_cell_x_within_block < current_x_tracker + phosphorWidth) {129 phosphor_base_color = vec3(0.0, 0.0, 1.0);130 video_component_intensity = video_color.b;131 current_phosphor_startX_in_block = current_x_tracker;132 }133 134 if (current_phosphor_startX_in_block >= 0.0) {135 float x_in_phosphor = (uv_cell_x_within_block - current_phosphor_startX_in_block) / phosphorWidth;136 float horizontal_intensity_factor = pow(sin(x_in_phosphor * PI), phosphorPower);137 float y_in_phosphor_band = uv_row_y / phosphorHeight;138 float vertical_intensity_factor = (phosphorHeight > 0.0) ? pow(sin(y_in_phosphor_band * PI), phosphorPower) : 1.0;139 float total_intensity_factor = horizontal_intensity_factor * vertical_intensity_factor;140 final_color = phosphor_base_color * video_component_intensity * total_intensity_factor;141 }142 }143 144 vec3 noise_pos = vec3(logical_cell_index_x * cell_noise_scale_xy,145 logical_row_index * cell_noise_scale_xy,146 time * cell_noise_speed);147 148 vec3 cell_noise_rgb;149 cell_noise_rgb.r = noise3d(noise_pos);150 cell_noise_rgb.g = noise3d(noise_pos + vec3(19.0, 0.0, 0.0));151 cell_noise_rgb.b = noise3d(noise_pos + vec3(0.0, 13.0, 0.0));152 cell_noise_rgb = cell_noise_rgb * 2.0 - 1.0;153 final_color += cell_noise_rgb * cell_noise_variation_amount;154 155 final_color *= brightness;156 float edge_darken_strength = 0.1;157 float vignette_factor = 1.0 - dot(centered_uv_output, centered_uv_output) * edge_darken_strength * 2.0;158 vignette_factor = clamp(vignette_factor, 0.0, 1.0);159 final_color *= vignette_factor;160 161 final_color = clamp(final_color, 0.0, 1.0);162 gl_FragColor = vec4(final_color, 1.0);163}164`;165 166export default class TrinitronPipeline extends Phaser.Renderer.WebGL.Pipelines.PostFXPipeline {167 constructor(game) {168 super({169 name: 'TrinitronPipeline',170 game: game,171 renderTarget: true,172 fragShader: fragShader,173 uniforms: [174 'uMainSampler',175 'resolution',176 'time'177 ]178 });179 }180 181 onPreRender() {182 // Use the actual canvas display size (after scaling), not the game resolution183 const canvas = this.game.canvas;184 const displayWidth = canvas.width;185 const displayHeight = canvas.height;186 this.set2f('resolution', displayWidth, displayHeight);187 this.set1f('time', this.game.loop.time / 1000);188 }189}190 191 