mirror of
https://github.com/bevyengine/bevy
synced 2024-11-24 21:53:07 +00:00
bevy_reflect: Feature-gate function reflection (#14174)
# Objective Function reflection requires a lot of macro code generation in the form of several `all_tuples!` invocations, as well as impls generated in the `Reflect` derive macro. Seeing as function reflection is currently a bit more niche, it makes sense to gate it all behind a feature. ## Solution Add a `functions` feature to `bevy_reflect`, which can be enabled in Bevy using the `reflect_functions` feature. ## Testing You can test locally by running: ``` cargo test --package bevy_reflect ``` That should ensure that everything still works with the feature disabled. To test with the feature on, you can run: ``` cargo test --package bevy_reflect --features functions ``` --- ## Changelog - Moved function reflection behind a Cargo feature (`bevy/reflect_functions` and `bevy_reflect/functions`) - Add `IntoFunction` export in `bevy_reflect::prelude` ## Internal Migration Guide > [!important] > Function reflection was introduced as part of the 0.15 dev cycle. This migration guide was written for developers relying on `main` during this cycle, and is not a breaking change coming from 0.14. Function reflection is now gated behind a feature. To use function reflection, enable the feature: - If using `bevy_reflect` directly, enable the `functions` feature - If using `bevy`, enable the `reflect_functions` feature
This commit is contained in:
parent
57d05927d6
commit
99c9218b56
21 changed files with 89 additions and 42 deletions
|
@ -348,6 +348,9 @@ ios_simulator = ["bevy_internal/ios_simulator"]
|
|||
# Enable built in global state machines
|
||||
bevy_state = ["bevy_internal/bevy_state"]
|
||||
|
||||
# Enable function reflection
|
||||
reflect_functions = ["bevy_internal/reflect_functions"]
|
||||
|
||||
[dependencies]
|
||||
bevy_internal = { path = "crates/bevy_internal", version = "0.15.0-dev", default-features = false }
|
||||
|
||||
|
@ -2158,6 +2161,7 @@ wasm = false
|
|||
name = "function_reflection"
|
||||
path = "examples/reflection/function_reflection.rs"
|
||||
doc-scrape-examples = true
|
||||
required-features = ["reflect_functions"]
|
||||
|
||||
[package.metadata.example.function_reflection]
|
||||
name = "Function Reflection"
|
||||
|
|
|
@ -195,6 +195,9 @@ ios_simulator = ["bevy_pbr?/ios_simulator", "bevy_render?/ios_simulator"]
|
|||
# Enable built in global state machines
|
||||
bevy_state = ["dep:bevy_state"]
|
||||
|
||||
# Enable function reflection
|
||||
reflect_functions = ["bevy_reflect/functions"]
|
||||
|
||||
[dependencies]
|
||||
# bevy
|
||||
bevy_a11y = { path = "../bevy_a11y", version = "0.15.0-dev" }
|
||||
|
|
|
@ -19,6 +19,8 @@ smallvec = ["dep:smallvec"]
|
|||
uuid = ["dep:uuid"]
|
||||
# When enabled, allows documentation comments to be accessed via reflection
|
||||
documentation = ["bevy_reflect_derive/documentation"]
|
||||
# Enables function reflection
|
||||
functions = ["bevy_reflect_derive/functions"]
|
||||
|
||||
[dependencies]
|
||||
# bevy
|
||||
|
|
|
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
|||
publish = false
|
||||
|
||||
[dependencies]
|
||||
bevy_reflect = { path = "../" }
|
||||
bevy_reflect = { path = "../", features = ["functions"] }
|
||||
|
||||
[dev-dependencies]
|
||||
compile_fail_utils = { path = "../../../tools/compile_fail_utils" }
|
||||
|
|
|
@ -15,6 +15,8 @@ proc-macro = true
|
|||
default = []
|
||||
# When enabled, allows documentation comments to be processed by the reflection macros
|
||||
documentation = []
|
||||
# Enables macro logic related to function reflection
|
||||
functions = []
|
||||
|
||||
[dependencies]
|
||||
bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.15.0-dev" }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::derive_data::{EnumVariantFields, ReflectEnum, StructField};
|
||||
use crate::enum_utility::{EnumVariantOutputData, TryApplyVariantBuilder, VariantBuilder};
|
||||
use crate::impls::{impl_function_traits, impl_type_path, impl_typed};
|
||||
use crate::impls::{impl_type_path, impl_typed};
|
||||
use bevy_macro_utils::fq_std::{FQAny, FQBox, FQOption, FQResult};
|
||||
use proc_macro2::{Ident, Span};
|
||||
use quote::quote;
|
||||
|
@ -65,7 +65,11 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
|
|||
|
||||
let type_path_impl = impl_type_path(reflect_enum.meta());
|
||||
|
||||
let function_impls = impl_function_traits(reflect_enum.meta(), &where_clause_options);
|
||||
#[cfg(not(feature = "functions"))]
|
||||
let function_impls = None::<proc_macro2::TokenStream>;
|
||||
#[cfg(feature = "functions")]
|
||||
let function_impls =
|
||||
crate::impls::impl_function_traits(reflect_enum.meta(), &where_clause_options);
|
||||
|
||||
let get_type_registration_impl = reflect_enum.get_type_registration(&where_clause_options);
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
mod enums;
|
||||
#[cfg(feature = "functions")]
|
||||
mod func;
|
||||
mod structs;
|
||||
mod tuple_structs;
|
||||
|
@ -6,6 +7,7 @@ mod typed;
|
|||
mod values;
|
||||
|
||||
pub(crate) use enums::impl_enum;
|
||||
#[cfg(feature = "functions")]
|
||||
pub(crate) use func::impl_function_traits;
|
||||
pub(crate) use structs::impl_struct;
|
||||
pub(crate) use tuple_structs::impl_tuple_struct;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::impls::{impl_function_traits, impl_type_path, impl_typed};
|
||||
use crate::impls::{impl_type_path, impl_typed};
|
||||
use crate::utility::ident_or_index;
|
||||
use crate::ReflectStruct;
|
||||
use bevy_macro_utils::fq_std::{FQAny, FQBox, FQDefault, FQOption, FQResult};
|
||||
|
@ -54,7 +54,11 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> proc_macro2::TokenS
|
|||
|
||||
let type_path_impl = impl_type_path(reflect_struct.meta());
|
||||
|
||||
let function_impls = impl_function_traits(reflect_struct.meta(), &where_clause_options);
|
||||
#[cfg(not(feature = "functions"))]
|
||||
let function_impls = None::<proc_macro2::TokenStream>;
|
||||
#[cfg(feature = "functions")]
|
||||
let function_impls =
|
||||
crate::impls::impl_function_traits(reflect_struct.meta(), &where_clause_options);
|
||||
|
||||
let get_type_registration_impl = reflect_struct.get_type_registration(&where_clause_options);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::impls::{impl_function_traits, impl_type_path, impl_typed};
|
||||
use crate::impls::{impl_type_path, impl_typed};
|
||||
use crate::ReflectStruct;
|
||||
use bevy_macro_utils::fq_std::{FQAny, FQBox, FQDefault, FQOption, FQResult};
|
||||
use quote::{quote, ToTokens};
|
||||
|
@ -46,7 +46,11 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> proc_macro2::
|
|||
|
||||
let type_path_impl = impl_type_path(reflect_struct.meta());
|
||||
|
||||
let function_impls = impl_function_traits(reflect_struct.meta(), &where_clause_options);
|
||||
#[cfg(not(feature = "functions"))]
|
||||
let function_impls = None::<proc_macro2::TokenStream>;
|
||||
#[cfg(feature = "functions")]
|
||||
let function_impls =
|
||||
crate::impls::impl_function_traits(reflect_struct.meta(), &where_clause_options);
|
||||
|
||||
let (impl_generics, ty_generics, where_clause) = reflect_struct
|
||||
.meta()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::impls::{impl_function_traits, impl_type_path, impl_typed};
|
||||
use crate::impls::{impl_type_path, impl_typed};
|
||||
use crate::utility::WhereClauseOptions;
|
||||
use crate::ReflectMeta;
|
||||
use bevy_macro_utils::fq_std::{FQAny, FQBox, FQClone, FQOption, FQResult};
|
||||
|
@ -33,7 +33,10 @@ pub(crate) fn impl_value(meta: &ReflectMeta) -> proc_macro2::TokenStream {
|
|||
|
||||
let type_path_impl = impl_type_path(meta);
|
||||
|
||||
let function_impls = impl_function_traits(meta, &where_clause_options);
|
||||
#[cfg(not(feature = "functions"))]
|
||||
let function_impls = None::<proc_macro2::TokenStream>;
|
||||
#[cfg(feature = "functions")]
|
||||
let function_impls = crate::impls::impl_function_traits(meta, &where_clause_options);
|
||||
|
||||
let (impl_generics, ty_generics, where_clause) = type_path.generics().split_for_impl();
|
||||
let where_reflect_clause = where_clause_options.extend_where_clause(where_clause);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::func::macros::impl_function_traits;
|
||||
use crate::{
|
||||
self as bevy_reflect, utility::reflect_hasher, ApplyError, Reflect, ReflectKind, ReflectMut,
|
||||
ReflectOwned, ReflectRef, TypeInfo, TypePath, TypePathTable,
|
||||
|
@ -359,7 +358,9 @@ impl Array for DynamicArray {
|
|||
}
|
||||
|
||||
impl_type_path!((in bevy_reflect) DynamicArray);
|
||||
impl_function_traits!(DynamicArray);
|
||||
#[cfg(feature = "functions")]
|
||||
crate::func::macros::impl_function_traits!(DynamicArray);
|
||||
|
||||
/// An iterator over an [`Array`].
|
||||
pub struct ArrayIter<'a> {
|
||||
array: &'a dyn Array,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use bevy_reflect_derive::impl_type_path;
|
||||
|
||||
use crate::func::macros::impl_function_traits;
|
||||
use crate::{
|
||||
self as bevy_reflect, enum_debug, enum_hash, enum_partial_eq, ApplyError, DynamicStruct,
|
||||
DynamicTuple, Enum, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Struct, Tuple,
|
||||
|
@ -428,4 +427,5 @@ impl Reflect for DynamicEnum {
|
|||
}
|
||||
|
||||
impl_type_path!((in bevy_reflect) DynamicEnum);
|
||||
impl_function_traits!(DynamicEnum);
|
||||
#[cfg(feature = "functions")]
|
||||
crate::func::macros::impl_function_traits!(DynamicEnum);
|
||||
|
|
|
@ -3,7 +3,6 @@ use smallvec::{Array as SmallArray, SmallVec};
|
|||
|
||||
use std::any::Any;
|
||||
|
||||
use crate::func::macros::impl_function_traits;
|
||||
use crate::utility::GenericTypeInfoCell;
|
||||
use crate::{
|
||||
self as bevy_reflect, ApplyError, FromReflect, FromType, GetTypeRegistration, List, ListInfo,
|
||||
|
@ -188,4 +187,5 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl_function_traits!(SmallVec<T>; <T: SmallArray + TypePath + Send + Sync> where T::Item: FromReflect + TypePath);
|
||||
#[cfg(feature = "functions")]
|
||||
crate::func::macros::impl_function_traits!(SmallVec<T>; <T: SmallArray + TypePath + Send + Sync> where T::Item: FromReflect + TypePath);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::func::macros::impl_function_traits;
|
||||
use crate::std_traits::ReflectDefault;
|
||||
use crate::utility::{
|
||||
reflect_hasher, GenericTypeInfoCell, GenericTypePathCell, NonGenericTypeInfoCell,
|
||||
|
@ -398,7 +397,8 @@ impl_reflect_for_veclike!(
|
|||
Vec::pop,
|
||||
[T]
|
||||
);
|
||||
impl_function_traits!(Vec<T>; <T: FromReflect + TypePath + GetTypeRegistration>);
|
||||
#[cfg(feature = "functions")]
|
||||
crate::func::macros::impl_function_traits!(Vec<T>; <T: FromReflect + TypePath + GetTypeRegistration>);
|
||||
|
||||
impl_reflect_for_veclike!(
|
||||
::alloc::collections::VecDeque<T>,
|
||||
|
@ -408,7 +408,8 @@ impl_reflect_for_veclike!(
|
|||
VecDeque::pop_back,
|
||||
VecDeque::<T>
|
||||
);
|
||||
impl_function_traits!(VecDeque<T>; <T: FromReflect + TypePath + GetTypeRegistration>);
|
||||
#[cfg(feature = "functions")]
|
||||
crate::func::macros::impl_function_traits!(VecDeque<T>; <T: FromReflect + TypePath + GetTypeRegistration>);
|
||||
|
||||
macro_rules! impl_reflect_for_hashmap {
|
||||
($ty:path) => {
|
||||
|
@ -638,7 +639,8 @@ macro_rules! impl_reflect_for_hashmap {
|
|||
impl_reflect_for_hashmap!(::std::collections::HashMap<K, V, S>);
|
||||
impl_type_path!(::std::collections::hash_map::RandomState);
|
||||
impl_type_path!(::std::collections::HashMap<K, V, S>);
|
||||
impl_function_traits!(::std::collections::HashMap<K, V, S>;
|
||||
#[cfg(feature = "functions")]
|
||||
crate::func::macros::impl_function_traits!(::std::collections::HashMap<K, V, S>;
|
||||
<
|
||||
K: FromReflect + TypePath + GetTypeRegistration + Eq + Hash,
|
||||
V: FromReflect + TypePath + GetTypeRegistration,
|
||||
|
@ -649,7 +651,8 @@ impl_function_traits!(::std::collections::HashMap<K, V, S>;
|
|||
impl_reflect_for_hashmap!(bevy_utils::hashbrown::HashMap<K, V, S>);
|
||||
impl_type_path!(::bevy_utils::hashbrown::hash_map::DefaultHashBuilder);
|
||||
impl_type_path!(::bevy_utils::hashbrown::HashMap<K, V, S>);
|
||||
impl_function_traits!(::bevy_utils::hashbrown::HashMap<K, V, S>;
|
||||
#[cfg(feature = "functions")]
|
||||
crate::func::macros::impl_function_traits!(::bevy_utils::hashbrown::HashMap<K, V, S>;
|
||||
<
|
||||
K: FromReflect + TypePath + GetTypeRegistration + Eq + Hash,
|
||||
V: FromReflect + TypePath + GetTypeRegistration,
|
||||
|
@ -869,7 +872,8 @@ where
|
|||
}
|
||||
|
||||
impl_type_path!(::std::collections::BTreeMap<K, V>);
|
||||
impl_function_traits!(::std::collections::BTreeMap<K, V>;
|
||||
#[cfg(feature = "functions")]
|
||||
crate::func::macros::impl_function_traits!(::std::collections::BTreeMap<K, V>;
|
||||
<
|
||||
K: FromReflect + TypePath + GetTypeRegistration + Eq + Ord,
|
||||
V: FromReflect + TypePath + GetTypeRegistration
|
||||
|
@ -1035,7 +1039,8 @@ impl<T: Reflect + TypePath + GetTypeRegistration, const N: usize> GetTypeRegistr
|
|||
}
|
||||
}
|
||||
|
||||
impl_function_traits!([T; N]; <T: Reflect + TypePath + GetTypeRegistration> [const N: usize]);
|
||||
#[cfg(feature = "functions")]
|
||||
crate::func::macros::impl_function_traits!([T; N]; <T: Reflect + TypePath + GetTypeRegistration> [const N: usize]);
|
||||
|
||||
impl_reflect! {
|
||||
#[type_path = "core::option"]
|
||||
|
@ -1194,7 +1199,8 @@ impl FromReflect for Cow<'static, str> {
|
|||
}
|
||||
}
|
||||
|
||||
impl_function_traits!(Cow<'static, str>);
|
||||
#[cfg(feature = "functions")]
|
||||
crate::func::macros::impl_function_traits!(Cow<'static, str>);
|
||||
|
||||
impl<T: TypePath> TypePath for [T]
|
||||
where
|
||||
|
@ -1374,7 +1380,8 @@ impl<T: FromReflect + Clone + TypePath + GetTypeRegistration> FromReflect for Co
|
|||
}
|
||||
}
|
||||
|
||||
impl_function_traits!(Cow<'static, [T]>; <T: FromReflect + Clone + TypePath + GetTypeRegistration>);
|
||||
#[cfg(feature = "functions")]
|
||||
crate::func::macros::impl_function_traits!(Cow<'static, [T]>; <T: FromReflect + Clone + TypePath + GetTypeRegistration>);
|
||||
|
||||
impl Reflect for &'static str {
|
||||
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
|
||||
|
@ -1482,7 +1489,8 @@ impl FromReflect for &'static str {
|
|||
}
|
||||
}
|
||||
|
||||
impl_function_traits!(&'static str);
|
||||
#[cfg(feature = "functions")]
|
||||
crate::func::macros::impl_function_traits!(&'static str);
|
||||
|
||||
impl Reflect for &'static Path {
|
||||
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
|
||||
|
@ -1589,7 +1597,8 @@ impl FromReflect for &'static Path {
|
|||
}
|
||||
}
|
||||
|
||||
impl_function_traits!(&'static Path);
|
||||
#[cfg(feature = "functions")]
|
||||
crate::func::macros::impl_function_traits!(&'static Path);
|
||||
|
||||
impl Reflect for Cow<'static, Path> {
|
||||
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
|
||||
|
@ -1706,7 +1715,8 @@ impl GetTypeRegistration for Cow<'static, Path> {
|
|||
}
|
||||
}
|
||||
|
||||
impl_function_traits!(Cow<'static, Path>);
|
||||
#[cfg(feature = "functions")]
|
||||
crate::func::macros::impl_function_traits!(Cow<'static, Path>);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
|
@ -476,6 +476,7 @@
|
|||
mod array;
|
||||
mod fields;
|
||||
mod from_reflect;
|
||||
#[cfg(feature = "functions")]
|
||||
pub mod func;
|
||||
mod list;
|
||||
mod map;
|
||||
|
@ -517,6 +518,9 @@ pub mod prelude {
|
|||
ReflectDeserialize, ReflectFromReflect, ReflectPath, ReflectSerialize, Struct, TupleStruct,
|
||||
TypePath,
|
||||
};
|
||||
|
||||
#[cfg(feature = "functions")]
|
||||
pub use crate::func::IntoFunction;
|
||||
}
|
||||
|
||||
pub use array::*;
|
||||
|
|
|
@ -4,7 +4,6 @@ use std::hash::{Hash, Hasher};
|
|||
|
||||
use bevy_reflect_derive::impl_type_path;
|
||||
|
||||
use crate::func::macros::impl_function_traits;
|
||||
use crate::utility::reflect_hasher;
|
||||
use crate::{
|
||||
self as bevy_reflect, ApplyError, FromReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned,
|
||||
|
@ -370,7 +369,8 @@ impl Reflect for DynamicList {
|
|||
}
|
||||
|
||||
impl_type_path!((in bevy_reflect) DynamicList);
|
||||
impl_function_traits!(DynamicList);
|
||||
#[cfg(feature = "functions")]
|
||||
crate::func::macros::impl_function_traits!(DynamicList);
|
||||
|
||||
impl Debug for DynamicList {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
|
|
|
@ -4,7 +4,6 @@ use std::fmt::{Debug, Formatter};
|
|||
use bevy_reflect_derive::impl_type_path;
|
||||
use bevy_utils::{Entry, HashMap};
|
||||
|
||||
use crate::func::macros::impl_function_traits;
|
||||
use crate::{
|
||||
self as bevy_reflect, ApplyError, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef,
|
||||
TypeInfo, TypePath, TypePathTable,
|
||||
|
@ -418,7 +417,8 @@ impl Reflect for DynamicMap {
|
|||
}
|
||||
|
||||
impl_type_path!((in bevy_reflect) DynamicMap);
|
||||
impl_function_traits!(DynamicMap);
|
||||
#[cfg(feature = "functions")]
|
||||
crate::func::macros::impl_function_traits!(DynamicMap);
|
||||
|
||||
impl Debug for DynamicMap {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::attributes::{impl_custom_attribute_methods, CustomAttributes};
|
||||
use crate::func::macros::impl_function_traits;
|
||||
use crate::{
|
||||
self as bevy_reflect, ApplyError, NamedField, Reflect, ReflectKind, ReflectMut, ReflectOwned,
|
||||
ReflectRef, TypeInfo, TypePath, TypePathTable,
|
||||
|
@ -500,7 +499,8 @@ impl Reflect for DynamicStruct {
|
|||
}
|
||||
|
||||
impl_type_path!((in bevy_reflect) DynamicStruct);
|
||||
impl_function_traits!(DynamicStruct);
|
||||
#[cfg(feature = "functions")]
|
||||
crate::func::macros::impl_function_traits!(DynamicStruct);
|
||||
|
||||
impl Debug for DynamicStruct {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
|
|
|
@ -710,6 +710,8 @@ macro_rules! impl_type_path_tuple {
|
|||
|
||||
all_tuples!(impl_type_path_tuple, 0, 12, P);
|
||||
|
||||
#[cfg(feature = "functions")]
|
||||
const _: () = {
|
||||
macro_rules! impl_get_ownership_tuple {
|
||||
($($name: ident),*) => {
|
||||
$crate::func::args::impl_get_ownership!(($($name,)*); <$($name),*>);
|
||||
|
@ -734,6 +736,7 @@ macro_rules! impl_into_return_tuple {
|
|||
|
||||
// The unit type (i.e. `()`) is special-cased, so we skip implementing it here.
|
||||
all_tuples!(impl_into_return_tuple, 1, 12, P);
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use bevy_reflect_derive::impl_type_path;
|
||||
|
||||
use crate::attributes::{impl_custom_attribute_methods, CustomAttributes};
|
||||
use crate::func::macros::impl_function_traits;
|
||||
use crate::{
|
||||
self as bevy_reflect, ApplyError, DynamicTuple, Reflect, ReflectKind, ReflectMut, ReflectOwned,
|
||||
ReflectRef, Tuple, TypeInfo, TypePath, TypePathTable, UnnamedField,
|
||||
|
@ -409,7 +408,8 @@ impl Reflect for DynamicTupleStruct {
|
|||
}
|
||||
|
||||
impl_type_path!((in bevy_reflect) DynamicTupleStruct);
|
||||
impl_function_traits!(DynamicTupleStruct);
|
||||
#[cfg(feature = "functions")]
|
||||
crate::func::macros::impl_function_traits!(DynamicTupleStruct);
|
||||
|
||||
impl Debug for DynamicTupleStruct {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
|
|
|
@ -75,6 +75,7 @@ The default feature set enables most of the expected features of a game engine,
|
|||
|pbr_multi_layer_material_textures|Enable support for multi-layer material textures in the `StandardMaterial`, at the risk of blowing past the global, per-shader texture limit on older/lower-end GPUs|
|
||||
|pbr_transmission_textures|Enable support for transmission-related textures in the `StandardMaterial`, at the risk of blowing past the global, per-shader texture limit on older/lower-end GPUs|
|
||||
|pnm|PNM image format support, includes pam, pbm, pgm and ppm|
|
||||
|reflect_functions|Enable function reflection|
|
||||
|serialize|Enable serialization support through serde|
|
||||
|shader_format_glsl|Enable support for shaders in GLSL|
|
||||
|shader_format_spirv|Enable support for shaders in SPIR-V|
|
||||
|
|
Loading…
Reference in a new issue