Skip to content

Commit

Permalink
tfx: Terrain vertex AO
Browse files Browse the repository at this point in the history
  • Loading branch information
cohaereo committed Nov 28, 2024
1 parent 15d5ce1 commit 70aeb43
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 25 deletions.
32 changes: 29 additions & 3 deletions crates/alkahest-data/src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,10 @@ pub struct SUnk80807152 {
#[tiger_tag(id = 0xffffffff, size = 0x20)]
pub struct SUnk8080714b {
#[tag(offset = 0x10)]
pub unk10: u16,
pub unk12: u16,
pub unk14: ResourceHash,
pub identifier: u64, // used for vertex AO
// pub unk10: u16,
// pub unk12: u16,
// pub unk14: ResourceHash,
pub terrain: TagHash,
pub terrain_bounds: TagHash,
}
Expand Down Expand Up @@ -662,3 +663,28 @@ pub struct SMapAtmosphere {
pub struct SLensFlare {
// TODO(cohae): Placeholder struct
}

#[tiger_tag(id = 0x80806D19)]
pub struct SStaticAmbientOcclusion {
pub file_size: u64,
pub ao0: SAmbientOcclusionBuffer,
pub ao1: SAmbientOcclusionBuffer,
pub ao2: SAmbientOcclusionBuffer,
// pub unk50: Vec<S80806D4F>,
// pub unk60: Vec<u16>,
}

#[tiger_tag]
pub struct SAmbientOcclusionBuffer {
pub buffer: TagHash, // Vertex buffer
_padding: [u8; 4],
pub mappings: Vec<SAmbientOcclusionOffsetMapping>,
}

#[tiger_tag(id = 0x80806D21)]
pub struct SAmbientOcclusionOffsetMapping {
pub identifier: u64,
pub offset: u32,
pub unkc: u32,
pub unk10: [u32; 4],
}
33 changes: 30 additions & 3 deletions crates/alkahest-renderer/src/ecs/map.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
use alkahest_data::map::SMapAtmosphere;
use std::collections::HashMap;

use alkahest_data::map::{SMapAtmosphere, SStaticAmbientOcclusion};
use bevy_ecs::{prelude::Component, system::Resource};
use destiny_pkg::TagHash;
use glam::Vec3;

use crate::{
gpu::{texture::Texture, GpuContext},
handle::Handle,
loaders::texture::load_texture,
loaders::{
texture::load_texture,
vertex_buffer::{load_vertex_buffer, VertexBuffer},
},
tfx::externs::{self, TextureView},
};

// TODO(cohae): This should probably be a resource, since there can only be one per map
#[derive(Resource)]
pub struct MapAtmosphere {
_data: SMapAtmosphere,
Expand Down Expand Up @@ -125,3 +129,26 @@ pub struct NodeMetadata {

pub name: Option<String>,
}

#[derive(Resource)]
pub struct MapStaticAO {
pub ao_buffer: VertexBuffer,
pub offset_map: HashMap<u64, u32>,
}

impl MapStaticAO {
pub fn from_tag(gpu: &GpuContext, tag: &SStaticAmbientOcclusion) -> anyhow::Result<Self> {
let ao_buffer = load_vertex_buffer(gpu, tag.ao0.buffer)?;
let offset_map = tag
.ao0
.mappings
.iter()
.map(|m| (m.identifier, m.offset))
.collect();

Ok(MapStaticAO {
ao_buffer,
offset_map,
})
}
}
6 changes: 2 additions & 4 deletions crates/alkahest-renderer/src/ecs/render/static_geometry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ impl ModelBuffers {
0,
Some(&[
color.srv.clone(),
renderer.gpu.color_ao_fallback.srv.clone(),
// renderer.gpu.color_ao_fallback.srv.clone(),
]),
);
}
Expand Down Expand Up @@ -166,9 +166,7 @@ impl StaticModel {
return;
}

if !renderer.settings.stage_transparent
&& render_stage == TfxRenderStage::Transparents
{
if !renderer.settings.stage_transparent && render_stage == TfxRenderStage::Transparents {
return;
}

Expand Down
69 changes: 65 additions & 4 deletions crates/alkahest-renderer/src/ecs/render/terrain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ use alkahest_data::{
use alkahest_pm::package_manager;
use bevy_ecs::{entity::Entity, prelude::Component};
use destiny_pkg::TagHash;
use glam::{Mat4, Vec4};
use glam::Vec4;
use tiger_parse::PackageManagerExt;
use windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT;

use crate::{
ecs::{
map::MapStaticAO,
visibility::{ViewVisibility, VisibilityHelper},
Scene,
},
Expand All @@ -28,17 +29,34 @@ pub struct TerrainPatches {
pub terrain: STerrain,
techniques: Vec<Handle<Technique>>,
dyemaps: Vec<Handle<Texture>>,
group_cbuffers: Vec<ConstantBuffer<Mat4>>,
group_cbuffers: Vec<ConstantBuffer<TerrainPatchGroupConstants>>,

pub vertex0_buffer: Handle<VertexBuffer>,
pub vertex1_buffer: Handle<VertexBuffer>,
pub index_buffer: Handle<IndexBuffer>,

pub hash: TagHash,
pub identifier: u64,
}

#[repr(C)]
#[derive(Default)]
pub struct TerrainPatchGroupConstants {
offset: Vec4,
texcoord_transform: Vec4,
unk20: f32,
unk24: f32,
unk28: f32,
ao_offset: u32,
unk30: Vec4,
}

impl TerrainPatches {
pub fn load_from_tag(renderer: &Renderer, hash: TagHash) -> anyhow::Result<Self> {
pub fn load_from_tag(
renderer: &Renderer,
hash: TagHash,
identifier: u64,
) -> anyhow::Result<Self> {
let terrain: STerrain = package_manager().read_tag_struct(hash)?;

let mut render_data = renderer.data.lock();
Expand Down Expand Up @@ -69,7 +87,12 @@ impl TerrainPatches {
let texcoord_transform =
Vec4::new(group.unk20.x, group.unk20.y, group.unk20.z, group.unk20.w);

let scope_terrain = Mat4::from_cols(offset, texcoord_transform, Vec4::ZERO, Vec4::ZERO);
// let scope_terrain = Mat4::from_cols(offset, texcoord_transform, Vec4::ZERO, Vec4::ZERO);
let scope_terrain = TerrainPatchGroupConstants {
offset,
texcoord_transform,
..Default::default()
};

let cb = ConstantBuffer::create(renderer.gpu.clone(), Some(&scope_terrain))?;
group_cbuffers.push(cb);
Expand All @@ -90,9 +113,38 @@ impl TerrainPatches {
dyemaps,
group_cbuffers,
hash,
identifier,
})
}

pub fn update_constants(&self, map_ao: &MapStaticAO) {
for (i, group) in self.terrain.mesh_groups.iter().enumerate() {
let offset = Vec4::new(
self.terrain.unk30.x,
self.terrain.unk30.y,
self.terrain.unk30.z,
self.terrain.unk30.w,
);

let texcoord_transform =
Vec4::new(group.unk20.x, group.unk20.y, group.unk20.z, group.unk20.w);

// let scope_terrain = Mat4::from_cols(offset, texcoord_transform, Vec4::ZERO, Vec4::ZERO);
let scope_terrain = TerrainPatchGroupConstants {
offset,
texcoord_transform,
ao_offset: map_ao
.offset_map
.get(&self.identifier)
.copied()
.unwrap_or_default(),
..Default::default()
};

self.group_cbuffers[i].write(&scope_terrain).ok();
}
}

pub fn draw(&self, renderer: &Renderer, render_stage: TfxRenderStage) {
if !matches!(
render_stage,
Expand Down Expand Up @@ -194,6 +246,15 @@ pub fn draw_terrain_patches_system(
return;
}

if let Some(map_ao) = scene.get_resource::<MapStaticAO>() {
unsafe {
renderer
.gpu
.context()
.VSSetShaderResources(1, Some(&[map_ao.ao_buffer.srv.clone()]));
}
}

for (e, terrain, vis) in scene
.query::<(Entity, &TerrainPatches, Option<&ViewVisibility>)>()
.iter(scene)
Expand Down
55 changes: 48 additions & 7 deletions crates/alkahest-renderer/src/loaders/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use alkahest_data::{
map::{
SAudioClipCollection, SBubbleDefinition, SBubbleParent, SCubemapVolume,
SDecalCollectionResource, SLensFlare, SLightCollection, SMapAtmosphere, SMapDataTable,
SShadowingLight, SSlipSurfaceVolume, SUnk808068d4, SUnk80806aa7, SUnk80806ef4,
SUnk8080714b, SUnk80808604, SUnk80808cb7, SUnk80809178, SUnk8080917b,
SShadowingLight, SSlipSurfaceVolume, SStaticAmbientOcclusion, SUnk808068d4, SUnk80806aa7,
SUnk80806ef4, SUnk8080714b, SUnk80808604, SUnk80808cb7, SUnk80809178, SUnk8080917b,
},
occlusion::Aabb,
text::{StringContainer, StringContainerShared},
Expand All @@ -18,7 +18,7 @@ use alkahest_data::{
};
use alkahest_pm::package_manager;
use anyhow::Context;
use bevy_ecs::{bundle::Bundle, entity::Entity};
use bevy_ecs::{bundle::Bundle, entity::Entity, query::With};
use binrw::BinReaderExt;
use destiny_pkg::TagHash;
use ecolor::Color32;
Expand All @@ -33,7 +33,7 @@ use crate::{
audio::AmbientAudio,
common::{Icon, Label, RenderCommonBundle, ResourceOrigin},
hierarchy::{Children, Parent},
map::{CubemapVolume, MapAtmosphere, NodeMetadata},
map::{CubemapVolume, MapAtmosphere, MapStaticAO, NodeMetadata},
render::{
decorators::DecoratorRenderer,
dynamic_geometry::DynamicModelComponent,
Expand Down Expand Up @@ -401,6 +401,21 @@ pub async fn load_map(
scene.entity_mut(entity).insert_one(transform);
}

let mut to_update = vec![];
for entity in scene
.query_filtered::<Entity, With<TerrainPatches>>()
.iter(&scene)
{
to_update.push(entity);
}
// Vertex AO: refresh terrain constants
if let Some(map_ao) = scene.get_resource::<MapStaticAO>() {
for e in to_update {
let patches = scene.entity(e).get::<TerrainPatches>().unwrap();
patches.update_constants(map_ao);
}
}

Ok(scene)
}

Expand Down Expand Up @@ -534,9 +549,12 @@ fn load_datatable_into_scene<R: Read + Seek>(
.unwrap();

let terrain_resource: SUnk8080714b = TigerReadable::read_ds(table_data).unwrap();
let terrain_renderer =
TerrainPatches::load_from_tag(renderer, terrain_resource.terrain)
.context("Failed to load terrain patches")?;
let terrain_renderer = TerrainPatches::load_from_tag(
renderer,
terrain_resource.terrain,
terrain_resource.identifier,
)
.context("Failed to load terrain patches")?;

spawn_data_entity(
scene,
Expand Down Expand Up @@ -743,6 +761,29 @@ fn load_datatable_into_scene<R: Read + Seek>(
);
}
}
0x80806a40 => {
table_data
.seek(SeekFrom::Start(data.data_resource.offset + 16))
.unwrap();
let tag: TagHash = table_data.read_le().unwrap();
if tag.is_none() {
continue;
}

let static_ao =
match package_manager().read_tag_struct::<SStaticAmbientOcclusion>(tag) {
Ok(static_ao) => static_ao,
Err(e) => {
error!(error=?e, tag=%tag, "Failed to load static AO");
continue;
}
};

scene.insert_resource(
MapStaticAO::from_tag(&renderer.gpu, &static_ao)
.context("Failed to load static AO")?,
);
}
0x80806a63 => {
table_data
.seek(SeekFrom::Start(data.data_resource.offset + 16))
Expand Down
12 changes: 8 additions & 4 deletions crates/alkahest-renderer/src/loaders/vertex_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use windows::Win32::Graphics::{
D3D11_BUFFER_SRV_1, D3D11_SHADER_RESOURCE_VIEW_DESC, D3D11_SHADER_RESOURCE_VIEW_DESC_0,
D3D11_SUBRESOURCE_DATA, D3D11_USAGE_DEFAULT,
},
Dxgi::Common::DXGI_FORMAT_R8G8B8A8_UNORM,
Dxgi::Common::{DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8_UNORM},
};

use crate::{gpu::GpuContext, util::d3d::D3dResource};
Expand All @@ -27,7 +27,7 @@ pub struct VertexBuffer {

impl VertexBuffer {
pub fn load_data(device: &ID3D11Device, data: &[u8], stride: u32) -> anyhow::Result<Self> {
let bind_flags = if stride == 4 {
let bind_flags = if matches!(stride, 1 | 4) {
D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_SHADER_RESOURCE
} else {
D3D11_BIND_VERTEX_BUFFER
Expand All @@ -53,12 +53,16 @@ impl VertexBuffer {
let buffer = buffer.unwrap();

let mut srv = None;
if stride == 4 {
if matches!(stride, 1 | 4) {
unsafe {
device.CreateShaderResourceView(
&buffer,
Some(&D3D11_SHADER_RESOURCE_VIEW_DESC {
Format: DXGI_FORMAT_R8G8B8A8_UNORM,
Format: if stride == 1 {
DXGI_FORMAT_R8_UNORM
} else {
DXGI_FORMAT_R8G8B8A8_UNORM
},
ViewDimension: D3D11_SRV_DIMENSION_BUFFER,
Anonymous: D3D11_SHADER_RESOURCE_VIEW_DESC_0 {
Buffer: D3D11_BUFFER_SRV {
Expand Down

0 comments on commit 70aeb43

Please sign in to comment.