mirror of https://github.com/AxioDL/metaforce.git
Working movie player
This commit is contained in:
parent
a1482b4743
commit
921d6bf10a
|
@ -9,28 +9,34 @@ use aabb::queue_aabb;
|
||||||
use bytemuck::Pod;
|
use bytemuck::Pod;
|
||||||
use bytemuck_derive::{Pod, Zeroable};
|
use bytemuck_derive::{Pod, Zeroable};
|
||||||
use cxx::{type_id, ExternType};
|
use cxx::{type_id, ExternType};
|
||||||
use cxx::private::hash;
|
|
||||||
use fog_volume_filter::queue_fog_volume_filter;
|
use fog_volume_filter::queue_fog_volume_filter;
|
||||||
use fog_volume_plane::queue_fog_volume_plane;
|
use fog_volume_plane::queue_fog_volume_plane;
|
||||||
use model::{add_material_set, add_model};
|
use model::{add_material_set, add_model};
|
||||||
use texture::{create_render_texture, create_static_texture_2d, drop_texture};
|
use movie_player::queue_movie_player;
|
||||||
use textured_quad::{queue_textured_quad_verts, queue_textured_quad};
|
use texture::{
|
||||||
|
create_dynamic_texture_2d, create_render_texture, create_static_texture_2d, drop_texture,
|
||||||
|
write_texture,
|
||||||
|
};
|
||||||
|
use textured_quad::{queue_textured_quad, queue_textured_quad_verts};
|
||||||
use twox_hash::Xxh3Hash64;
|
use twox_hash::Xxh3Hash64;
|
||||||
use wgpu::RenderPipeline;
|
use wgpu::RenderPipeline;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
gpu::GraphicsConfig,
|
gpu::GraphicsConfig,
|
||||||
|
shaders::{
|
||||||
|
ffi::{TextureFormat, TextureRef},
|
||||||
|
texture::{RenderTexture, TextureWithView},
|
||||||
|
},
|
||||||
zeus::{CColor, CMatrix4f, CRectangle, CVector2f, CVector3f, IDENTITY_MATRIX4F},
|
zeus::{CColor, CMatrix4f, CRectangle, CVector2f, CVector3f, IDENTITY_MATRIX4F},
|
||||||
};
|
};
|
||||||
use crate::shaders::ffi::{TextureFormat, TextureRef};
|
|
||||||
use crate::shaders::texture::{RenderTexture, TextureWithView};
|
|
||||||
|
|
||||||
mod aabb;
|
mod aabb;
|
||||||
mod fog_volume_filter;
|
mod fog_volume_filter;
|
||||||
mod fog_volume_plane;
|
mod fog_volume_plane;
|
||||||
mod model;
|
mod model;
|
||||||
mod textured_quad;
|
mod movie_player;
|
||||||
mod texture;
|
mod texture;
|
||||||
|
mod textured_quad;
|
||||||
|
|
||||||
#[cxx::bridge]
|
#[cxx::bridge]
|
||||||
mod ffi {
|
mod ffi {
|
||||||
|
@ -203,6 +209,14 @@ mod ffi {
|
||||||
rect: CRectangle,
|
rect: CRectangle,
|
||||||
z: f32,
|
z: f32,
|
||||||
);
|
);
|
||||||
|
fn queue_movie_player(
|
||||||
|
tex_y: TextureRef,
|
||||||
|
tex_u: TextureRef,
|
||||||
|
tex_v: TextureRef,
|
||||||
|
color: CColor,
|
||||||
|
h_pad: f32,
|
||||||
|
v_pad: f32,
|
||||||
|
);
|
||||||
|
|
||||||
fn create_static_texture_2d(
|
fn create_static_texture_2d(
|
||||||
width: u32,
|
width: u32,
|
||||||
|
@ -212,6 +226,13 @@ mod ffi {
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
label: &str,
|
label: &str,
|
||||||
) -> TextureRef;
|
) -> TextureRef;
|
||||||
|
fn create_dynamic_texture_2d(
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
mips: u32,
|
||||||
|
format: TextureFormat,
|
||||||
|
label: &str,
|
||||||
|
) -> TextureRef;
|
||||||
fn create_render_texture(
|
fn create_render_texture(
|
||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
|
@ -220,6 +241,7 @@ mod ffi {
|
||||||
depth_bind_count: u32,
|
depth_bind_count: u32,
|
||||||
label: &str,
|
label: &str,
|
||||||
) -> TextureRef;
|
) -> TextureRef;
|
||||||
|
fn write_texture(handle: TextureRef, data: &[u8]);
|
||||||
fn drop_texture(handle: TextureRef);
|
fn drop_texture(handle: TextureRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -310,7 +332,7 @@ enum ShaderDrawCommand {
|
||||||
game_blend_mode: u32,
|
game_blend_mode: u32,
|
||||||
model_flags: u32,
|
model_flags: u32,
|
||||||
},
|
},
|
||||||
MoviePlayer {/* TODO */},
|
MoviePlayer(movie_player::DrawData),
|
||||||
NES {/* TODO */},
|
NES {/* TODO */},
|
||||||
ParticleSwoosh {/* TODO */},
|
ParticleSwoosh {/* TODO */},
|
||||||
PhazonSuitFilter {/* TODO */},
|
PhazonSuitFilter {/* TODO */},
|
||||||
|
@ -347,6 +369,7 @@ struct RenderState {
|
||||||
// Shader states
|
// Shader states
|
||||||
aabb: aabb::State,
|
aabb: aabb::State,
|
||||||
textured_quad: textured_quad::State,
|
textured_quad: textured_quad::State,
|
||||||
|
movie_player: movie_player::State,
|
||||||
}
|
}
|
||||||
pub(crate) fn construct_state(
|
pub(crate) fn construct_state(
|
||||||
device: Arc<wgpu::Device>,
|
device: Arc<wgpu::Device>,
|
||||||
|
@ -370,6 +393,7 @@ pub(crate) fn construct_state(
|
||||||
};
|
};
|
||||||
let aabb = aabb::construct_state(&device, &queue, &buffers);
|
let aabb = aabb::construct_state(&device, &queue, &buffers);
|
||||||
let textured_quad = textured_quad::construct_state(&device, &queue, &buffers, graphics_config);
|
let textured_quad = textured_quad::construct_state(&device, &queue, &buffers, graphics_config);
|
||||||
|
let movie_player = movie_player::construct_state(&device, &queue, &buffers, graphics_config);
|
||||||
let mut state = RenderState {
|
let mut state = RenderState {
|
||||||
device: device.clone(),
|
device: device.clone(),
|
||||||
queue: queue.clone(),
|
queue: queue.clone(),
|
||||||
|
@ -384,6 +408,7 @@ pub(crate) fn construct_state(
|
||||||
render_textures: Default::default(),
|
render_textures: Default::default(),
|
||||||
aabb,
|
aabb,
|
||||||
textured_quad,
|
textured_quad,
|
||||||
|
movie_player,
|
||||||
};
|
};
|
||||||
for config in aabb::INITIAL_PIPELINES {
|
for config in aabb::INITIAL_PIPELINES {
|
||||||
construct_pipeline(&mut state, config);
|
construct_pipeline(&mut state, config);
|
||||||
|
@ -486,6 +511,7 @@ struct PipelineRef {
|
||||||
pub(crate) enum PipelineCreateCommand {
|
pub(crate) enum PipelineCreateCommand {
|
||||||
Aabb(aabb::PipelineConfig),
|
Aabb(aabb::PipelineConfig),
|
||||||
TexturedQuad(textured_quad::PipelineConfig),
|
TexturedQuad(textured_quad::PipelineConfig),
|
||||||
|
MoviePlayer(movie_player::PipelineConfig),
|
||||||
}
|
}
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn hash_with_seed<T: Hash>(value: &T, seed: u64) -> u64 {
|
fn hash_with_seed<T: Hash>(value: &T, seed: u64) -> u64 {
|
||||||
|
@ -497,6 +523,7 @@ fn construct_pipeline(state: &mut RenderState, cmd: &PipelineCreateCommand) -> u
|
||||||
let id = match cmd {
|
let id = match cmd {
|
||||||
PipelineCreateCommand::Aabb(ref config) => hash_with_seed(config, 0xAABB),
|
PipelineCreateCommand::Aabb(ref config) => hash_with_seed(config, 0xAABB),
|
||||||
PipelineCreateCommand::TexturedQuad(ref config) => hash_with_seed(config, 0xEEAD),
|
PipelineCreateCommand::TexturedQuad(ref config) => hash_with_seed(config, 0xEEAD),
|
||||||
|
PipelineCreateCommand::MoviePlayer(ref config) => hash_with_seed(config, 0xFAAE),
|
||||||
};
|
};
|
||||||
if !state.pipelines.contains_key(&id) {
|
if !state.pipelines.contains_key(&id) {
|
||||||
let pipeline = match cmd {
|
let pipeline = match cmd {
|
||||||
|
@ -512,6 +539,12 @@ fn construct_pipeline(state: &mut RenderState, cmd: &PipelineCreateCommand) -> u
|
||||||
&state.textured_quad,
|
&state.textured_quad,
|
||||||
config,
|
config,
|
||||||
),
|
),
|
||||||
|
PipelineCreateCommand::MoviePlayer(ref config) => movie_player::construct_pipeline(
|
||||||
|
state.device.as_ref(),
|
||||||
|
&state.graphics_config,
|
||||||
|
&state.movie_player,
|
||||||
|
config,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
state.pipelines.insert(id, pipeline);
|
state.pipelines.insert(id, pipeline);
|
||||||
}
|
}
|
||||||
|
@ -566,7 +599,20 @@ pub(crate) fn render_into_pass(pass: &mut wgpu::RenderPass) {
|
||||||
aabb::draw_aabb(data, &state.aabb, pass, &state.buffers);
|
aabb::draw_aabb(data, &state.aabb, pass, &state.buffers);
|
||||||
}
|
}
|
||||||
ShaderDrawCommand::TexturedQuad(data) => {
|
ShaderDrawCommand::TexturedQuad(data) => {
|
||||||
textured_quad::draw_textured_quad(data, &state.textured_quad, pass, &state.buffers);
|
textured_quad::draw_textured_quad(
|
||||||
|
data,
|
||||||
|
&state.textured_quad,
|
||||||
|
pass,
|
||||||
|
&state.buffers,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ShaderDrawCommand::MoviePlayer(data) => {
|
||||||
|
movie_player::draw_movie_player(
|
||||||
|
data,
|
||||||
|
&state.movie_player,
|
||||||
|
pass,
|
||||||
|
&state.buffers,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,301 @@
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
hash::{Hash, Hasher},
|
||||||
|
ops::Range,
|
||||||
|
};
|
||||||
|
|
||||||
|
use bytemuck_derive::{Pod, Zeroable};
|
||||||
|
use wgpu::{include_wgsl, vertex_attr_array};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
get_app,
|
||||||
|
gpu::GraphicsConfig,
|
||||||
|
shaders::{
|
||||||
|
bind_pipeline,
|
||||||
|
ffi::{CameraFilterType, TextureRef, ZTest},
|
||||||
|
pipeline_ref, push_draw_command, push_uniform, push_verts,
|
||||||
|
texture::create_sampler,
|
||||||
|
BuiltBuffers, PipelineCreateCommand, PipelineHolder, PipelineRef, ShaderDrawCommand, STATE,
|
||||||
|
},
|
||||||
|
util::{align, Vec2, Vec3},
|
||||||
|
zeus::{CColor, CMatrix4f, CRectangle, CVector4f},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct DrawData {
|
||||||
|
pipeline: PipelineRef,
|
||||||
|
vert_range: Range<u64>,
|
||||||
|
uniform_range: Range<u64>,
|
||||||
|
bind_group_id: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Hash)]
|
||||||
|
pub(crate) struct PipelineConfig {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
pub(crate) const INITIAL_PIPELINES: &[PipelineCreateCommand] =
|
||||||
|
&[PipelineCreateCommand::MoviePlayer(PipelineConfig {})];
|
||||||
|
|
||||||
|
pub(crate) struct State {
|
||||||
|
shader: wgpu::ShaderModule,
|
||||||
|
uniform_layout: wgpu::BindGroupLayout,
|
||||||
|
uniform_bind_group: wgpu::BindGroup,
|
||||||
|
texture_layout: wgpu::BindGroupLayout,
|
||||||
|
sampler: wgpu::Sampler,
|
||||||
|
pipeline_layout: wgpu::PipelineLayout,
|
||||||
|
// Transient state
|
||||||
|
texture_bind_groups: HashMap<u32, wgpu::BindGroup>,
|
||||||
|
frame_used_textures: Vec<u32>, // TODO use to clear bind groups
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn construct_state(
|
||||||
|
device: &wgpu::Device,
|
||||||
|
_queue: &wgpu::Queue,
|
||||||
|
buffers: &BuiltBuffers,
|
||||||
|
graphics_config: &GraphicsConfig,
|
||||||
|
) -> State {
|
||||||
|
let shader = device.create_shader_module(&include_wgsl!("shader.wgsl"));
|
||||||
|
let uniform_alignment = device.limits().min_uniform_buffer_offset_alignment;
|
||||||
|
let uniform_size = wgpu::BufferSize::new(align(
|
||||||
|
std::mem::size_of::<Uniform>() as u64,
|
||||||
|
uniform_alignment as u64,
|
||||||
|
));
|
||||||
|
let uniform_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
|
label: Some("Textured Quad Uniform Bind Group Layout"),
|
||||||
|
entries: &[
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 0,
|
||||||
|
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Buffer {
|
||||||
|
ty: wgpu::BufferBindingType::Uniform,
|
||||||
|
has_dynamic_offset: true,
|
||||||
|
min_binding_size: uniform_size,
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 1,
|
||||||
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
let sampler = create_sampler(device, wgpu::AddressMode::Repeat, None);
|
||||||
|
let uniform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
label: Some("Textured Quad Uniform Bind Group"),
|
||||||
|
layout: &uniform_layout,
|
||||||
|
entries: &[
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
|
||||||
|
buffer: &buffers.uniform_buffer,
|
||||||
|
offset: 0, // dynamic
|
||||||
|
size: uniform_size,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry { binding: 1, resource: wgpu::BindingResource::Sampler(&sampler) },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
let texture_binding = wgpu::BindingType::Texture {
|
||||||
|
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||||
|
view_dimension: wgpu::TextureViewDimension::D2,
|
||||||
|
multisampled: false,
|
||||||
|
};
|
||||||
|
let texture_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
|
label: Some("Textured Quad Texture Bind Group Layout"),
|
||||||
|
entries: &[
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 0,
|
||||||
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
ty: texture_binding,
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 1,
|
||||||
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
ty: texture_binding,
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 2,
|
||||||
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
ty: texture_binding,
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
|
label: Some("Textured Quad Pipeline Layout"),
|
||||||
|
bind_group_layouts: &[&uniform_layout, &texture_layout],
|
||||||
|
push_constant_ranges: &[],
|
||||||
|
});
|
||||||
|
State {
|
||||||
|
shader,
|
||||||
|
uniform_layout,
|
||||||
|
uniform_bind_group,
|
||||||
|
texture_layout,
|
||||||
|
sampler,
|
||||||
|
pipeline_layout,
|
||||||
|
texture_bind_groups: Default::default(),
|
||||||
|
frame_used_textures: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn construct_pipeline(
|
||||||
|
device: &wgpu::Device,
|
||||||
|
graphics: &GraphicsConfig,
|
||||||
|
state: &State,
|
||||||
|
config: &PipelineConfig,
|
||||||
|
) -> PipelineHolder {
|
||||||
|
PipelineHolder {
|
||||||
|
pipeline: device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
|
label: Some("Textured Quad Pipeline"),
|
||||||
|
layout: Some(&state.pipeline_layout),
|
||||||
|
vertex: wgpu::VertexState {
|
||||||
|
module: &state.shader,
|
||||||
|
entry_point: "vs_main",
|
||||||
|
buffers: &[wgpu::VertexBufferLayout {
|
||||||
|
array_stride: std::mem::size_of::<Vert>() as u64,
|
||||||
|
step_mode: wgpu::VertexStepMode::Vertex,
|
||||||
|
attributes: &vertex_attr_array![0 => Float32x3, 1 => Float32x2],
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
primitive: wgpu::PrimitiveState {
|
||||||
|
topology: wgpu::PrimitiveTopology::TriangleStrip,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
depth_stencil: Some(wgpu::DepthStencilState {
|
||||||
|
format: graphics.depth_format,
|
||||||
|
depth_write_enabled: false,
|
||||||
|
depth_compare: wgpu::CompareFunction::Always,
|
||||||
|
stencil: Default::default(),
|
||||||
|
bias: Default::default(),
|
||||||
|
}),
|
||||||
|
multisample: wgpu::MultisampleState {
|
||||||
|
count: graphics.msaa_samples,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
fragment: Some(wgpu::FragmentState {
|
||||||
|
module: &state.shader,
|
||||||
|
entry_point: "fs_main",
|
||||||
|
targets: &[wgpu::ColorTargetState {
|
||||||
|
format: graphics.color_format,
|
||||||
|
blend: Some(wgpu::BlendState {
|
||||||
|
color: wgpu::BlendComponent {
|
||||||
|
src_factor: wgpu::BlendFactor::SrcAlpha,
|
||||||
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
|
operation: wgpu::BlendOperation::Add,
|
||||||
|
},
|
||||||
|
alpha: wgpu::BlendComponent {
|
||||||
|
src_factor: wgpu::BlendFactor::SrcAlpha,
|
||||||
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
|
operation: wgpu::BlendOperation::Add,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
write_mask: wgpu::ColorWrites::COLOR,
|
||||||
|
}],
|
||||||
|
}),
|
||||||
|
multiview: None,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Pod, Zeroable, Copy, Clone, Default, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct Uniform {
|
||||||
|
xf: CMatrix4f,
|
||||||
|
color: CColor,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Pod, Zeroable, Copy, Clone, Default, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct Vert {
|
||||||
|
pos: Vec3<f32>,
|
||||||
|
uv: Vec2<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn queue_movie_player(
|
||||||
|
tex_y: TextureRef,
|
||||||
|
tex_u: TextureRef,
|
||||||
|
tex_v: TextureRef,
|
||||||
|
color: CColor,
|
||||||
|
h_pad: f32,
|
||||||
|
v_pad: f32,
|
||||||
|
) {
|
||||||
|
let pipeline = pipeline_ref(&PipelineCreateCommand::MoviePlayer(PipelineConfig {}));
|
||||||
|
let vert_range = push_verts(&[
|
||||||
|
Vert { pos: Vec3::new(-h_pad, v_pad, 0.0), uv: Vec2::new(0.0, 0.0) },
|
||||||
|
Vert { pos: Vec3::new(-h_pad, -v_pad, 0.0), uv: Vec2::new(0.0, 1.0) },
|
||||||
|
Vert { pos: Vec3::new(h_pad, v_pad, 0.0), uv: Vec2::new(1.0, 0.0) },
|
||||||
|
Vert { pos: Vec3::new(h_pad, -v_pad, 0.0), uv: Vec2::new(1.0, 1.0) },
|
||||||
|
]);
|
||||||
|
let uniform_range = push_uniform(&Uniform { xf: CMatrix4f::default(), color });
|
||||||
|
|
||||||
|
// TODO defer bind group creation to draw time or another thread?
|
||||||
|
let state = unsafe { STATE.as_mut().unwrap_unchecked() };
|
||||||
|
let groups = &mut state.movie_player.texture_bind_groups;
|
||||||
|
let mut hasher = twox_hash::XxHash32::default();
|
||||||
|
tex_y.id.hash(&mut hasher);
|
||||||
|
tex_u.id.hash(&mut hasher);
|
||||||
|
tex_v.id.hash(&mut hasher);
|
||||||
|
let bind_group_id = hasher.finish() as u32;
|
||||||
|
if !groups.contains_key(&bind_group_id) {
|
||||||
|
let tex_y = state.textures.get(&tex_y.id).unwrap();
|
||||||
|
let tex_u = state.textures.get(&tex_u.id).unwrap();
|
||||||
|
let tex_v = state.textures.get(&tex_v.id).unwrap();
|
||||||
|
let bind_group = get_app().gpu.device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
label: None,
|
||||||
|
layout: &state.movie_player.texture_layout,
|
||||||
|
entries: &[
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: wgpu::BindingResource::TextureView(&tex_y.view),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 1,
|
||||||
|
resource: wgpu::BindingResource::TextureView(&tex_u.view),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 2,
|
||||||
|
resource: wgpu::BindingResource::TextureView(&tex_v.view),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
groups.insert(bind_group_id, bind_group);
|
||||||
|
}
|
||||||
|
|
||||||
|
push_draw_command(ShaderDrawCommand::MoviePlayer(DrawData {
|
||||||
|
pipeline,
|
||||||
|
vert_range,
|
||||||
|
uniform_range,
|
||||||
|
bind_group_id,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn draw_movie_player<'a>(
|
||||||
|
data: &DrawData,
|
||||||
|
state: &'a State,
|
||||||
|
pass: &mut wgpu::RenderPass<'a>,
|
||||||
|
buffers: &'a BuiltBuffers,
|
||||||
|
) {
|
||||||
|
if !bind_pipeline(data.pipeline, pass) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uniform bind group
|
||||||
|
pass.set_bind_group(0, &state.uniform_bind_group, &[
|
||||||
|
data.uniform_range.start as wgpu::DynamicOffset
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Texture bind group
|
||||||
|
let texture_bind_group = state
|
||||||
|
.texture_bind_groups
|
||||||
|
.get(&data.bind_group_id)
|
||||||
|
.expect("Failed to find texture bind group");
|
||||||
|
pass.set_bind_group(1, texture_bind_group, &[]);
|
||||||
|
|
||||||
|
// Vertex buffer
|
||||||
|
pass.set_vertex_buffer(0, buffers.vertex_buffer.slice(data.vert_range.clone()));
|
||||||
|
pass.draw(0..4, 0..1);
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
struct Uniform {
|
||||||
|
xf: mat4x4<f32>;
|
||||||
|
color: vec4<f32>;
|
||||||
|
};
|
||||||
|
@group(0) @binding(0)
|
||||||
|
var<uniform> ubuf: Uniform;
|
||||||
|
@group(0) @binding(1)
|
||||||
|
var tex_sampler: sampler;
|
||||||
|
@group(1) @binding(0)
|
||||||
|
var tex_y: texture_2d<f32>;
|
||||||
|
@group(1) @binding(1)
|
||||||
|
var tex_u: texture_2d<f32>;
|
||||||
|
@group(1) @binding(2)
|
||||||
|
var tex_v: texture_2d<f32>;
|
||||||
|
|
||||||
|
struct VertexOutput {
|
||||||
|
@builtin(position) pos: vec4<f32>;
|
||||||
|
@location(0) uv: vec2<f32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
@stage(vertex)
|
||||||
|
fn vs_main(@location(0) in_pos: vec3<f32>, @location(1) in_uv: vec2<f32>) -> VertexOutput {
|
||||||
|
var out: VertexOutput;
|
||||||
|
out.pos = ubuf.xf * vec4<f32>(in_pos, 1.0);
|
||||||
|
out.uv = in_uv;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@stage(fragment)
|
||||||
|
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
|
var yuv = vec3<f32>(
|
||||||
|
1.1643 * (textureSample(tex_y, tex_sampler, in.uv).x - 0.0625),
|
||||||
|
textureSample(tex_u, tex_sampler, in.uv).x - 0.5,
|
||||||
|
textureSample(tex_v, tex_sampler, in.uv).x - 0.5
|
||||||
|
);
|
||||||
|
return ubuf.color * vec4<f32>(
|
||||||
|
yuv.x + 1.5958 * yuv.z,
|
||||||
|
yuv.x - 0.39173 * yuv.y - 0.8129 * yuv.z,
|
||||||
|
yuv.x + 2.017 * yuv.y,
|
||||||
|
1.0
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,8 +1,11 @@
|
||||||
use std::hash::{Hash, Hasher};
|
use std::{
|
||||||
use std::num::NonZeroU8;
|
collections::hash_map::Entry::{Occupied, Vacant},
|
||||||
|
hash::{Hash, Hasher},
|
||||||
|
num::{NonZeroU32, NonZeroU8},
|
||||||
|
};
|
||||||
|
|
||||||
use twox_hash::XxHash32;
|
use twox_hash::XxHash32;
|
||||||
use wgpu::util::DeviceExt;
|
use wgpu::{util::DeviceExt, ImageDataLayout};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
get_app,
|
get_app,
|
||||||
|
@ -15,11 +18,13 @@ use crate::{
|
||||||
pub(crate) struct TextureWithView {
|
pub(crate) struct TextureWithView {
|
||||||
pub(crate) texture: wgpu::Texture,
|
pub(crate) texture: wgpu::Texture,
|
||||||
pub(crate) view: wgpu::TextureView,
|
pub(crate) view: wgpu::TextureView,
|
||||||
|
pub(crate) format: wgpu::TextureFormat,
|
||||||
|
pub(crate) extent: wgpu::Extent3d,
|
||||||
}
|
}
|
||||||
impl TextureWithView {
|
impl TextureWithView {
|
||||||
fn new(texture: wgpu::Texture) -> Self {
|
fn new(texture: wgpu::Texture, format: wgpu::TextureFormat, extent: wgpu::Extent3d) -> Self {
|
||||||
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
Self { texture, view }
|
Self { texture, view, format, extent }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,15 +42,8 @@ pub(crate) fn create_static_texture_2d(
|
||||||
label: &str,
|
label: &str,
|
||||||
) -> TextureRef {
|
) -> TextureRef {
|
||||||
let gpu = &get_app().gpu;
|
let gpu = &get_app().gpu;
|
||||||
let texture = gpu.device.create_texture_with_data(
|
let extent = wgpu::Extent3d { width, height, depth_or_array_layers: 1 };
|
||||||
&gpu.queue,
|
let wgpu_format = match format {
|
||||||
&wgpu::TextureDescriptor {
|
|
||||||
label: Some(label),
|
|
||||||
size: wgpu::Extent3d { width, height, depth_or_array_layers: 1 },
|
|
||||||
mip_level_count: mips,
|
|
||||||
sample_count: 1,
|
|
||||||
dimension: wgpu::TextureDimension::D2,
|
|
||||||
format: match format {
|
|
||||||
TextureFormat::RGBA8 => wgpu::TextureFormat::Rgba8Unorm,
|
TextureFormat::RGBA8 => wgpu::TextureFormat::Rgba8Unorm,
|
||||||
TextureFormat::R8 => wgpu::TextureFormat::R8Unorm,
|
TextureFormat::R8 => wgpu::TextureFormat::R8Unorm,
|
||||||
TextureFormat::R32Float => wgpu::TextureFormat::R32Float,
|
TextureFormat::R32Float => wgpu::TextureFormat::R32Float,
|
||||||
|
@ -54,7 +52,16 @@ pub(crate) fn create_static_texture_2d(
|
||||||
TextureFormat::DXT5 => wgpu::TextureFormat::Bc5RgUnorm,
|
TextureFormat::DXT5 => wgpu::TextureFormat::Bc5RgUnorm,
|
||||||
TextureFormat::BPTC => wgpu::TextureFormat::Bc7RgbaUnorm,
|
TextureFormat::BPTC => wgpu::TextureFormat::Bc7RgbaUnorm,
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
},
|
};
|
||||||
|
let texture = gpu.device.create_texture_with_data(
|
||||||
|
&gpu.queue,
|
||||||
|
&wgpu::TextureDescriptor {
|
||||||
|
label: Some(label),
|
||||||
|
size: extent,
|
||||||
|
mip_level_count: mips,
|
||||||
|
sample_count: 1,
|
||||||
|
dimension: wgpu::TextureDimension::D2,
|
||||||
|
format: wgpu_format,
|
||||||
usage: wgpu::TextureUsages::TEXTURE_BINDING,
|
usage: wgpu::TextureUsages::TEXTURE_BINDING,
|
||||||
},
|
},
|
||||||
data,
|
data,
|
||||||
|
@ -71,7 +78,60 @@ pub(crate) fn create_static_texture_2d(
|
||||||
|
|
||||||
// Store texture and return reference
|
// Store texture and return reference
|
||||||
let state = unsafe { STATE.as_mut().unwrap_unchecked() };
|
let state = unsafe { STATE.as_mut().unwrap_unchecked() };
|
||||||
state.textures.insert(id, TextureWithView::new(texture));
|
match state.textures.entry(id) {
|
||||||
|
Occupied(entry) => panic!("Hash collision ({:x}) on texture creation: {}", id, label),
|
||||||
|
Vacant(entry) => {
|
||||||
|
state.textures.insert(id, TextureWithView::new(texture, wgpu_format, extent));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TextureRef { id, render: false }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn create_dynamic_texture_2d(
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
mips: u32,
|
||||||
|
format: TextureFormat,
|
||||||
|
label: &str,
|
||||||
|
) -> TextureRef {
|
||||||
|
let gpu = &get_app().gpu;
|
||||||
|
let extent = wgpu::Extent3d { width, height, depth_or_array_layers: 1 };
|
||||||
|
let wgpu_format = match format {
|
||||||
|
TextureFormat::RGBA8 => wgpu::TextureFormat::Rgba8Unorm,
|
||||||
|
TextureFormat::R8 => wgpu::TextureFormat::R8Unorm,
|
||||||
|
TextureFormat::R32Float => wgpu::TextureFormat::R32Float,
|
||||||
|
TextureFormat::DXT1 => wgpu::TextureFormat::Bc1RgbaUnorm,
|
||||||
|
TextureFormat::DXT3 => wgpu::TextureFormat::Bc3RgbaUnorm,
|
||||||
|
TextureFormat::DXT5 => wgpu::TextureFormat::Bc5RgUnorm,
|
||||||
|
TextureFormat::BPTC => wgpu::TextureFormat::Bc7RgbaUnorm,
|
||||||
|
_ => todo!(),
|
||||||
|
};
|
||||||
|
let texture = gpu.device.create_texture(&wgpu::TextureDescriptor {
|
||||||
|
label: Some(label),
|
||||||
|
size: extent,
|
||||||
|
mip_level_count: mips,
|
||||||
|
sample_count: 1,
|
||||||
|
dimension: wgpu::TextureDimension::D2,
|
||||||
|
format: wgpu_format,
|
||||||
|
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Generate texture hash as ID
|
||||||
|
let mut hasher = XxHash32::with_seed(format.into());
|
||||||
|
width.hash(&mut hasher);
|
||||||
|
height.hash(&mut hasher);
|
||||||
|
mips.hash(&mut hasher);
|
||||||
|
label.hash(&mut hasher);
|
||||||
|
let id = hasher.finish() as u32;
|
||||||
|
|
||||||
|
// Store texture and return reference
|
||||||
|
let state = unsafe { STATE.as_mut().unwrap_unchecked() };
|
||||||
|
match state.textures.entry(id) {
|
||||||
|
Occupied(entry) => panic!("Hash collision ({:x}) on texture creation: {}", id, label),
|
||||||
|
Vacant(entry) => {
|
||||||
|
state.textures.insert(id, TextureWithView::new(texture, wgpu_format, extent));
|
||||||
|
}
|
||||||
|
}
|
||||||
TextureRef { id, render: false }
|
TextureRef { id, render: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,28 +145,38 @@ pub(crate) fn create_render_texture(
|
||||||
) -> TextureRef {
|
) -> TextureRef {
|
||||||
let gpu = &get_app().gpu;
|
let gpu = &get_app().gpu;
|
||||||
let color_texture = if color_bind_count > 0 {
|
let color_texture = if color_bind_count > 0 {
|
||||||
Some(TextureWithView::new(gpu.device.create_texture(&wgpu::TextureDescriptor {
|
let extent = wgpu::Extent3d { width, height, depth_or_array_layers: color_bind_count };
|
||||||
|
Some(TextureWithView::new(
|
||||||
|
gpu.device.create_texture(&wgpu::TextureDescriptor {
|
||||||
label: Some(format!("{} Color", label).as_str()),
|
label: Some(format!("{} Color", label).as_str()),
|
||||||
size: wgpu::Extent3d { width, height, depth_or_array_layers: color_bind_count },
|
size: extent,
|
||||||
mip_level_count: 1,
|
mip_level_count: 1,
|
||||||
sample_count: 1,
|
sample_count: 1,
|
||||||
dimension: wgpu::TextureDimension::D2,
|
dimension: wgpu::TextureDimension::D2,
|
||||||
format: gpu.config.color_format,
|
format: gpu.config.color_format,
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
})))
|
}),
|
||||||
|
gpu.config.color_format,
|
||||||
|
extent,
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let depth_texture = if depth_bind_count > 0 {
|
let depth_texture = if depth_bind_count > 0 {
|
||||||
Some(TextureWithView::new(gpu.device.create_texture(&wgpu::TextureDescriptor {
|
let extent = wgpu::Extent3d { width, height, depth_or_array_layers: depth_bind_count };
|
||||||
|
Some(TextureWithView::new(
|
||||||
|
gpu.device.create_texture(&wgpu::TextureDescriptor {
|
||||||
label: Some(format!("{} Depth", label).as_str()),
|
label: Some(format!("{} Depth", label).as_str()),
|
||||||
size: wgpu::Extent3d { width, height, depth_or_array_layers: depth_bind_count },
|
size: extent,
|
||||||
mip_level_count: 1,
|
mip_level_count: 1,
|
||||||
sample_count: 1,
|
sample_count: 1,
|
||||||
dimension: wgpu::TextureDimension::D2,
|
dimension: wgpu::TextureDimension::D2,
|
||||||
format: gpu.config.depth_format,
|
format: gpu.config.depth_format,
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
})))
|
}),
|
||||||
|
gpu.config.depth_format,
|
||||||
|
extent,
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -146,10 +216,46 @@ pub(crate) fn create_render_texture(
|
||||||
|
|
||||||
// Store texture and return reference
|
// Store texture and return reference
|
||||||
let state = unsafe { STATE.as_mut().unwrap_unchecked() };
|
let state = unsafe { STATE.as_mut().unwrap_unchecked() };
|
||||||
|
match state.textures.entry(id) {
|
||||||
|
Occupied(entry) => panic!("Hash collision ({:x}) on texture creation: {}", id, label),
|
||||||
|
Vacant(entry) => {
|
||||||
state.render_textures.insert(id, RenderTexture { color_texture, depth_texture });
|
state.render_textures.insert(id, RenderTexture { color_texture, depth_texture });
|
||||||
|
}
|
||||||
|
}
|
||||||
TextureRef { id, render: true }
|
TextureRef { id, render: true }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn write_texture(handle: TextureRef, data: &[u8]) {
|
||||||
|
if handle.render {
|
||||||
|
panic!("Can't write to render texture");
|
||||||
|
}
|
||||||
|
|
||||||
|
let state = unsafe { STATE.as_mut().unwrap_unchecked() };
|
||||||
|
if let Some(TextureWithView { texture, format, extent, .. }) = state.textures.get(&handle.id) {
|
||||||
|
state.queue.write_texture(
|
||||||
|
texture.as_image_copy(),
|
||||||
|
data,
|
||||||
|
ImageDataLayout {
|
||||||
|
offset: 0,
|
||||||
|
bytes_per_row: match format {
|
||||||
|
wgpu::TextureFormat::Rgba8Unorm | wgpu::TextureFormat::R32Float => {
|
||||||
|
NonZeroU32::new(extent.width * 4)
|
||||||
|
}
|
||||||
|
wgpu::TextureFormat::R8Unorm => NonZeroU32::new(extent.width),
|
||||||
|
_ => todo!("Unimplemented format for write_texture: {:?}", format),
|
||||||
|
},
|
||||||
|
rows_per_image: match extent.depth_or_array_layers {
|
||||||
|
1 => None,
|
||||||
|
_ => todo!("Unimplemented write_texture for 3D/2DArray textures"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
*extent,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
panic!("Failed to find texture {}", handle.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn drop_texture(handle: TextureRef) {
|
pub(crate) fn drop_texture(handle: TextureRef) {
|
||||||
let state = unsafe { STATE.as_mut().unwrap_unchecked() };
|
let state = unsafe { STATE.as_mut().unwrap_unchecked() };
|
||||||
if handle.render {
|
if handle.render {
|
||||||
|
|
|
@ -47,6 +47,13 @@ inline std::shared_ptr<TextureHandle> new_static_texture_2d(uint32_t width, uint
|
||||||
auto ref = aurora::shaders::create_static_texture_2d(width, height, mips, format, data, rlabel);
|
auto ref = aurora::shaders::create_static_texture_2d(width, height, mips, format, data, rlabel);
|
||||||
return std::make_shared<TextureHandle>(ref);
|
return std::make_shared<TextureHandle>(ref);
|
||||||
}
|
}
|
||||||
|
inline std::shared_ptr<TextureHandle> new_dynamic_texture_2d(uint32_t width, uint32_t height, uint32_t mips,
|
||||||
|
aurora::shaders::TextureFormat format,
|
||||||
|
std::string_view label) {
|
||||||
|
rust::Str rlabel{label.data(), label.size()};
|
||||||
|
auto ref = aurora::shaders::create_dynamic_texture_2d(width, height, mips, format, rlabel);
|
||||||
|
return std::make_shared<TextureHandle>(ref);
|
||||||
|
}
|
||||||
inline std::shared_ptr<TextureHandle> new_render_texture(uint32_t width, uint32_t height,
|
inline std::shared_ptr<TextureHandle> new_render_texture(uint32_t width, uint32_t height,
|
||||||
uint32_t color_bind_count, uint32_t depth_bind_count,
|
uint32_t color_bind_count, uint32_t depth_bind_count,
|
||||||
std::string_view label) {
|
std::string_view label) {
|
||||||
|
|
|
@ -5,13 +5,10 @@
|
||||||
#include "Runtime/Graphics/CGraphics.hpp"
|
#include "Runtime/Graphics/CGraphics.hpp"
|
||||||
|
|
||||||
#include <amuse/DSPCodec.hpp>
|
#include <amuse/DSPCodec.hpp>
|
||||||
//#include <hecl/Pipeline.hpp>
|
|
||||||
#include <turbojpeg.h>
|
#include <turbojpeg.h>
|
||||||
|
|
||||||
namespace metaforce {
|
namespace metaforce {
|
||||||
|
|
||||||
zeus::CMatrix4f g_PlatformMatrix;
|
|
||||||
|
|
||||||
/* used in the original to look up fixed-point dividends on a
|
/* used in the original to look up fixed-point dividends on a
|
||||||
* MIDI-style volume scale (0-127) -> (n/0x8000) */
|
* MIDI-style volume scale (0-127) -> (n/0x8000) */
|
||||||
static const std::array<u16, 128> StaticVolumeLookup = {
|
static const std::array<u16, 128> StaticVolumeLookup = {
|
||||||
|
@ -26,8 +23,7 @@ static const std::array<u16, 128> StaticVolumeLookup = {
|
||||||
0x55D6, 0x577E, 0x592B, 0x5ADC, 0x5C90, 0x5E49, 0x6006, 0x61C7, 0x638C, 0x6555, 0x6722, 0x68F4, 0x6AC9,
|
0x55D6, 0x577E, 0x592B, 0x5ADC, 0x5C90, 0x5E49, 0x6006, 0x61C7, 0x638C, 0x6555, 0x6722, 0x68F4, 0x6AC9,
|
||||||
0x6CA2, 0x6E80, 0x7061, 0x7247, 0x7430, 0x761E, 0x7810, 0x7A06, 0x7C00, 0x7DFE, 0x8000};
|
0x6CA2, 0x6E80, 0x7061, 0x7247, 0x7430, 0x761E, 0x7810, 0x7A06, 0x7C00, 0x7DFE, 0x8000};
|
||||||
|
|
||||||
/* shared boo resources */
|
/* shared resources */
|
||||||
//static boo::ObjToken<boo::IShaderPipeline> YUVShaderPipeline;
|
|
||||||
static tjhandle TjHandle = nullptr;
|
static tjhandle TjHandle = nullptr;
|
||||||
|
|
||||||
/* RSF audio state */
|
/* RSF audio state */
|
||||||
|
@ -43,25 +39,9 @@ static g72x_state StaticStateRight = {};
|
||||||
/* THP SFX audio */
|
/* THP SFX audio */
|
||||||
static float SfxVolume = 1.f;
|
static float SfxVolume = 1.f;
|
||||||
|
|
||||||
static const char* BlockNames[] = {"SpecterViewBlock"};
|
void CMoviePlayer::Initialize() { TjHandle = tjInitDecompress(); }
|
||||||
static const char* TexNames[] = {"texY", "texU", "texV"};
|
|
||||||
|
|
||||||
void CMoviePlayer::Initialize() {
|
void CMoviePlayer::Shutdown() { tjDestroy(TjHandle); }
|
||||||
// switch (factory->platform()) {
|
|
||||||
// case boo::IGraphicsDataFactory::Platform::Vulkan:
|
|
||||||
// g_PlatformMatrix.m[1][1] = -1.f;
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// YUVShaderPipeline = hecl::conv->convert(Shader_CMoviePlayerShader{});
|
|
||||||
TjHandle = tjInitDecompress();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CMoviePlayer::Shutdown() {
|
|
||||||
// YUVShaderPipeline.reset();
|
|
||||||
tjDestroy(TjHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CMoviePlayer::THPHeader::swapBig() {
|
void CMoviePlayer::THPHeader::swapBig() {
|
||||||
magic = hecl::SBig(magic);
|
magic = hecl::SBig(magic);
|
||||||
|
@ -201,51 +181,39 @@ CMoviePlayer::CMoviePlayer(const char* path, float preLoadSeconds, bool loop, bo
|
||||||
if (xf0_preLoadFrames > 0)
|
if (xf0_preLoadFrames > 0)
|
||||||
xa0_bufferQueue.reserve(xf0_preLoadFrames);
|
xa0_bufferQueue.reserve(xf0_preLoadFrames);
|
||||||
|
|
||||||
/* All set for GPU resources */
|
/* Allocate textures here (rather than at decode time) */
|
||||||
// CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) {
|
x80_textures.reserve(3);
|
||||||
// m_blockBuf = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(m_viewVertBlock), 1);
|
for (int i = 0; i < 3; ++i) {
|
||||||
// m_vertBuf = ctx.newDynamicBuffer(boo::BufferUse::Vertex, sizeof(TexShaderVert), 4);
|
CTHPTextureSet& set = x80_textures.emplace_back();
|
||||||
//
|
if (deinterlace) {
|
||||||
// /* Allocate textures here (rather than at decode time) */
|
/* metaforce addition: this way interlaced THPs don't look horrible */
|
||||||
// x80_textures.reserve(3);
|
set.Y[0] = aurora::new_dynamic_texture_2d(x6c_videoInfo.width, x6c_videoInfo.height / 2, 1,
|
||||||
// for (int i = 0; i < 3; ++i) {
|
aurora::shaders::TextureFormat::R8,
|
||||||
// CTHPTextureSet& set = x80_textures.emplace_back();
|
fmt::format(FMT_STRING("Movie {} Texture Set {} Y[0]"), path, i));
|
||||||
// if (deinterlace) {
|
set.Y[1] = aurora::new_dynamic_texture_2d(x6c_videoInfo.width, x6c_videoInfo.height / 2, 1,
|
||||||
// /* metaforce addition: this way interlaced THPs don't look horrible */
|
aurora::shaders::TextureFormat::R8,
|
||||||
// set.Y[0] = ctx.newDynamicTexture(x6c_videoInfo.width, x6c_videoInfo.height / 2, boo::TextureFormat::I8,
|
fmt::format(FMT_STRING("Movie {} Texture Set {} Y[1]"), path, i));
|
||||||
// boo::TextureClampMode::Repeat);
|
set.U = aurora::new_dynamic_texture_2d(x6c_videoInfo.width / 2, x6c_videoInfo.height / 2, 1,
|
||||||
// set.Y[1] = ctx.newDynamicTexture(x6c_videoInfo.width, x6c_videoInfo.height / 2, boo::TextureFormat::I8,
|
aurora::shaders::TextureFormat::R8,
|
||||||
// boo::TextureClampMode::Repeat);
|
fmt::format(FMT_STRING("Movie {} Texture Set {} U"), path, i));
|
||||||
// set.U = ctx.newDynamicTexture(x6c_videoInfo.width / 2, x6c_videoInfo.height / 2, boo::TextureFormat::I8,
|
set.V = aurora::new_dynamic_texture_2d(x6c_videoInfo.width / 2, x6c_videoInfo.height / 2, 1,
|
||||||
// boo::TextureClampMode::Repeat);
|
aurora::shaders::TextureFormat::R8,
|
||||||
// set.V = ctx.newDynamicTexture(x6c_videoInfo.width / 2, x6c_videoInfo.height / 2, boo::TextureFormat::I8,
|
fmt::format(FMT_STRING("Movie {} Texture Set {} V"), path, i));
|
||||||
// boo::TextureClampMode::Repeat);
|
} else {
|
||||||
//
|
/* normal progressive presentation */
|
||||||
// boo::ObjToken<boo::IGraphicsBuffer> bufs[] = {m_blockBuf.get()};
|
set.Y[0] = aurora::new_dynamic_texture_2d(x6c_videoInfo.width, x6c_videoInfo.height, 1,
|
||||||
// for (int j = 0; j < 2; ++j) {
|
aurora::shaders::TextureFormat::R8,
|
||||||
// boo::ObjToken<boo::ITexture> texs[] = {set.Y[j].get(), set.U.get(), set.V.get()};
|
fmt::format(FMT_STRING("Movie {} Texture Set {} Y"), path, i));
|
||||||
// set.binding[j] = ctx.newShaderDataBinding(YUVShaderPipeline, m_vertBuf.get(), nullptr, nullptr, 1, bufs,
|
set.U = aurora::new_dynamic_texture_2d(x6c_videoInfo.width / 2, x6c_videoInfo.height / 2, 1,
|
||||||
// nullptr, 3, texs, nullptr, nullptr);
|
aurora::shaders::TextureFormat::R8,
|
||||||
// }
|
fmt::format(FMT_STRING("Movie {} Texture Set {} U"), path, i));
|
||||||
// } else {
|
set.V = aurora::new_dynamic_texture_2d(x6c_videoInfo.width / 2, x6c_videoInfo.height / 2, 1,
|
||||||
// /* normal progressive presentation */
|
aurora::shaders::TextureFormat::R8,
|
||||||
// set.Y[0] = ctx.newDynamicTexture(x6c_videoInfo.width, x6c_videoInfo.height, boo::TextureFormat::I8,
|
fmt::format(FMT_STRING("Movie {} Texture Set {} V"), path, i));
|
||||||
// boo::TextureClampMode::Repeat);
|
}
|
||||||
// set.U = ctx.newDynamicTexture(x6c_videoInfo.width / 2, x6c_videoInfo.height / 2, boo::TextureFormat::I8,
|
if (xf4_25_hasAudio)
|
||||||
// boo::TextureClampMode::Repeat);
|
set.audioBuf.reset(new s16[x28_thpHead.maxAudioSamples * 2]);
|
||||||
// set.V = ctx.newDynamicTexture(x6c_videoInfo.width / 2, x6c_videoInfo.height / 2, boo::TextureFormat::I8,
|
}
|
||||||
// boo::TextureClampMode::Repeat);
|
|
||||||
//
|
|
||||||
// boo::ObjToken<boo::IGraphicsBuffer> bufs[] = {m_blockBuf.get()};
|
|
||||||
// boo::ObjToken<boo::ITexture> texs[] = {set.Y[0].get(), set.U.get(), set.V.get()};
|
|
||||||
// set.binding[0] = ctx.newShaderDataBinding(YUVShaderPipeline, m_vertBuf.get(), nullptr, nullptr, 1, bufs,
|
|
||||||
// nullptr, 3, texs, nullptr, nullptr);
|
|
||||||
// }
|
|
||||||
// if (xf4_25_hasAudio)
|
|
||||||
// set.audioBuf.reset(new s16[x28_thpHead.maxAudioSamples * 2]);
|
|
||||||
// }
|
|
||||||
// return true;
|
|
||||||
// } BooTrace);
|
|
||||||
|
|
||||||
/* Temporary planar YUV decode buffer, resulting planes copied to Boo */
|
/* Temporary planar YUV decode buffer, resulting planes copied to Boo */
|
||||||
m_yuvBuf.reset(new uint8_t[tjBufSizeYUV(x6c_videoInfo.width, x6c_videoInfo.height, TJ_420)]);
|
m_yuvBuf.reset(new uint8_t[tjBufSizeYUV(x6c_videoInfo.width, x6c_videoInfo.height, TJ_420)]);
|
||||||
|
@ -253,14 +221,8 @@ CMoviePlayer::CMoviePlayer(const char* path, float preLoadSeconds, bool loop, bo
|
||||||
/* Schedule initial read */
|
/* Schedule initial read */
|
||||||
PostDVDReadRequestIfNeeded();
|
PostDVDReadRequestIfNeeded();
|
||||||
|
|
||||||
m_frame[0].m_uv = {0.f, 0.f};
|
m_hpad = 0.5f;
|
||||||
m_frame[1].m_uv = {0.f, 1.f};
|
m_vpad = 0.5f;
|
||||||
m_frame[2].m_uv = {1.f, 0.f};
|
|
||||||
m_frame[3].m_uv = {1.f, 1.f};
|
|
||||||
SetFrame({-0.5f, 0.5f, 0.f}, {-0.5f, -0.5f, 0.f}, {0.5f, -0.5f, 0.f}, {0.5f, 0.5f, 0.f});
|
|
||||||
|
|
||||||
m_viewVertBlock.finalAssign(m_viewVertBlock);
|
|
||||||
// m_blockBuf->load(&m_viewVertBlock, sizeof(m_viewVertBlock));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMoviePlayer::SetStaticAudioVolume(int vol) {
|
void CMoviePlayer::SetStaticAudioVolume(int vol) {
|
||||||
|
@ -399,13 +361,9 @@ void CMoviePlayer::Rewind() {
|
||||||
xe8_curSeconds = 0.f;
|
xe8_curSeconds = 0.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMoviePlayer::SetFrame(const zeus::CVector3f& a, const zeus::CVector3f& b, const zeus::CVector3f& c,
|
void CMoviePlayer::SetFrame(float hpad, float vpad) {
|
||||||
const zeus::CVector3f& d) {
|
m_hpad = hpad;
|
||||||
m_frame[0].m_pos = a;
|
m_vpad = vpad;
|
||||||
m_frame[1].m_pos = b;
|
|
||||||
m_frame[2].m_pos = d;
|
|
||||||
m_frame[3].m_pos = c;
|
|
||||||
// m_vertBuf->load(m_frame, sizeof(m_frame));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMoviePlayer::DrawFrame() {
|
void CMoviePlayer::DrawFrame() {
|
||||||
|
@ -415,8 +373,8 @@ void CMoviePlayer::DrawFrame() {
|
||||||
|
|
||||||
/* draw appropriate field */
|
/* draw appropriate field */
|
||||||
CTHPTextureSet& tex = x80_textures[xd0_drawTexSlot];
|
CTHPTextureSet& tex = x80_textures[xd0_drawTexSlot];
|
||||||
// CGraphics::SetShaderDataBinding(tex.binding[m_deinterlace ? (xfc_fieldIndex != 0) : 0]);
|
aurora::shaders::queue_movie_player(tex.Y[m_deinterlace ? (xfc_fieldIndex != 0) : 0]->ref, tex.U->ref, tex.V->ref,
|
||||||
// CGraphics::DrawArray(0, 4);
|
zeus::skWhite, m_hpad, m_vpad);
|
||||||
|
|
||||||
/* ensure second field is being displayed by VI to signal advance
|
/* ensure second field is being displayed by VI to signal advance
|
||||||
* (faked in metaforce with continuous xor) */
|
* (faked in metaforce with continuous xor) */
|
||||||
|
@ -532,28 +490,23 @@ void CMoviePlayer::DecodeFromRead(const void* data) {
|
||||||
|
|
||||||
if (m_deinterlace) {
|
if (m_deinterlace) {
|
||||||
/* Deinterlace into 2 discrete 60-fps half-res textures */
|
/* Deinterlace into 2 discrete 60-fps half-res textures */
|
||||||
// u8* mappedData = (u8*)tex.Y[0]->map(planeSizeHalf);
|
auto buffer = std::make_unique<u8[]>(planeSizeHalf);
|
||||||
// for (unsigned y = 0; y < x6c_videoInfo.height / 2; ++y) {
|
for (unsigned y = 0; y < x6c_videoInfo.height / 2; ++y) {
|
||||||
// memmove(mappedData + x6c_videoInfo.width * y, m_yuvBuf.get() + x6c_videoInfo.width * (y * 2),
|
memcpy(buffer.get() + x6c_videoInfo.width * y, m_yuvBuf.get() + x6c_videoInfo.width * (y * 2),
|
||||||
// x6c_videoInfo.width);
|
x6c_videoInfo.width);
|
||||||
// }
|
}
|
||||||
// tex.Y[0]->unmap();
|
aurora::shaders::write_texture(tex.Y[0]->ref, {buffer.get(), planeSizeHalf});
|
||||||
//
|
for (unsigned y = 0; y < x6c_videoInfo.height / 2; ++y) {
|
||||||
// mappedData = (u8*)tex.Y[1]->map(planeSizeHalf);
|
memmove(buffer.get() + x6c_videoInfo.width * y, m_yuvBuf.get() + x6c_videoInfo.width * (y * 2 + 1),
|
||||||
// for (unsigned y = 0; y < x6c_videoInfo.height / 2; ++y) {
|
x6c_videoInfo.width);
|
||||||
// memmove(mappedData + x6c_videoInfo.width * y, m_yuvBuf.get() + x6c_videoInfo.width * (y * 2 + 1),
|
}
|
||||||
// x6c_videoInfo.width);
|
aurora::shaders::write_texture(tex.Y[1]->ref, {buffer.get(), planeSizeHalf});
|
||||||
// }
|
|
||||||
// tex.Y[1]->unmap();
|
|
||||||
//
|
|
||||||
// tex.U->load(m_yuvBuf.get() + planeSize, planeSizeQuarter);
|
|
||||||
// tex.V->load(m_yuvBuf.get() + planeSize + planeSizeQuarter, planeSizeQuarter);
|
|
||||||
} else {
|
} else {
|
||||||
/* Direct planar load */
|
/* Direct planar load */
|
||||||
// tex.Y[0]->load(m_yuvBuf.get(), planeSize);
|
aurora::shaders::write_texture(tex.Y[0]->ref, {m_yuvBuf.get(), planeSize});
|
||||||
// tex.U->load(m_yuvBuf.get() + planeSize, planeSizeQuarter);
|
|
||||||
// tex.V->load(m_yuvBuf.get() + planeSize + planeSizeQuarter, planeSizeQuarter);
|
|
||||||
}
|
}
|
||||||
|
aurora::shaders::write_texture(tex.U->ref, {m_yuvBuf.get() + planeSize, planeSizeQuarter});
|
||||||
|
aurora::shaders::write_texture(tex.V->ref, {m_yuvBuf.get() + planeSize + planeSizeQuarter, planeSizeQuarter});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
|
|
||||||
namespace metaforce {
|
namespace metaforce {
|
||||||
|
|
||||||
extern zeus::CMatrix4f g_PlatformMatrix;
|
|
||||||
|
|
||||||
class CMoviePlayer : public CDvdFile {
|
class CMoviePlayer : public CDvdFile {
|
||||||
public:
|
public:
|
||||||
enum class EPlayMode { Stopped, Playing };
|
enum class EPlayMode { Stopped, Playing };
|
||||||
|
@ -77,7 +75,6 @@ private:
|
||||||
u32 playedSamples = 0;
|
u32 playedSamples = 0;
|
||||||
u32 audioSamples = 0;
|
u32 audioSamples = 0;
|
||||||
std::unique_ptr<s16[]> audioBuf;
|
std::unique_ptr<s16[]> audioBuf;
|
||||||
// boo::ObjToken<boo::IShaderDataBinding> binding[2];
|
|
||||||
};
|
};
|
||||||
std::vector<CTHPTextureSet> x80_textures;
|
std::vector<CTHPTextureSet> x80_textures;
|
||||||
std::unique_ptr<uint8_t[]> x90_requestBuf;
|
std::unique_ptr<uint8_t[]> x90_requestBuf;
|
||||||
|
@ -109,31 +106,8 @@ private:
|
||||||
u32 xfc_fieldIndex = 0;
|
u32 xfc_fieldIndex = 0;
|
||||||
|
|
||||||
std::unique_ptr<uint8_t[]> m_yuvBuf;
|
std::unique_ptr<uint8_t[]> m_yuvBuf;
|
||||||
|
float m_hpad;
|
||||||
struct TexShaderVert {
|
float m_vpad;
|
||||||
zeus::CVector3f m_pos;
|
|
||||||
zeus::CVector2f m_uv;
|
|
||||||
};
|
|
||||||
struct ViewBlock {
|
|
||||||
zeus::CMatrix4f m_mv;
|
|
||||||
zeus::CColor m_color = zeus::skWhite;
|
|
||||||
void setViewRect(const aurora::shaders::ClipRect& root, const aurora::shaders::ClipRect& sub) {
|
|
||||||
m_mv[0][0] = 2.0f / root.width;
|
|
||||||
m_mv[1][1] = 2.0f / root.height;
|
|
||||||
m_mv[3][0] = sub.x * m_mv[0][0] - 1.0f;
|
|
||||||
m_mv[3][1] = sub.y * m_mv[1][1] - 1.0f;
|
|
||||||
}
|
|
||||||
void finalAssign(const ViewBlock& other) {
|
|
||||||
m_mv = g_PlatformMatrix * other.m_mv;
|
|
||||||
m_color = other.m_color;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ViewBlock m_viewVertBlock;
|
|
||||||
// boo::ObjToken<boo::IGraphicsBufferD> m_blockBuf;
|
|
||||||
// boo::ObjToken<boo::IGraphicsBufferD> m_vertBuf;
|
|
||||||
|
|
||||||
TexShaderVert m_frame[4];
|
|
||||||
|
|
||||||
static u32 THPAudioDecode(s16* buffer, const u8* audioFrame, bool stereo);
|
static u32 THPAudioDecode(s16* buffer, const u8* audioFrame, bool stereo);
|
||||||
void DecodeFromRead(const void* data);
|
void DecodeFromRead(const void* data);
|
||||||
|
@ -161,7 +135,7 @@ public:
|
||||||
float GetPlayedSeconds() const { return xdc_frameRem + xe8_curSeconds; }
|
float GetPlayedSeconds() const { return xdc_frameRem + xe8_curSeconds; }
|
||||||
float GetTotalSeconds() const { return xe4_totalSeconds; }
|
float GetTotalSeconds() const { return xe4_totalSeconds; }
|
||||||
void SetPlayMode(EPlayMode mode) { xe0_playMode = mode; }
|
void SetPlayMode(EPlayMode mode) { xe0_playMode = mode; }
|
||||||
void SetFrame(const zeus::CVector3f& a, const zeus::CVector3f& b, const zeus::CVector3f& c, const zeus::CVector3f& d);
|
void SetFrame(float hpad, float vpad);
|
||||||
void DrawFrame();
|
void DrawFrame();
|
||||||
void Update(float dt);
|
void Update(float dt);
|
||||||
std::pair<u32, u32> GetVideoDimensions() const { return {x6c_videoInfo.width, x6c_videoInfo.height}; }
|
std::pair<u32, u32> GetVideoDimensions() const { return {x6c_videoInfo.width, x6c_videoInfo.height}; }
|
||||||
|
|
|
@ -212,7 +212,7 @@ void CCredits::DrawVideo() {
|
||||||
|
|
||||||
if (x28_ && x28_->GetIsFullyCached()) {
|
if (x28_ && x28_->GetIsFullyCached()) {
|
||||||
/* Render movie */
|
/* Render movie */
|
||||||
x28_->SetFrame({-hPad, vPad, 0.f}, {-hPad, -vPad, 0.f}, {hPad, -vPad, 0.f}, {hPad, vPad, 0.f});
|
x28_->SetFrame(hPad, vPad);
|
||||||
x28_->DrawFrame();
|
x28_->DrawFrame();
|
||||||
if (x5c_27_ || x5c_28_) {
|
if (x5c_27_ || x5c_28_) {
|
||||||
float alpha = x58_ / g_tweakGui->x310_;
|
float alpha = x58_ / g_tweakGui->x310_;
|
||||||
|
|
|
@ -56,7 +56,7 @@ struct FEMovie {
|
||||||
bool loop;
|
bool loop;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr std::array<FEMovie, 9> FEMovies{{
|
constexpr std::array<FEMovie, 8> FEMovies{{
|
||||||
{"Video/00_first_start.thp", false},
|
{"Video/00_first_start.thp", false},
|
||||||
{"Video/01_startloop.thp", true},
|
{"Video/01_startloop.thp", true},
|
||||||
{"Video/02_start_fileselect_A.thp", false},
|
{"Video/02_start_fileselect_A.thp", false},
|
||||||
|
@ -65,7 +65,6 @@ constexpr std::array<FEMovie, 9> FEMovies{{
|
||||||
{"Video/06_fileselect_GBA.thp", false},
|
{"Video/06_fileselect_GBA.thp", false},
|
||||||
{"Video/07_GBAloop.thp", true},
|
{"Video/07_GBAloop.thp", true},
|
||||||
{"Video/08_GBA_fileselect.thp", false},
|
{"Video/08_GBA_fileselect.thp", false},
|
||||||
{"Video/08_GBA_fileselect.thp", false},
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
constexpr SObjectTag g_DefaultWorldTag = {FOURCC('MLVL'), 0x158efe17};
|
constexpr SObjectTag g_DefaultWorldTag = {FOURCC('MLVL'), 0x158efe17};
|
||||||
|
@ -2021,7 +2020,7 @@ void CFrontEndUI::Draw() {
|
||||||
|
|
||||||
if (xcc_curMoviePtr && xcc_curMoviePtr->GetIsFullyCached()) {
|
if (xcc_curMoviePtr && xcc_curMoviePtr->GetIsFullyCached()) {
|
||||||
/* Render movie */
|
/* Render movie */
|
||||||
xcc_curMoviePtr->SetFrame({-hPad, vPad, 0.f}, {-hPad, -vPad, 0.f}, {hPad, -vPad, 0.f}, {hPad, vPad, 0.f});
|
xcc_curMoviePtr->SetFrame(hPad, vPad);
|
||||||
xcc_curMoviePtr->DrawFrame();
|
xcc_curMoviePtr->DrawFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2038,7 +2037,7 @@ void CFrontEndUI::Draw() {
|
||||||
xe4_fusionBonusFrme->Draw();
|
xe4_fusionBonusFrme->Draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x64_pressStartAlpha > 0.f && x38_pressStart.IsLoaded() && m_pressStartQuad) {
|
if (x64_pressStartAlpha > 0.f && x38_pressStart.IsLoaded()) {
|
||||||
/* Render "Press Start" */
|
/* Render "Press Start" */
|
||||||
const zeus::CRectangle rect(0.5f - x38_pressStart->GetWidth() / 2.f / 640.f * hPad,
|
const zeus::CRectangle rect(0.5f - x38_pressStart->GetWidth() / 2.f / 640.f * hPad,
|
||||||
0.5f + (x38_pressStart->GetHeight() / 2.f - 240.f + 72.f) / 480.f * vPad,
|
0.5f + (x38_pressStart->GetHeight() / 2.f - 240.f + 72.f) / 480.f * vPad,
|
||||||
|
@ -2047,7 +2046,7 @@ void CFrontEndUI::Draw() {
|
||||||
zeus::CColor color = zeus::skWhite;
|
zeus::CColor color = zeus::skWhite;
|
||||||
color.a() = x64_pressStartAlpha;
|
color.a() = x64_pressStartAlpha;
|
||||||
aurora::shaders::queue_textured_quad(
|
aurora::shaders::queue_textured_quad(
|
||||||
aurora::shaders::CameraFilterType::Blend,
|
aurora::shaders::CameraFilterType::Add,
|
||||||
x38_pressStart->GetTexture()->ref,
|
x38_pressStart->GetTexture()->ref,
|
||||||
aurora::shaders::ZTest::None,
|
aurora::shaders::ZTest::None,
|
||||||
color,
|
color,
|
||||||
|
@ -2130,9 +2129,6 @@ bool CFrontEndUI::PumpLoad() {
|
||||||
if (!x44_frontendAudioGrp.IsLoaded())
|
if (!x44_frontendAudioGrp.IsLoaded())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Ready to construct texture quads */
|
|
||||||
m_pressStartQuad.emplace(EFilterType::Add, x38_pressStart);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -330,7 +330,7 @@ private:
|
||||||
float x64_pressStartAlpha = 0.f;
|
float x64_pressStartAlpha = 0.f;
|
||||||
float x68_musicVol = 1.f;
|
float x68_musicVol = 1.f;
|
||||||
u32 x6c_;
|
u32 x6c_;
|
||||||
std::array<std::unique_ptr<CMoviePlayer>, 9> x70_menuMovies;
|
std::array<std::unique_ptr<CMoviePlayer>, 8> x70_menuMovies;
|
||||||
EMenuMovie xb8_curMovie = EMenuMovie::Stopped;
|
EMenuMovie xb8_curMovie = EMenuMovie::Stopped;
|
||||||
int xbc_nextAttract = 0;
|
int xbc_nextAttract = 0;
|
||||||
int xc0_attractCount = 0;
|
int xc0_attractCount = 0;
|
||||||
|
@ -350,7 +350,6 @@ private:
|
||||||
CStaticAudioPlayer* xf4_curAudio = nullptr;
|
CStaticAudioPlayer* xf4_curAudio = nullptr;
|
||||||
|
|
||||||
CColoredQuadFilter m_fadeToBlack{EFilterType::Blend};
|
CColoredQuadFilter m_fadeToBlack{EFilterType::Blend};
|
||||||
std::optional<CTexturedQuadFilterAlpha> m_pressStartQuad;
|
|
||||||
|
|
||||||
std::unique_ptr<CFrontEndUITouchBar> m_touchBar;
|
std::unique_ptr<CFrontEndUITouchBar> m_touchBar;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue