diff --git a/.gitignore b/.gitignore index 1d13293..7909c4b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ games/*/saves/ .DS_Store web/dist/ web/game.bundle.json +.claude/ diff --git a/mrpci/src/main.rs b/mrpci/src/main.rs index ac9adf9..94c6e21 100644 --- a/mrpci/src/main.rs +++ b/mrpci/src/main.rs @@ -229,21 +229,25 @@ async fn amain(game_dir: String) { let mut index_img = Image::gen_image_color(PIC_W as u16, PIC_H as u16, BLACK); let index_tex = Texture2D::from_image(&index_img); index_tex.set_filter(FilterMode::Nearest); - let mut pal_img = Image::gen_image_color(256, 1, BLACK); - let pal_tex = Texture2D::from_image(&pal_img); - pal_tex.set_filter(FilterMode::Nearest); - let material = load_material( - ShaderSource::Glsl { vertex: CRT_VERTEX, fragment: CRT_FRAGMENT }, - MaterialParams { - textures: vec!["palette_tex".to_string()], - uniforms: vec![ - UniformDesc::new("crt", UniformType::Float1), - UniformDesc::new("fade", UniformType::Float1), - ], - ..Default::default() - }, - ) - .expect("CRT shader compiles"); + #[cfg(not(target_arch = "wasm32"))] + let (mut pal_img, pal_tex, material) = { + let pal_img = Image::gen_image_color(256, 1, BLACK); + let pal_tex = Texture2D::from_image(&pal_img); + pal_tex.set_filter(FilterMode::Nearest); + let material = load_material( + ShaderSource::Glsl { vertex: CRT_VERTEX, fragment: CRT_FRAGMENT }, + MaterialParams { + textures: vec!["palette_tex".to_string()], + uniforms: vec![ + UniformDesc::new("crt", UniformType::Float1), + UniformDesc::new("fade", UniformType::Float1), + ], + ..Default::default() + }, + ) + .expect("CRT shader compiles"); + (pal_img, pal_tex, material) + }; let mut last_dir_sent: u8 = 0; let mut ed = editor::Editor::new(); @@ -496,28 +500,51 @@ async fn amain(game_dir: String) { // --- draw ------------------------------------------------------------ clear_background(Color::from_rgba(12, 12, 16, 255)); - // Indices into the R channel; the shader does the palette lookup. - let indices = gs.render_indices(true); - for (i, &idx) in indices.iter().enumerate() { - index_img.bytes[i * 4] = idx; - index_img.bytes[i * 4 + 3] = 255; - } - index_tex.update(&index_img); - pal_img.bytes.copy_from_slice(&gs.effective_palette()); - pal_tex.update(&pal_img); + // Native: indices into the R channel; the CRT shader does the + // palette lookup, scanlines, curvature and fades on the GPU. + #[cfg(not(target_arch = "wasm32"))] + { + let indices = gs.render_indices(true); + for (i, &idx) in indices.iter().enumerate() { + index_img.bytes[i * 4] = idx; + index_img.bytes[i * 4 + 3] = 255; + } + index_tex.update(&index_img); + pal_img.bytes.copy_from_slice(&gs.effective_palette()); + pal_tex.update(&pal_img); - gl_use_material(&material); - material.set_texture("palette_tex", pal_tex.clone()); - material.set_uniform("crt", if ui.scanlines { 1.0f32 } else { 0.0f32 }); - material.set_uniform("fade", ui.fade); - draw_texture_ex( - &index_tex, - 0.0, - BAR_H, - WHITE, - DrawTextureParams { dest_size: Some(vec2(PIC_W as f32 * SCALE, PIC_H as f32 * SCALE)), ..Default::default() }, - ); - gl_use_default_material(); + gl_use_material(&material); + material.set_texture("palette_tex", pal_tex.clone()); + material.set_uniform("crt", if ui.scanlines { 1.0f32 } else { 0.0f32 }); + material.set_uniform("fade", ui.fade); + draw_texture_ex( + &index_tex, + 0.0, + BAR_H, + WHITE, + DrawTextureParams { dest_size: Some(vec2(PIC_W as f32 * SCALE, PIC_H as f32 * SCALE)), ..Default::default() }, + ); + gl_use_default_material(); + } + + // Web: miniquad's GL shim and the multi-texture material don't get + // along (stale-texture binds, frozen frame) — take the MRPGI-proven + // path instead: CPU palette blit, plain textured quad. The CRT stays + // a desktop luxury. + #[cfg(target_arch = "wasm32")] + { + let rgba = gs.render_visual(true); + index_img.bytes.copy_from_slice(&rgba); + index_tex.update(&index_img); + let tint = (ui.fade * 255.0) as u8; + draw_texture_ex( + &index_tex, + 0.0, + BAR_H, + Color::from_rgba(tint, tint, tint, 255), + DrawTextureParams { dest_size: Some(vec2(PIC_W as f32 * SCALE, PIC_H as f32 * SCALE)), ..Default::default() }, + ); + } if ui.flash > 0.0 { draw_rectangle(