Skip to main content

rpfm_lib/files/fxc/
mod.rs

1//---------------------------------------------------------------------------//
2// Copyright (c) 2017-2026 Ismael Gutiérrez González. All rights reserved.
3//
4// This file is part of the Rusted PackFile Manager (RPFM) project,
5// which can be found here: https://github.com/Frodo45127/rpfm.
6//
7// This file is licensed under the MIT license, which can be found here:
8// https://github.com/Frodo45127/rpfm/blob/master/LICENSE.
9//---------------------------------------------------------------------------//
10
11//! Compiled shader containers (`.fxc`) of the Warscape games.
12//!
13//! These files, under `fxc/` in the packs, hold one compiled DirectX shader each, with the defines and
14//! includes it was compiled with. Newer games use [`HlslCompiled`](crate::files::hlsl_compiled::HlslCompiled) instead.
15//!
16//! # File Format
17//!
18//! All values are little endian:
19//!
20//! ```text
21//! [u32]      signature (0x075BCD15)
22//! [u32]      version
23//! [u32]      define count
24//! [...]      defines: name and value, each a u32 size and that many bytes, NUL included
25//! [u32]      timestamp of the source
26//! [u32]      include count
27//! [...]      includes: path (u16 size and that many bytes, no NUL), u32 hash
28//! [...]      DXBC shader blob, up to the end of the file
29//! ```
30//!
31//! Only version 4 is known, used by Attila's DX11 shaders.
32//!
33//! # Usage
34//!
35//! ```ignore
36//! use rpfm_lib::files::fxc::Fxc;
37//! use rpfm_lib::files::Decodeable;
38//!
39//! let fxc = Fxc::decode(&mut data, &None)?;
40//! let dxbc = fxc.shader();
41//! ```
42
43use getset::*;
44use serde_derive::{Serialize, Deserialize};
45
46use crate::binary::{ReadBytes, WriteBytes};
47use crate::error::{Result, RLibError};
48use crate::files::{DecodeableExtraData, Decodeable, EncodeableExtraData, Encodeable};
49
50/// File extension of compiled shader containers.
51pub const EXTENSION: &str = ".fxc";
52
53/// Signature at the start of every fxc file.
54pub const SIGNATURE: u32 = 0x075B_CD15;
55
56mod v4;
57
58#[cfg(test)] mod fxc_test;
59
60//---------------------------------------------------------------------------//
61//                              Enum & Structs
62//---------------------------------------------------------------------------//
63
64/// A compiled shader with the defines and includes it was compiled with.
65#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
66#[getset(get = "pub", get_mut = "pub", set = "pub")]
67pub struct Fxc {
68
69    /// Version of the container format.
70    version: u32,
71
72    /// Preprocessor defines the shader was compiled with, in file order.
73    defines: Vec<FxcDefine>,
74
75    /// Timestamp of the shader's source file.
76    source_timestamp: u32,
77
78    /// Files the shader's source includes, in file order.
79    includes: Vec<FxcInclude>,
80
81    /// The compiled shader: a DXBC blob, with its reflection data.
82    shader: Vec<u8>,
83}
84
85/// A preprocessor define of a compiled shader.
86#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
87#[getset(get = "pub", get_mut = "pub", set = "pub")]
88pub struct FxcDefine {
89
90    /// Name of the define.
91    name: String,
92
93    /// Value of the define.
94    value: String,
95}
96
97/// A file included by the source of a compiled shader.
98#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
99#[getset(get = "pub", get_mut = "pub", set = "pub")]
100pub struct FxcInclude {
101
102    /// Path of the included file.
103    path: String,
104
105    /// Hash of the included file.
106    hash: u32,
107}
108
109//---------------------------------------------------------------------------//
110//                              Implementations
111//---------------------------------------------------------------------------//
112
113impl Decodeable for Fxc {
114
115    fn decode<R: ReadBytes>(data: &mut R, extra_data: &Option<DecodeableExtraData>) -> Result<Self> {
116        let signature = data.read_u32()?;
117        if signature != SIGNATURE {
118            return Err(RLibError::DecodingFxcUnsupportedSignature(signature));
119        }
120
121        let mut fxc = Self {
122            version: data.read_u32()?,
123            ..Default::default()
124        };
125
126        match fxc.version {
127            4 => fxc.read_v4(data, extra_data)?,
128            _ => return Err(RLibError::DecodingFxcUnsupportedVersion(fxc.version)),
129        }
130
131        Ok(fxc)
132    }
133}
134
135impl Encodeable for Fxc {
136
137    fn encode<W: WriteBytes>(&mut self, buffer: &mut W, extra_data: &Option<EncodeableExtraData>) -> Result<()> {
138        buffer.write_u32(SIGNATURE)?;
139        buffer.write_u32(self.version)?;
140
141        match self.version {
142            4 => self.write_v4(buffer, extra_data)?,
143            _ => return Err(RLibError::EncodingFxcUnsupportedVersion(self.version)),
144        }
145
146        Ok(())
147    }
148}