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