1use crate::disasm::ShaderKind;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4enum VertexMode {
5 Base,
6 D3,
7 D3Fog,
8 D3Light,
9}
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12enum PixelMode {
13 V0,
14 V1Fog,
15 V2Light,
16}
17
18#[derive(Debug, Clone, Copy, Default)]
19struct PixelFlags {
20 tex: bool,
21 mrbd: bool,
22 rgb: bool,
23 tonecurve: bool,
24 mask: bool,
25 mul: bool,
26 screen: bool,
27}
28
29#[derive(Debug, Clone, Copy)]
30struct RegularTechnique {
31 vertex: VertexMode,
32 pixel: PixelMode,
33 flags: PixelFlags,
34}
35
36pub fn rewrite_wgsl_for_stage(technique_name: &str, kind: ShaderKind) -> Option<String> {
37 if let Some(t) = parse_regular_technique(technique_name) {
38 return match kind {
39 ShaderKind::Vertex => Some(regular_vertex_wgsl(t)),
40 ShaderKind::Pixel => Some(regular_fragment_wgsl(t)),
41 };
42 }
43
44 if kind == ShaderKind::Pixel {
45 return special_fragment_wgsl(technique_name);
46 }
47
48 None
49}
50
51fn parse_regular_technique(name: &str) -> Option<RegularTechnique> {
52 let rest = name.strip_prefix("tec_v")?;
53 let (vpart, ppart) = rest.split_once("_p_")?;
54 let vertex = match vpart {
55 "" => VertexMode::Base,
56 "_d3" => VertexMode::D3,
57 "_d3_fog" => VertexMode::D3Fog,
58 "_d3_light" => VertexMode::D3Light,
59 _ => return None,
60 };
61
62 let pixel = if ppart.starts_with("v0") {
63 PixelMode::V0
64 } else if ppart.starts_with("v1") {
65 PixelMode::V1Fog
66 } else if ppart.starts_with("v2") {
67 PixelMode::V2Light
68 } else {
69 return None;
70 };
71
72 let flags = PixelFlags {
73 tex: has_flag(ppart, "tex"),
74 mrbd: has_flag(ppart, "mrbd"),
75 rgb: has_flag(ppart, "rgb"),
76 tonecurve: has_flag(ppart, "tonecurve"),
77 mask: has_flag(ppart, "mask"),
78 mul: has_flag(ppart, "mul"),
79 screen: has_flag(ppart, "screen"),
80 };
81
82 Some(RegularTechnique {
83 vertex,
84 pixel,
85 flags,
86 })
87}
88
89fn has_flag(s: &str, flag: &str) -> bool {
90 s.split('_').any(|part| part == flag)
91}
92
93fn regular_vertex_wgsl(t: RegularTechnique) -> String {
94 let needs_d3 = !matches!(t.vertex, VertexMode::Base);
95 let needs_normal = matches!(t.vertex, VertexMode::D3Light);
96 let needs_mask_uv = t.flags.mask;
97
98 let mut out = String::new();
99 if needs_d3 {
100 push_uniforms(&mut out);
101 }
102
103 out.push_str("struct VSInput {\n");
104 out.push_str(" @location(0) position: vec4<f32>,\n");
105 if needs_normal {
106 out.push_str(" @location(1) normal: vec3<f32>,\n");
107 }
108 out.push_str(" @location(2) diffuse: vec4<f32>,\n");
109 out.push_str(" @location(4) texture_uv: vec2<f32>,\n");
110 if needs_mask_uv {
111 out.push_str(" @location(5) mask_uv: vec2<f32>,\n");
112 }
113 out.push_str("};\n\n");
114
115 out.push_str("struct VSOutput {\n");
116 out.push_str(" @builtin(position) position: vec4<f32>,\n");
117 out.push_str(" @location(2) diffuse: vec4<f32>,\n");
118 out.push_str(" @location(4) texture_uv: vec2<f32>,\n");
119 match t.vertex {
120 VertexMode::Base | VertexMode::D3 => {
121 if needs_mask_uv {
122 out.push_str(" @location(5) mask_uv: vec2<f32>,\n");
123 }
124 }
125 VertexMode::D3Fog => {
126 out.push_str(" @location(5) world_pos: vec4<f32>,\n");
127 out.push_str(" @location(6) proj_pos: vec4<f32>,\n");
128 }
129 VertexMode::D3Light => {
130 out.push_str(" @location(5) normal: vec3<f32>,\n");
131 out.push_str(" @location(6) world_pos: vec4<f32>,\n");
132 out.push_str(" @location(7) proj_pos: vec4<f32>,\n");
133 }
134 }
135 out.push_str("};\n\n");
136
137 if needs_d3 {
138 out.push_str("fn mul_vec4_mat4(v: vec4<f32>, m: mat4x4<f32>) -> vec4<f32> {\n");
139 out.push_str(
140 " return vec4<f32>(dot(v, m[0]), dot(v, m[1]), dot(v, m[2]), dot(v, m[3]));\n",
141 );
142 out.push_str("}\n\n");
143 if needs_normal {
144 out.push_str("fn mul_vec3_mat4(v: vec3<f32>, m: mat4x4<f32>) -> vec3<f32> {\n");
145 out.push_str(" let x = dot(vec4<f32>(v, 0.0), m[0]);\n");
146 out.push_str(" let y = dot(vec4<f32>(v, 0.0), m[1]);\n");
147 out.push_str(" let z = dot(vec4<f32>(v, 0.0), m[2]);\n");
148 out.push_str(" return vec3<f32>(x, y, z);\n");
149 out.push_str("}\n\n");
150 }
151 }
152
153 out.push_str("@vertex\n");
154 out.push_str("fn main(input: VSInput) -> VSOutput {\n");
155 out.push_str(" var output: VSOutput;\n");
156 match t.vertex {
157 VertexMode::Base => {
158 out.push_str(" output.position = input.position;\n");
159 out.push_str(" output.diffuse = input.diffuse;\n");
160 }
161 VertexMode::D3 => {
162 out.push_str(" var position = mul_vec4_mat4(input.position, u.g_mat_world);\n");
163 out.push_str(" position = mul_vec4_mat4(position, u.g_mat_view_proj);\n");
164 out.push_str(" output.position = position;\n");
165 out.push_str(" output.diffuse = input.diffuse * u.g_mtrl_diffuse;\n");
166 }
167 VertexMode::D3Fog => {
168 out.push_str(" var position = mul_vec4_mat4(input.position, u.g_mat_world);\n");
169 out.push_str(" output.world_pos = position;\n");
170 out.push_str(" position = mul_vec4_mat4(position, u.g_mat_view_proj);\n");
171 out.push_str(" output.proj_pos = position;\n");
172 out.push_str(" output.position = position;\n");
173 out.push_str(" output.diffuse = input.diffuse * u.g_mtrl_diffuse;\n");
174 }
175 VertexMode::D3Light => {
176 out.push_str(" var position = mul_vec4_mat4(input.position, u.g_mat_world);\n");
177 out.push_str(" output.world_pos = position;\n");
178 out.push_str(" position = mul_vec4_mat4(position, u.g_mat_view_proj);\n");
179 out.push_str(" output.proj_pos = position;\n");
180 out.push_str(" output.position = position;\n");
181 out.push_str(" output.normal = mul_vec3_mat4(input.normal, u.g_mat_world);\n");
182 out.push_str(" output.diffuse = input.diffuse * u.g_mtrl_diffuse;\n");
183 }
184 }
185 out.push_str(" output.texture_uv = input.texture_uv;\n");
186 if needs_mask_uv {
187 out.push_str(" output.mask_uv = input.mask_uv;\n");
188 }
189 out.push_str(" return output;\n");
190 out.push_str("}\n");
191 out
192}
193
194fn regular_fragment_wgsl(t: RegularTechnique) -> String {
195 let mut out = String::new();
196 push_uniforms(&mut out);
197 push_texture_bindings(
198 &mut out,
199 t.flags.tex,
200 t.flags.mask,
201 t.flags.tonecurve,
202 matches!(t.pixel, PixelMode::V1Fog | PixelMode::V2Light),
203 false,
204 false,
205 false,
206 );
207 push_regular_helpers(&mut out, t);
208
209 out.push_str("struct PSInput {\n");
210 out.push_str(" @location(2) diffuse: vec4<f32>,\n");
211 if t.flags.tex {
212 out.push_str(" @location(4) texcoord0: vec2<f32>,\n");
213 }
214 if t.flags.mask {
215 out.push_str(" @location(5) mask_uv: vec2<f32>,\n");
216 }
217 match t.pixel {
218 PixelMode::V0 => {}
219 PixelMode::V1Fog => {
220 out.push_str(" @location(5) world_pos: vec4<f32>,\n");
221 out.push_str(" @location(6) proj_pos: vec4<f32>,\n");
222 }
223 PixelMode::V2Light => {
224 out.push_str(" @location(5) normal: vec3<f32>,\n");
225 out.push_str(" @location(6) world_pos: vec4<f32>,\n");
226 out.push_str(" @location(7) proj_pos: vec4<f32>,\n");
227 }
228 }
229 out.push_str("};\n\n");
230
231 out.push_str("@fragment\n");
232 out.push_str("fn main(input: PSInput) -> @location(0) vec4<f32> {\n");
233 out.push_str(" var color = input.diffuse;\n");
234 if t.flags.tex {
235 out.push_str(" let texture_uv = vec2<f32>(input.texcoord0.x, input.texcoord0.y);\n");
236 out.push_str(" color = color * textureSample(tex00, samp_tex00, texture_uv);\n");
237 }
238 if t.flags.mrbd
239 || t.flags.rgb
240 || t.flags.tonecurve
241 || t.flags.mul
242 || t.flags.screen
243 || !matches!(t.pixel, PixelMode::V0)
244 {
245 out.push_str(" let color_org = color;\n");
246 if matches!(t.pixel, PixelMode::V2Light) {
247 out.push_str(" if (u.g_light_pos.w > 0.5) {\n");
248 out.push_str(" color = calc_light(color, input.world_pos, input.normal);\n");
249 out.push_str(" }\n");
250 }
251 if matches!(t.pixel, PixelMode::V1Fog | PixelMode::V2Light) {
252 out.push_str(" if (u.g_fog_range.x > 0.5) {\n");
253 out.push_str(" color = calc_fog(color, input.world_pos, input.proj_pos);\n");
254 out.push_str(" }\n");
255 }
256 if t.flags.tonecurve || t.flags.mrbd {
257 out.push_str(" let mono_y = dot(vec4<f32>(0.2989, 0.5886, 0.1145, 0.0), color);\n");
258 }
259 if t.flags.tonecurve {
260 out.push_str(" color = tonecurve(color, mono_y);\n");
261 }
262 if t.flags.mrbd {
263 out.push_str(" let reverse = vec4<f32>(1.0) - color;\n");
264 out.push_str(" color = mix(color, reverse, u.c[0].y);\n");
265 out.push_str(" color = mix(color, vec4<f32>(mono_y), u.c[0].x);\n");
266 out.push_str(" color = color + vec4<f32>(u.c[0].z);\n");
267 out.push_str(" color = color - vec4<f32>(u.c[0].w);\n");
268 }
269 if t.flags.rgb {
270 out.push_str(" color = mix(color, u.c[1], u.c[1].w);\n");
271 out.push_str(" color = color + u.c[2];\n");
272 }
273 if t.flags.mul {
274 out.push_str(" color = mix(vec4<f32>(1.0), color, color_org.a);\n");
275 }
276 if t.flags.screen {
277 out.push_str(" color = mix(vec4<f32>(0.0), color, color_org.a);\n");
278 }
279 out.push_str(" color.a = color_org.a;\n");
280 }
281 if t.flags.mask {
282 out.push_str(" let mask_color = textureSample(tex01, samp_tex01, input.mask_uv);\n");
283 out.push_str(" color = color * mask_color;\n");
284 }
285 out.push_str(" return color;\n");
286 out.push_str("}\n");
287 out
288}
289
290fn push_regular_helpers(out: &mut String, t: RegularTechnique) {
291 if t.flags.tonecurve {
292 out.push_str("fn tonecurve(color_in: vec4<f32>, mono_y: f32) -> vec4<f32> {\n");
293 out.push_str(" var color = mix(color_in, vec4<f32>(mono_y), u.c[3].g);\n");
294 out.push_str(" var tonecurve_pos = vec2<f32>(color.r, u.c[3].r);\n");
295 out.push_str(
296 " var tonecurve_color = textureSample(tex02, samp_tex02, tonecurve_pos);\n",
297 );
298 out.push_str(" color.r = tonecurve_color.r;\n");
299 out.push_str(" tonecurve_pos = vec2<f32>(color.g, u.c[3].r);\n");
300 out.push_str(" tonecurve_color = textureSample(tex02, samp_tex02, tonecurve_pos);\n");
301 out.push_str(" color.g = tonecurve_color.g;\n");
302 out.push_str(" tonecurve_pos = vec2<f32>(color.b, u.c[3].r);\n");
303 out.push_str(" tonecurve_color = textureSample(tex02, samp_tex02, tonecurve_pos);\n");
304 out.push_str(" color.b = tonecurve_color.b;\n");
305 out.push_str(" return color;\n");
306 out.push_str("}\n\n");
307 }
308 if matches!(t.pixel, PixelMode::V2Light) {
309 push_calc_light(out);
310 }
311 if matches!(t.pixel, PixelMode::V1Fog | PixelMode::V2Light) {
312 push_calc_fog(out);
313 }
314}
315
316fn special_fragment_wgsl(name: &str) -> Option<String> {
317 match name {
318 "tec_tex2_mask" => Some(wgsl_tex2_mask()),
319 "tec_tex1_shimi" => Some(wgsl_tex1_shimi(false)),
320 "tec_tex1_shimi_inv" => Some(wgsl_tex1_shimi(true)),
321 "tec_tex2_raster_h" => Some(wgsl_tex2_raster(true)),
322 "tec_tex2_raster_v" => Some(wgsl_tex2_raster(false)),
323 "tec_tex1_raster_h" => Some(wgsl_tex1_raster(true)),
324 "tec_tex1_raster_v" => Some(wgsl_tex1_raster(false)),
325 "tec_tex2_explosion_blur" => Some(wgsl_tex2_explosion_blur()),
326 "tec_tex1_explosion_blur" => Some(wgsl_tex1_explosion_blur()),
327 "tec_tex1_mosaic" => Some(wgsl_tex1_mosaic()),
328 _ => None,
329 }
330}
331
332fn push_uniforms(out: &mut String) {
333 out.push_str("struct SiglusUniforms {\n");
334 out.push_str(" g_mat_world: mat4x4<f32>,\n");
335 out.push_str(" g_mat_view_proj: mat4x4<f32>,\n");
336 out.push_str(" g_mtrl_diffuse: vec4<f32>,\n");
337 out.push_str(" g_camera_pos: vec4<f32>,\n");
338 out.push_str(" g_camera_dir: vec4<f32>,\n");
339 out.push_str(" g_light_pos: vec4<f32>,\n");
340 out.push_str(" g_light_ambient: vec4<f32>,\n");
341 out.push_str(" g_fog_param: vec4<f32>,\n");
342 out.push_str(" g_fog_range: vec4<f32>,\n");
343 out.push_str(" c: array<vec4<f32>, 4>,\n");
344 out.push_str("};\n");
345 out.push_str("@group(0) @binding(0) var<uniform> u: SiglusUniforms;\n\n");
346}
347
348fn push_texture_bindings(
349 out: &mut String,
350 tex00: bool,
351 tex01: bool,
352 tex02: bool,
353 tex03: bool,
354 tex00_point: bool,
355 _tex01_point: bool,
356 _tex02_point: bool,
357) {
358 if tex00 || tex00_point {
359 out.push_str("@group(1) @binding(0) var tex00: texture_2d<f32>;\n");
360 }
361 if tex00 {
362 out.push_str("@group(1) @binding(1) var samp_tex00: sampler;\n");
363 }
364 if tex01 {
365 out.push_str("@group(1) @binding(2) var tex01: texture_2d<f32>;\n");
366 out.push_str("@group(1) @binding(3) var samp_tex01: sampler;\n");
367 }
368 if tex02 {
369 out.push_str("@group(1) @binding(4) var tex02: texture_2d<f32>;\n");
370 out.push_str("@group(1) @binding(5) var samp_tex02: sampler;\n");
371 }
372 if tex03 {
373 out.push_str("@group(1) @binding(6) var tex03: texture_2d<f32>;\n");
374 out.push_str("@group(1) @binding(7) var samp_tex03: sampler;\n");
375 }
376 if tex00_point {
377 out.push_str("@group(1) @binding(8) var samp_tex00_point: sampler;\n");
378 }
379 if tex00 || tex01 || tex02 || tex03 || tex00_point {
380 out.push('\n');
381 }
382}
383
384fn push_ps_input_texcoord(out: &mut String) {
385 out.push_str("struct PSInput {\n");
386 out.push_str(" @location(2) diffuse: vec4<f32>,\n");
387 out.push_str(" @location(4) texcoord0: vec2<f32>,\n");
388 out.push_str("};\n\n");
389}
390
391fn push_calc_light(out: &mut String) {
392 out.push_str("fn calc_light(color_in: vec4<f32>, world_pos: vec4<f32>, normal: vec3<f32>) -> vec4<f32> {\n");
393 out.push_str(" var color = color_in;\n");
394 out.push_str(" let dir_point = u.g_light_pos.xyz - world_pos.xyz;\n");
395 out.push_str(" let distance_point = length(dir_point);\n");
396 out.push_str(" var light_power = dot(normalize(normal), normalize(dir_point));\n");
397 out.push_str(" light_power = light_power * (1.0 - distance_point / 2000.0);\n");
398 out.push_str(" light_power = clamp(light_power, 0.0, 1.0);\n");
399 out.push_str(" color = color * vec4<f32>(light_power);\n");
400 out.push_str(" color = color * u.g_light_ambient;\n");
401 out.push_str(" return color;\n");
402 out.push_str("}\n\n");
403}
404
405fn push_calc_fog(out: &mut String) {
406 out.push_str("fn calc_fog(color_in: vec4<f32>, world_pos: vec4<f32>, proj_pos: vec4<f32>) -> vec4<f32> {\n");
407 out.push_str(" var color = color_in;\n");
408 out.push_str(" let camera_dir = u.g_camera_pos.xyz - world_pos.xyz;\n");
409 out.push_str(" let camera_distance = length(camera_dir);\n");
410 out.push_str(" let fog_uv = vec2<f32>((proj_pos.x / proj_pos.w + 1.0) / 2.0 * u.g_fog_param.z + u.g_fog_param.x, 1.0 - (proj_pos.y / proj_pos.w + 1.0) / 2.0) * u.g_fog_param.w + vec2<f32>(u.g_fog_param.y);\n");
411 out.push_str(" let fog_color = textureSample(tex03, samp_tex03, fog_uv);\n");
412 out.push_str(" var fog_rate = (1.0 - 0.0) / (u.g_fog_range.z - u.g_fog_range.y) * (camera_distance - u.g_fog_range.y);\n");
413 out.push_str(" fog_rate = clamp(fog_rate, 0.0, 1.0);\n");
414 out.push_str(" color = vec4<f32>(mix(color.rgb, fog_color.rgb, fog_rate), color.a);\n");
415 out.push_str(" return color;\n");
416 out.push_str("}\n\n");
417}
418
419fn push_brightness(out: &mut String) {
420 out.push_str("fn get_rgb_brightness(rgb: vec4<f32>) -> f32 {\n");
421 out.push_str(" return dot(vec4<f32>(0.2989, 0.5886, 0.1145, 0.0), rgb);\n");
422 out.push_str("}\n\n");
423}
424
425fn push_in_uv_range(out: &mut String) {
426 out.push_str("fn in_uv_range(uv: vec2<f32>) -> bool {\n");
427 out.push_str(" return uv.x >= 0.0 && uv.x <= 1.0 && uv.y >= 0.0 && uv.y <= 1.0;\n");
428 out.push_str("}\n\n");
429}
430
431fn push_log10(out: &mut String) {
432 out.push_str("fn log10_scalar(v: f32) -> f32 {\n");
433 out.push_str(" return log(v) / log(10.0);\n");
434 out.push_str("}\n\n");
435}
436
437fn wgsl_tex2_mask() -> String {
438 let mut out = String::new();
439 push_uniforms(&mut out);
440 push_texture_bindings(&mut out, true, true, false, false, false, false, false);
441 push_ps_input_texcoord2(&mut out);
442 out.push_str("@fragment\n");
443 out.push_str("fn main(input: PSInput) -> @location(0) vec4<f32> {\n");
444 out.push_str(" let tex = textureSample(tex00, samp_tex00, input.texcoord0);\n");
445 out.push_str(" let mask = textureSample(tex01, samp_tex01, input.texcoord1);\n");
446 out.push_str(" let fade = mix(256.0, 2.0, u.c[0].r);\n");
447 out.push_str(
448 " var color = (u.c[0] * fade + mask * (fade - 1.0) - vec4<f32>(fade - 1.0)) * tex;\n",
449 );
450 out.push_str(" color = vec4<f32>(tex.r, tex.g, tex.b, color.a);\n");
451 out.push_str(" return color;\n");
452 out.push_str("}\n");
453 out
454}
455
456fn push_ps_input_texcoord2(out: &mut String) {
457 out.push_str("struct PSInput {\n");
458 out.push_str(" @location(2) diffuse: vec4<f32>,\n");
459 out.push_str(" @location(4) texcoord0: vec2<f32>,\n");
460 out.push_str(" @location(5) texcoord1: vec2<f32>,\n");
461 out.push_str("};\n\n");
462}
463
464fn wgsl_tex1_shimi(inv: bool) -> String {
465 let mut out = String::new();
466 push_uniforms(&mut out);
467 push_texture_bindings(&mut out, true, false, false, false, false, false, false);
468 push_brightness(&mut out);
469 push_ps_input_texcoord(&mut out);
470 out.push_str("@fragment\n");
471 out.push_str("fn main(input: PSInput) -> @location(0) vec4<f32> {\n");
472 out.push_str(" let tex = textureSample(tex00, samp_tex00, input.texcoord0);\n");
473 out.push_str(" var color = tex;\n");
474 if inv {
475 out.push_str(" if (get_rgb_brightness(color) < 1.0 - u.c[0].w) {\n");
476 } else {
477 out.push_str(" if (get_rgb_brightness(color) > u.c[0].w) {\n");
478 }
479 out.push_str(" color.a = tex.a * (u.c[0].x - mix(u.c[0].x, 0.0, u.c[0].w));\n");
480 out.push_str(" }\n");
481 out.push_str(" return color;\n");
482 out.push_str("}\n");
483 out
484}
485
486fn wgsl_tex2_raster(horizontal: bool) -> String {
487 let mut out = String::new();
488 push_uniforms(&mut out);
489 push_texture_bindings(&mut out, true, true, false, false, false, false, false);
490 push_in_uv_range(&mut out);
491 push_log10(&mut out);
492 push_ps_input_texcoord(&mut out);
493 out.push_str("@fragment\n");
494 out.push_str("fn main(input: PSInput) -> @location(0) vec4<f32> {\n");
495 out.push_str(" let fraction_num = u.c[0].x;\n");
496 if horizontal {
497 out.push_str(" var tex_coord_for_sin = floor(input.texcoord0.y * fraction_num);\n");
498 } else {
499 out.push_str(" var tex_coord_for_sin = floor(input.texcoord0.x * fraction_num);\n");
500 }
501 out.push_str(" tex_coord_for_sin = tex_coord_for_sin - fraction_num * 0.1;\n");
502 out.push_str(" tex_coord_for_sin = tex_coord_for_sin / fraction_num;\n");
503 out.push_str(" var raster_power = 1.0;\n");
504 out.push_str(" var st_tex_rate = 0.0;\n");
505 out.push_str(" var ed_tex_rate = 0.0;\n");
506 out.push_str(" if (u.c[0].w < 0.5) {\n");
507 out.push_str(" raster_power = 1.0 - mix(1.0, 0.0, u.c[0].w * 2.0);\n");
508 out.push_str(" st_tex_rate = mix(2.0, 0.0, u.c[0].w * 2.0);\n");
509 out.push_str(" if (st_tex_rate > 1.0) { st_tex_rate = 1.0; }\n");
510 out.push_str(" } else {\n");
511 out.push_str(" raster_power = 1.0 - mix(0.0, 2.0, u.c[0].w - 0.5);\n");
512 out.push_str(" ed_tex_rate = mix(0.0, 4.0, u.c[0].w - 0.5);\n");
513 out.push_str(" if (ed_tex_rate > 1.0) { ed_tex_rate = 1.0; }\n");
514 out.push_str(" }\n");
515 out.push_str(" let raster_offset = sin(3.14 * u.c[0].w * u.c[0].z + tex_coord_for_sin * 3.14 * u.c[0].y) * (1.0 - (log10_scalar((1.0 - raster_power) * 100.0) + 1.0) / 3.0);\n");
516 if horizontal {
517 out.push_str(" let raster_uv = vec2<f32>(input.texcoord0.x + raster_offset, input.texcoord0.y);\n");
518 } else {
519 out.push_str(" let raster_uv = vec2<f32>(input.texcoord0.x, input.texcoord0.y + raster_offset);\n");
520 }
521 out.push_str(" var tex0 = textureSample(tex00, samp_tex00, raster_uv);\n");
522 out.push_str(" var tex1 = textureSample(tex01, samp_tex01, raster_uv);\n");
523 out.push_str(" if (!in_uv_range(raster_uv)) {\n");
524 out.push_str(" tex0 = vec4<f32>(0.0);\n");
525 out.push_str(" tex1 = vec4<f32>(0.0);\n");
526 out.push_str(" }\n");
527 out.push_str(" let color = tex1 * st_tex_rate + tex0 * ed_tex_rate;\n");
528 out.push_str(" return color;\n");
529 out.push_str("}\n");
530 out
531}
532
533fn wgsl_tex1_raster(horizontal: bool) -> String {
534 let mut out = String::new();
535 push_uniforms(&mut out);
536 push_texture_bindings(&mut out, true, false, false, false, false, false, false);
537 push_in_uv_range(&mut out);
538 push_log10(&mut out);
539 push_ps_input_texcoord(&mut out);
540 out.push_str("@fragment\n");
541 out.push_str("fn main(input: PSInput) -> @location(0) vec4<f32> {\n");
542 out.push_str(" let fraction_num = u.c[0].x;\n");
543 if horizontal {
544 out.push_str(" var tex_coord_for_sin = floor(input.texcoord0.y * fraction_num);\n");
545 } else {
546 out.push_str(" var tex_coord_for_sin = floor(input.texcoord0.x * fraction_num);\n");
547 }
548 out.push_str(" tex_coord_for_sin = tex_coord_for_sin - fraction_num * 0.1;\n");
549 out.push_str(" tex_coord_for_sin = tex_coord_for_sin / fraction_num;\n");
550 out.push_str(" let raster_power = 1.0 - u.c[0].w;\n");
551 out.push_str(" let tex_rate = u.c[0].w;\n");
552 out.push_str(" let raster_offset = sin(3.14 * u.c[0].w * u.c[0].z + tex_coord_for_sin * 3.14 * u.c[0].y) * (1.0 - (log10_scalar((1.0 - raster_power) * 100.0) + 1.0) / 3.0);\n");
553 if horizontal {
554 out.push_str(" let raster_uv = vec2<f32>(input.texcoord0.x + raster_offset, input.texcoord0.y);\n");
555 } else {
556 out.push_str(" let raster_uv = vec2<f32>(input.texcoord0.x, input.texcoord0.y + raster_offset);\n");
557 }
558 out.push_str(" var tex = textureSample(tex00, samp_tex00, raster_uv);\n");
559 out.push_str(" if (!in_uv_range(raster_uv)) {\n");
560 out.push_str(" tex = vec4<f32>(0.0);\n");
561 out.push_str(" }\n");
562 out.push_str(" var color = tex;\n");
563 out.push_str(" color.a = tex.a * tex_rate;\n");
564 out.push_str(" return color;\n");
565 out.push_str("}\n");
566 out
567}
568
569fn wgsl_tex2_explosion_blur() -> String {
570 let mut out = String::new();
571 push_uniforms(&mut out);
572 push_texture_bindings(&mut out, true, true, false, false, false, false, false);
573 push_ps_input_texcoord(&mut out);
574 out.push_str("@fragment\n");
575 out.push_str("fn main(input: PSInput) -> @location(0) vec4<f32> {\n");
576 out.push_str(" let center_texel = vec2<f32>(u.c[0].z, u.c[0].w);\n");
577 out.push_str(" var dir = center_texel - input.texcoord0;\n");
578 out.push_str(" let len = length(dir);\n");
579 out.push_str(" dir = normalize(dir) * vec2<f32>(u.c[0].x, u.c[0].x);\n");
580 out.push_str(" dir = dir * u.c[1].x * len * u.c[1].y;\n");
581 out.push_str(" let color0 = textureSample(tex01, samp_tex01, input.texcoord0) * 0.40 + textureSample(tex01, samp_tex01, input.texcoord0 + dir * 2.0) * 0.24 + textureSample(tex01, samp_tex01, input.texcoord0 + dir * 4.0) * 0.16 + textureSample(tex01, samp_tex01, input.texcoord0 + dir * 6.0) * 0.14 + textureSample(tex01, samp_tex01, input.texcoord0 + dir * 8.0) * 0.06;\n");
582 out.push_str(" let color1 = textureSample(tex00, samp_tex00, input.texcoord0) * 0.40 + textureSample(tex00, samp_tex00, input.texcoord0 + dir * 2.0) * 0.24 + textureSample(tex00, samp_tex00, input.texcoord0 + dir * 4.0) * 0.16 + textureSample(tex00, samp_tex00, input.texcoord0 + dir * 6.0) * 0.14 + textureSample(tex00, samp_tex00, input.texcoord0 + dir * 8.0) * 0.06;\n");
583 out.push_str(" return input.diffuse.a * color0 + (1.0 - input.diffuse.a) * color1;\n");
584 out.push_str("}\n");
585 out
586}
587
588fn wgsl_tex1_explosion_blur() -> String {
589 let mut out = String::new();
590 push_uniforms(&mut out);
591 push_texture_bindings(&mut out, true, false, false, false, false, false, false);
592 push_ps_input_texcoord(&mut out);
593 out.push_str("@fragment\n");
594 out.push_str("fn main(input: PSInput) -> @location(0) vec4<f32> {\n");
595 out.push_str(" let center_texel = vec2<f32>(u.c[0].z, u.c[0].w);\n");
596 out.push_str(" var dir = center_texel - input.texcoord0;\n");
597 out.push_str(" let len = length(dir);\n");
598 out.push_str(" dir = normalize(dir) * vec2<f32>(u.c[0].x, u.c[0].x);\n");
599 out.push_str(" dir = dir * u.c[1].x * len * u.c[1].y;\n");
600 out.push_str(" var color = textureSample(tex00, samp_tex00, input.texcoord0) * 0.19;\n");
601 out.push_str(
602 " color = color + textureSample(tex00, samp_tex00, input.texcoord0 + dir) * 0.17;\n",
603 );
604 out.push_str(" color = color + textureSample(tex00, samp_tex00, input.texcoord0 + dir * 2.0) * 0.15;\n");
605 out.push_str(" color = color + textureSample(tex00, samp_tex00, input.texcoord0 + dir * 3.0) * 0.13;\n");
606 out.push_str(" color = color + textureSample(tex00, samp_tex00, input.texcoord0 + dir * 4.0) * 0.11;\n");
607 out.push_str(" color = color + textureSample(tex00, samp_tex00, input.texcoord0 + dir * 5.0) * 0.09;\n");
608 out.push_str(" color = color + textureSample(tex00, samp_tex00, input.texcoord0 + dir * 6.0) * 0.07;\n");
609 out.push_str(" color = color + textureSample(tex00, samp_tex00, input.texcoord0 + dir * 7.0) * 0.05;\n");
610 out.push_str(" color = color + textureSample(tex00, samp_tex00, input.texcoord0 + dir * 8.0) * 0.03;\n");
611 out.push_str(" color = color + textureSample(tex00, samp_tex00, input.texcoord0 + dir * 9.0) * 0.01;\n");
612 out.push_str(" color.a = input.diffuse.a;\n");
613 out.push_str(" return color;\n");
614 out.push_str("}\n");
615 out
616}
617
618fn wgsl_tex1_mosaic() -> String {
619 let mut out = String::new();
620 push_uniforms(&mut out);
621 push_texture_bindings(&mut out, false, false, false, false, true, false, false);
622 push_ps_input_texcoord(&mut out);
623 out.push_str("@fragment\n");
624 out.push_str("fn main(input: PSInput) -> @location(0) vec4<f32> {\n");
625 out.push_str(" let cut_per_texel_u = u.c[0].x;\n");
626 out.push_str(" let cut_per_texel_u_inv = 1.0 / cut_per_texel_u;\n");
627 out.push_str(" let cut_per_texel_v = u.c[0].x * u.c[0].y;\n");
628 out.push_str(" let cut_per_texel_v_inv = 1.0 / cut_per_texel_v;\n");
629 out.push_str(" let tc = vec2<f32>(floor(cut_per_texel_u_inv * input.texcoord0.x) * cut_per_texel_u, floor(cut_per_texel_v_inv * input.texcoord0.y) * cut_per_texel_v);\n");
630 out.push_str(" var color = textureSample(tex00, samp_tex00_point, tc);\n");
631 out.push_str(" color.a = input.diffuse.a;\n");
632 out.push_str(" return color;\n");
633 out.push_str("}\n");
634 out
635}