lib/ecs_macros: implement

A small little proc_macro to generate ecs::Access for any struct. This
can be used instead of tuples in SystemData.
master
q3k 2021-03-22 00:20:35 +00:00
parent 45d271c39b
commit 591e3146cd
6 changed files with 131 additions and 11 deletions

View File

@ -51,6 +51,9 @@ rust_binary(
"@com_github_q3k_q3d//:q3d_rs",
"@rules_rust//tools/runfiles",
],
proc_macro_deps = [
"//lib/ecs_macros",
],
data = [
"//engine/shaders:forward_vert",
"//engine/shaders:forward_frag",

View File

@ -26,6 +26,7 @@ mod util;
mod physics;
use ecs::{Component, World, Processor};
use ecs_macros::Access;
use render::vulkan::data;
use render::material::{Texture, PBRMaterialBuilder};
use render::{Light, Material, Mesh, Transform, Renderable};
@ -153,13 +154,17 @@ impl Main {
}
}
#[derive(Access)]
struct MainData<'a> {
scene_info: ecs::ReadWriteGlobal<'a, render::SceneInfo>,
time: ecs::ReadGlobal<'a, Time>,
transforms: ecs::ReadWriteComponent<'a, Transform>,
}
impl<'a> ecs::System <'a> for Main {
type SystemData = ( ecs::ReadWriteGlobal<'a, render::SceneInfo>
, ecs::ReadGlobal<'a, Time>
, ecs::ReadWriteComponent<'a, Transform>
);
fn run(&mut self, (scene_info, time, transforms): Self::SystemData) {
let position = (time.get().instant() / 10.0) * 3.14 * 2.0;
type SystemData = MainData<'a>;
fn run(&mut self, sd: Self::SystemData) {
let position = (sd.time.get().instant() / 10.0) * 3.14 * 2.0;
let camera = cgm::Point3::new(
7.0 + (position / 4.0).sin(),
@ -173,16 +178,16 @@ impl<'a> ecs::System <'a> for Main {
cgm::Vector3::new(0.0, 0.0, 1.0)
);
scene_info.get().camera = camera;
scene_info.get().view = view;
sd.scene_info.get().camera = camera;
sd.scene_info.get().view = view;
*transforms.get_mut(self.light1).unwrap() = Transform::at(
*sd.transforms.get_mut(self.light1).unwrap() = Transform::at(
-0.0 + (position*3.0).sin() * 4.0,
-0.0 + (position*4.0).cos() * 4.0,
-0.0 + (position*2.0).sin() * 3.0,
);
*transforms.get_mut(self.light2).unwrap() = Transform::at(
*sd.transforms.get_mut(self.light2).unwrap() = Transform::at(
-0.0 + (position*3.0).cos() * 4.0,
-0.0 + (position*4.0).sin() * 4.0,
-0.0 + (position*2.0).cos() * 3.0,

15
lib/ecs_macros/BUILD Normal file
View File

@ -0,0 +1,15 @@
load("@rules_rust//rust:defs.bzl", "rust_proc_macro")
rust_proc_macro(
name = "ecs_macros",
edition = "2018",
srcs = [
"src/lib.rs",
],
visibility = ["//engine:__subpackages__"],
deps = [
"//third_party/cargo:proc_macro2",
"//third_party/cargo:quote",
"//third_party/cargo:syn",
],
)

63
lib/ecs_macros/src/lib.rs Normal file
View File

@ -0,0 +1,63 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::parse_macro_input;
#[proc_macro_derive(Access)]
pub fn derive_access(input: TokenStream) -> TokenStream {
let syn::DeriveInput { ident, data, .. } = parse_macro_input!(input);
let fields: Vec<proc_macro2::TokenStream> = match data {
syn::Data::Struct(st) => match st.fields {
syn::Fields::Named(syn::FieldsNamed { named, .. }) => {
named.iter().filter(|field| {
field.ident.is_some()
}).map(|field| {
let ident = &field.ident;
let mut ty = field.ty.clone();
// Yeet out path.segments.arguments (ie. type arguments), as these need to be
// absent in instantiations:
// struct Foo<'a, T> {
// bar: baz<'a, T>,
// }
// but:
// Foo {
// bar: baz::new(),
// }
// Ugh.
match ty {
syn::Type::Path(syn::TypePath { ref mut path, .. }) => {
let segments = path.segments.clone().iter().map(|seg| {
let mut seg = seg.clone();
seg.arguments = syn::PathArguments::None;
seg
}).collect();
path.segments = segments;
},
_ => (),
};
quote! {
#ident : #ty::fetch(world)
}
}).collect()
},
_ => {
panic!("can only derive Access on structs with named fields");
},
}
_ => panic!("can only derive Access on structs"),
};
let output = quote! {
impl <'a> ecs::system::Access<'a> for #ident<'a> {
fn fetch(world: &'a ecs::World) -> Self {
Self {
#( #fields, )*
}
}
}
};
let tokens = output.into();
//eprintln!("TOKENS: {}", tokens);
tokens
}

View File

@ -16,6 +16,8 @@ winit = "0.24.0"
cgmath = "0.18.0"
#openvr = "0.6.0"
flatbuffers = "0.6.1"
quote = "1.0.8"
syn = "1.0.58"
[workspace.metadata.raze]
workspace_path = "//third_party/cargo"
@ -72,3 +74,6 @@ gen_buildrs = true
[workspace.metadata.raze.crates.winapi.'0.3.9']
gen_buildrs = true
[workspace.metadata.raze.crates.proc-macro2.'1.0.24']
gen_buildrs = true

View File

@ -29,8 +29,36 @@ licenses([
])
# Generated Targets
# buildifier: disable=load-on-top
load(
"@rules_rust//cargo:cargo_build_script.bzl",
"cargo_build_script",
)
# Unsupported target "build-script-build" with type "custom-build" omitted
cargo_build_script(
name = "proc_macro2_build_script",
srcs = glob(["**/*.rs"]),
build_script_env = {
},
crate_features = [
"default",
"proc-macro",
],
crate_root = "build.rs",
data = glob(["**"]),
edition = "2018",
rustc_flags = [
"--cap-lints=allow",
],
tags = [
"cargo-raze",
"manual",
],
version = "1.0.24",
visibility = ["//visibility:private"],
deps = [
],
)
rust_library(
name = "proc_macro2",
@ -53,6 +81,7 @@ rust_library(
version = "1.0.24",
# buildifier: leave-alone
deps = [
":proc_macro2_build_script",
"//third_party/cargo/vendor/unicode-xid-0.2.1:unicode_xid",
],
)