tirbofish/dropbear · commit
31165a80c92ec191e1959bde608471d3b0355dcd
wip: eucalyptus-core/scene.rs is the only one not done, all bindings completed
Signature present but could not be verified.
Unverified
@@ -66,6 +66,7 @@ pub struct AssetRegistry { model_labels: HashMap<String, Handle<Model>>, } +#[repr(C)] #[derive(Debug, Clone)] #[dropbear_macro::repr_c_enum] pub enum AssetKind { @@ -203,6 +204,10 @@ impl AssetRegistry { self.add_texture_with_label(label, texture) } + + pub fn get_label_from_texture_handle(&self, handle: Handle<Texture>) -> Option<String> { + self.texture_labels.iter().find_map(|(label, h)| if *h == handle { Some(label.clone()) } else { None }) + } } /// Model stuff @@ -225,6 +225,10 @@ impl MeshRenderer { self.import_scale = scale; } + pub fn import_scale(&self) -> f32 { + self.import_scale + } + pub fn set_model(&mut self, model: Handle<Model>) { self.handle = model; } @@ -237,6 +241,10 @@ impl MeshRenderer { self.texture_override = Some(texture); } + pub fn texture_override(&self) -> Option<Handle<Texture>> { + self.texture_override + } + pub fn is_texture_attached(&self, texture: Handle<Texture>) -> bool { let registry = ASSET_REGISTRY.read(); @@ -7,6 +7,7 @@ use syn::{ DeriveInput, FnArg, GenericArgument, Ident, Item, ItemFn, ItemMod, ItemEnum, LitStr, PathArguments, ReturnType, Token, Type, }; +use std::path::Path; /// A `derive` macro that converts a struct to a usable [SerializableComponent]. /// @@ -550,7 +551,10 @@ fn build_c_wrapper( option_inner: Option<&Type>, c_args: CArgs, ) -> proc_macro2::TokenStream { - let c_name = c_args.name.unwrap_or_else(|| default_c_name(original_name)); + let module_path = module_path_from_callsite(); + let c_name = c_args + .name + .unwrap_or_else(|| default_c_name(original_name, module_path.as_deref())); let c_ident = Ident::new(&c_name, original_name.span()); let mut wrapper_inputs = Vec::new(); @@ -893,9 +897,38 @@ fn build_jni_return( let (sig, wrapper, jvalue_expr) = jni_boxing_info(inner, jni_path); let body = quote! { match #inner_name(#(#call_args),*) { - crate::scripting::result::DropbearNativeResult::Ok(val) => { - crate::return_boxed!(&mut env, val.map(|v| #jvalue_expr), #sig, #wrapper) - } + crate::scripting::result::DropbearNativeResult::Ok(val) => match val { + Some(v) => { + let cls = match env.find_class(#wrapper) { + Ok(cls) => cls, + Err(e) => { + eprintln!("return_boxed failed for {}: {:?}", #wrapper, e); + let _ = env.throw_new("java/lang/RuntimeException", format!("Boxing failed: {:?}", e)); + return std::ptr::null_mut(); + } + }; + + let param: #jni_path::objects::JValue = #jvalue_expr; + let ret = match env.call_static_method(cls, "valueOf", #sig, &[param]) { + Ok(ret) => ret, + Err(e) => { + eprintln!("return_boxed failed for {}: {:?}", #wrapper, e); + let _ = env.throw_new("java/lang/RuntimeException", format!("Boxing failed: {:?}", e)); + return std::ptr::null_mut(); + } + }; + + match ret.l() { + Ok(obj) => obj.into_raw(), + Err(e) => { + eprintln!("return_boxed failed for {}: {:?}", #wrapper, e); + let _ = env.throw_new("java/lang/RuntimeException", format!("Boxing failed: {:?}", e)); + std::ptr::null_mut() + } + } + } + None => std::ptr::null_mut(), + }, crate::scripting::result::DropbearNativeResult::Err(e) => { let _ = env.throw_new("java/lang/RuntimeException", format!("JNI call failed: {:?}", e)); std::ptr::null_mut() @@ -1157,8 +1190,50 @@ fn jni_boxing_info( ) } -fn default_c_name(original_name: &Ident) -> String { - format!("dropbear_{}", original_name) +fn module_path_from_callsite() -> Option<String> { + let path = proc_macro::Span::call_site().local_file()?; + // proc_macro::Span::call_site().source_text() + module_path_from_file(&path) +} + +fn module_path_from_file(path: &Path) -> Option<String> { + let components: Vec<String> = path + .components() + .map(|c| c.as_os_str().to_string_lossy().to_string()) + .collect(); + + let src_index = components.iter().position(|c| c == "src")?; + if src_index + 1 >= components.len() { + return None; + } + + let mut parts = components[src_index + 1..].to_vec(); + let file = parts.pop()?; + let stem = file.strip_suffix(".rs").unwrap_or(&file); + + if stem != "mod" && stem != "lib" && stem != "main" { + parts.push(stem.to_string()); + } + + if parts.is_empty() { + return None; + } + + let joined = parts.join("_"); + Some(joined.replace('-', "_")) +} + +fn default_c_name(original_name: &Ident, module_path: Option<&str>) -> String { + let mut name = String::from("dropbear"); + if let Some(path) = module_path { + if !path.is_empty() { + name.push('_'); + name.push_str(path); + } + } + name.push('_'); + name.push_str(&original_name.to_string()); + name } fn is_string_type(ty: &Type) -> bool { @@ -61,5 +61,4 @@ jvm_debug = ["jvm"] [build-dependencies] anyhow.workspace = true app_dirs2.workspace = true -cbindgen.workspace = true -syn = { workspace = true, features = ["full"] } +goanna-gen = { path = "../goanna-gen" } @@ -6,798 +6,10 @@ fn main() -> anyhow::Result<()> { println!("cargo:rustc-link-arg=/NODEFAULTLIB:libcmt.lib"); } - generate_c_header()?; + goanna_gen::generate_c_header()?; println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=src"); println!("cargo:rerun-if-changed=../../include/dropbear.h"); Ok(()) -} - -fn generate_c_header() -> anyhow::Result<()> { - let manifest_dir = std::path::PathBuf::from(std::env::var("CARGO_MANIFEST_DIR")?); - let workspace_root = manifest_dir - .parent() - .and_then(|p| p.parent()) - .ok_or_else(|| anyhow::anyhow!("Failed to locate workspace root"))?; - - let output_path = workspace_root.join("include").join("dropbear.h"); - if let Some(parent) = output_path.parent() { - std::fs::create_dir_all(parent)?; - } - - let src_dir = manifest_dir.join("src"); - let mut functions = Vec::new(); - let mut structs = std::collections::HashMap::new(); - let mut enums = Vec::new(); - collect_exported_functions(&src_dir, &mut functions, &mut structs, &mut enums)?; - - let header = render_header(&functions, &structs, &enums); - std::fs::write(&output_path, header)?; - - Ok(()) -} - -#[derive(Debug)] -struct ExportedFunction { - name: String, - params: Vec<ExportParam>, - out_type: Option<String>, -} - -#[derive(Debug, Clone)] -struct ExportParam { - name: String, - ty: String, -} - -fn collect_exported_functions( - dir: &std::path::Path, - out: &mut Vec<ExportedFunction>, - structs: &mut std::collections::HashMap<String, StructDef>, - enums: &mut Vec<EnumDef>, -) -> anyhow::Result<()> { - if dir.is_dir() { - for entry in std::fs::read_dir(dir)? { - let entry = entry?; - let path = entry.path(); - if path.is_dir() { - collect_exported_functions(&path, out, structs, enums)?; - } else if path.extension().and_then(|s| s.to_str()) == Some("rs") { - let content = std::fs::read_to_string(&path)?; - let file = syn::parse_file(&content)?; - extract_exports_from_file(&file, out, structs)?; - extract_structs_from_file(&file, structs)?; - extract_repr_c_enums_from_file(&file, enums)?; - } - } - } - Ok(()) -} - -fn extract_exports_from_file( - file: &syn::File, - out: &mut Vec<ExportedFunction>, - _structs: &mut std::collections::HashMap<String, StructDef>, -) -> anyhow::Result<()> { - for item in &file.items { - if let syn::Item::Fn(func) = item { - if let Some(export) = parse_export_attr(&func.attrs)? { - if export.c.is_none() { - continue; - } - - let c_name = export.c.and_then(|c| c.name).unwrap_or_else(|| { - format!("dropbear_{}", func.sig.ident) - }); - - let (out_type, out_is_optional) = extract_result_type(&func.sig.output)?; - let mut params = Vec::new(); - for input in &func.sig.inputs { - if let syn::FnArg::Typed(pat_ty) = input { - let (define_ty, is_entity) = extract_arg_markers(&pat_ty.attrs); - let name = match &*pat_ty.pat { - syn::Pat::Ident(ident) => ident.ident.to_string(), - _ => continue, - }; - - let ty = if is_entity { - "uint64_t".to_string() - } else if let Some(define_ty) = define_ty { - type_to_c(&define_ty, true) - } else if is_object_input(&pat_ty.ty) { - object_input_to_c(&pat_ty.ty) - } else { - type_to_c(&pat_ty.ty, false) - }; - - params.push(ExportParam { name, ty }); - } - } - - if out_type.is_some() { - let out_ty = out_type.clone().unwrap(); - params.push(ExportParam { name: "out0".to_string(), ty: format!("{}*", out_ty) }); - if out_is_optional { - params.push(ExportParam { name: "out0_present".to_string(), ty: "bool*".to_string() }); - } - } - - out.push(ExportedFunction { - name: c_name, - params, - out_type, - }); - } - } - } - Ok(()) -} - -#[derive(Debug, Clone)] -struct StructDef { - name: String, - fields: Vec<ExportParam>, - is_repr_c: bool, -} - -#[derive(Debug)] -struct EnumDef { - name: String, - variants: Vec<EnumVariantDef>, -} - -#[derive(Debug)] -struct EnumVariantDef { - name: String, - fields: Vec<ExportParam>, -} - -fn extract_repr_c_enums_from_file( - file: &syn::File, - enums: &mut Vec<EnumDef>, -) -> anyhow::Result<()> { - for item in &file.items { - if let syn::Item::Enum(enm) = item { - if !has_repr_c_enum_attr(&enm.attrs) { - continue; - } - let mut variants = Vec::new(); - for variant in &enm.variants { - let mut fields = Vec::new(); - match &variant.fields { - syn::Fields::Named(named) => { - for field in &named.named { - let name = field - .ident - .as_ref() - .map(|i| i.to_string()) - .unwrap_or_else(|| "field".to_string()); - let ty = type_to_c(&field.ty, false); - fields.push(ExportParam { name, ty }); - } - } - syn::Fields::Unnamed(unnamed) => { - for (idx, field) in unnamed.unnamed.iter().enumerate() { - let name = format!("_{}", idx); - let ty = type_to_c(&field.ty, false); - fields.push(ExportParam { name, ty }); - } - } - syn::Fields::Unit => {} - } - variants.push(EnumVariantDef { name: variant.ident.to_string(), fields }); - } - enums.push(EnumDef { name: enm.ident.to_string(), variants }); - } - } - Ok(()) -} - -fn extract_structs_from_file( - file: &syn::File, - structs: &mut std::collections::HashMap<String, StructDef>, -) -> anyhow::Result<()> { - for item in &file.items { - if let syn::Item::Struct(strct) = item { - let name = strct.ident.to_string(); - let is_repr_c = has_repr_c(&strct.attrs); - let mut fields = Vec::new(); - - if let syn::Fields::Named(named) = &strct.fields { - for field in &named.named { - let field_name = field.ident.as_ref().map(|i| i.to_string()).unwrap_or_else(|| "field".to_string()); - let ty = type_to_c(&field.ty, false); - fields.push(ExportParam { name: field_name, ty }); - } - } - - structs.insert(name.clone(), StructDef { name, fields, is_repr_c }); - } - } - - Ok(()) -} - -#[derive(Default)] -struct ExportAttr { - c: Option<CArgs>, -} - -#[derive(Default)] -struct CArgs { - name: Option<String>, -} - -fn parse_export_attr(attrs: &[syn::Attribute]) -> anyhow::Result<Option<ExportAttr>> { - for attr in attrs { - let path = attr.path(); - let is_export = path.segments.last().map(|s| s.ident == "export").unwrap_or(false) - || (path.segments.iter().any(|s| s.ident == "dropbear_macro") - && path.segments.last().map(|s| s.ident == "export").unwrap_or(false)); - if !is_export { - continue; - } - - let meta = &attr.meta; - if let syn::Meta::List(list) = meta { - let args = syn::parse2::<ExportArgs>(list.tokens.clone())?; - return Ok(Some(ExportAttr { c: args.c })); - } - } - - Ok(None) -} - -struct ExportArgs { - c: Option<CArgs>, -} - -impl syn::parse::Parse for ExportArgs { - fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { - let items = syn::punctuated::Punctuated::<ExportItem, syn::Token![,]>::parse_terminated(input)?; - let mut args = ExportArgs { c: None }; - - for item in items { - if let ExportItem::C(c) = item { - args.c = Some(c); - } - } - - Ok(args) - } -} - -enum ExportItem { - C(CArgs), - Kotlin, -} - -impl syn::parse::Parse for ExportItem { - fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { - let ident: syn::Ident = input.parse()?; - if ident == "c" { - let args = if input.peek(syn::token::Paren) { - let content; - syn::parenthesized!(content in input); - let mut c_args = CArgs::default(); - while !content.is_empty() { - let key: syn::Ident = content.parse()?; - content.parse::<syn::Token![=]>()?; - let value: syn::LitStr = content.parse()?; - if key == "name" { - c_args.name = Some(value.value()); - } - if content.peek(syn::Token![,]) { - content.parse::<syn::Token![,]>()?; - } - } - c_args - } else { - CArgs::default() - }; - return Ok(ExportItem::C(args)); - } - - if ident == "kotlin" { - if input.peek(syn::token::Paren) { - let content; - syn::parenthesized!(content in input); - while !content.is_empty() { - let _key: syn::Ident = content.parse()?; - content.parse::<syn::Token![=]>()?; - let _value: syn::LitStr = content.parse()?; - if content.peek(syn::Token![,]) { - content.parse::<syn::Token![,]>()?; - } - } - } - return Ok(ExportItem::Kotlin); - } - - Err(syn::Error::new(ident.span(), "Expected c or kotlin")) - } -} - -fn extract_arg_markers(attrs: &[syn::Attribute]) -> (Option<syn::Type>, bool) { - let mut define_ty: Option<syn::Type> = None; - let mut is_entity = false; - for attr in attrs { - let path = attr.path(); - let ident = path.segments.last().map(|s| s.ident.to_string()).unwrap_or_default(); - if ident == "define" { - if let Ok(ty) = attr.parse_args::<syn::Type>() { - define_ty = Some(ty); - } - } - if ident == "entity" { - is_entity = true; - } - } - (define_ty, is_entity) -} - -fn extract_result_type(output: &syn::ReturnType) -> anyhow::Result<(Option<String>, bool)> { - let ty = match output { - syn::ReturnType::Type(_, ty) => ty, - syn::ReturnType::Default => return Ok((None, false)), - }; - - let inner = match &**ty { - syn::Type::Path(path) => { - let last = path.path.segments.last().ok_or_else(|| anyhow::anyhow!("Invalid return type"))?; - if last.ident != "DropbearNativeResult" { - return Ok((None, false)); - } - match &last.arguments { - syn::PathArguments::AngleBracketed(args) => args.args.first().and_then(|a| match a { - syn::GenericArgument::Type(t) => Some(t.clone()), - _ => None, - }).ok_or_else(|| anyhow::anyhow!("DropbearNativeResult missing type"))?, - _ => return Ok((None, false)), - } - } - _ => return Ok((None, false)), - }; - - if is_unit_type(&inner) { - return Ok((None, false)); - } - - if let Some(opt_inner) = extract_option_inner(&inner) { - return Ok((Some(type_to_c(&opt_inner, true)), true)); - } - - Ok((Some(type_to_c(&inner, true)), false)) -} - -fn extract_option_inner(ty: &syn::Type) -> Option<syn::Type> { - if let syn::Type::Path(path) = ty { - let last = path.path.segments.last()?; - if last.ident != "Option" { - return None; - } - if let syn::PathArguments::AngleBracketed(args) = &last.arguments { - if let Some(syn::GenericArgument::Type(inner)) = args.args.first() { - return Some(inner.clone()); - } - } - } - None -} - -fn is_unit_type(ty: &syn::Type) -> bool { - matches!(ty, syn::Type::Tuple(tuple) if tuple.elems.is_empty()) -} - -fn type_to_c(ty: &syn::Type, for_output: bool) -> String { - if let syn::Type::Reference(reference) = ty { - let inner = type_to_c(&reference.elem, for_output); - let mutability = if reference.mutability.is_some() { "" } else { "const " }; - return format!("{}{}*", mutability, inner); - } - if let Some(inner) = vec_inner_type(ty) { - return array_struct_name_from_type(&inner); - } - - if let syn::Type::Path(path) = ty { - let ident = path.path.segments.last().map(|s| s.ident.to_string()).unwrap_or_else(|| "void".to_string()); - return match ident.as_str() { - "i8" => "int8_t".to_string(), - "u8" => "uint8_t".to_string(), - "i16" => "int16_t".to_string(), - "u16" => "uint16_t".to_string(), - "i32" => "int32_t".to_string(), - "u32" => "uint32_t".to_string(), - "i64" => "int64_t".to_string(), - "u64" => "uint64_t".to_string(), - "isize" => "intptr_t".to_string(), - "usize" => "size_t".to_string(), - "f32" => "float".to_string(), - "f64" => "double".to_string(), - "bool" => "bool".to_string(), - "String" => { - if for_output { - "char*".to_string() - } else { - "const char*".to_string() - } - } - _ => ident, - }; - } - - "void".to_string() -} - -fn vec_inner_type(ty: &syn::Type) -> Option<syn::Type> { - if let syn::Type::Path(path) = ty { - let last = path.path.segments.last()?; - if last.ident != "Vec" { - return None; - } - if let syn::PathArguments::AngleBracketed(args) = &last.arguments { - if let Some(syn::GenericArgument::Type(inner)) = args.args.first() { - return Some(inner.clone()); - } - } - } - None -} - -fn type_name_from_type(ty: &syn::Type) -> Option<String> { - if let syn::Type::Path(path) = ty { - return path.path.segments.last().map(|s| s.ident.to_string()); - } - None -} - -fn array_struct_name_from_type(ty: &syn::Type) -> String { - if let Some(inner) = vec_inner_type(ty) { - let inner_name = array_struct_name_from_type(&inner); - return format!("{}ArrayFfi", inner_name); - } - - let name = type_name_from_type(ty).unwrap_or_else(|| "Unknown".to_string()); - format!("{}ArrayFfi", name) -} - -fn render_header( - funcs: &[ExportedFunction], - structs: &std::collections::HashMap<String, StructDef>, - enums: &[EnumDef], -) -> String { - let mut out = String::new(); - out.push_str("#ifndef DROPBEAR_H\n"); - out.push_str("#define DROPBEAR_H\n\n"); - out.push_str("#include <stdbool.h>\n"); - out.push_str("#include <stdint.h>\n\n"); - out.push_str("#include <stddef.h>\n\n"); - - let mut emitted_arrays = std::collections::HashSet::new(); - for enm in enums { - emit_repr_c_enum(enm, &mut emitted_arrays, &mut out); - } - - let mut needed = std::collections::HashSet::new(); - for func in funcs { - if let Some(out_ty) = &func.out_type { - if is_custom_type(out_ty) { - needed.insert(out_ty.clone()); - } else if is_opaque_ptr_name(out_ty) { - needed.insert(out_ty.clone()); - } - } - for param in &func.params { - if is_opaque_ptr_name(¶m.ty) { - needed.insert(param.ty.clone()); - } - if let Some(base) = base_type_name(¶m.ty) { - if is_custom_type(&base) { - needed.insert(base); - } else if is_opaque_ptr_name(&base) { - needed.insert(base); - } - } - } - } - - let mut emitted = std::collections::HashSet::new(); - for ty in needed { - emit_structs_recursive(&ty, structs, &mut emitted, &mut out); - } - - for func in funcs { - let params = if func.params.is_empty() { - "void".to_string() - } else { - func.params.iter() - .map(|p| format!("{} {}", p.ty, p.name)) - .collect::<Vec<_>>() - .join(", ") - }; - out.push_str(&format!("int32_t {}({});\n", func.name, params)); - } - - out.push_str("\n#endif /* DROPBEAR_H */\n"); - out -} - -fn emit_repr_c_enum( - enm: &EnumDef, - emitted_arrays: &mut std::collections::HashSet<String>, - out: &mut String, -) { - let tag_name = format!("{}Tag", enm.name); - let data_name = format!("{}Data", enm.name); - let ffi_name = format!("{}Ffi", enm.name); - - for var in &enm.variants { - for field in &var.fields { - if is_array_type(&field.ty) { - emit_array_struct(&field.ty, &std::collections::HashMap::new(), emitted_arrays, out); - } - } - } - - out.push_str(&format!("typedef enum {} {{\n", tag_name)); - for (idx, var) in enm.variants.iter().enumerate() { - out.push_str(&format!(" {}_{} = {},\n", tag_name, var.name, idx)); - } - out.push_str(&format!("}} {};\n\n", tag_name)); - - for var in &enm.variants { - let struct_name = format!("{}{}", enm.name, var.name); - out.push_str(&format!("typedef struct {} {{\n", struct_name)); - for field in &var.fields { - out.push_str(&format!(" {} {};\n", field.ty, field.name)); - } - out.push_str(&format!("}} {};\n\n", struct_name)); - } - - out.push_str(&format!("typedef union {} {{\n", data_name)); - for var in &enm.variants { - let struct_name = format!("{}{}", enm.name, var.name); - out.push_str(&format!(" {} {};\n", struct_name, var.name)); - } - out.push_str(&format!("}} {};\n\n", data_name)); - - out.push_str(&format!("typedef struct {} {{\n", ffi_name)); - out.push_str(&format!(" {} tag;\n", tag_name)); - out.push_str(&format!(" {} data;\n", data_name)); - out.push_str(&format!("}} {};\n\n", ffi_name)); -} - -fn has_repr_c_enum_attr(attrs: &[syn::Attribute]) -> bool { - for attr in attrs { - let path = attr.path(); - if path.segments.last().map(|s| s.ident == "repr_c_enum").unwrap_or(false) { - return true; - } - if path.segments.iter().any(|s| s.ident == "dropbear_macro") - && path.segments.last().map(|s| s.ident == "repr_c_enum").unwrap_or(false) - { - return true; - } - } - false -} - -fn has_repr_c(attrs: &[syn::Attribute]) -> bool { - for attr in attrs { - if !attr.path().is_ident("repr") { - continue; - } - if let syn::Meta::List(list) = &attr.meta { - let tokens = list.tokens.to_string(); - if tokens.contains("C") || tokens.contains("transparent") { - return true; - } - } - } - false -} - -fn is_custom_type(ty: &str) -> bool { - if ty.ends_with('*') { - return false; - } - if is_opaque_ptr_name(ty) { - return false; - } - !is_builtin_c_type(ty) -} - -fn base_type_name(ty: &str) -> Option<String> { - let mut t = ty.trim().to_string(); - if t.starts_with("const ") { - t = t.trim_start_matches("const ").trim().to_string(); - } - if t.ends_with('*') { - t = t.trim_end_matches('*').trim().to_string(); - return Some(t); - } - None -} - -fn is_object_input(ty: &syn::Type) -> bool { - let inner = peel_reference(ty); - if is_string_type(inner) || is_primitive_type(inner) { - return false; - } - !is_define_or_entity_like(inner) -} - -fn object_input_to_c(ty: &syn::Type) -> String { - match ty { - syn::Type::Reference(reference) => { - let inner = type_to_c(&reference.elem, false); - let mutability = if reference.mutability.is_some() { "" } else { "const " }; - format!("{}{}*", mutability, inner) - } - _ => type_to_c(ty, false), - } -} - -fn is_define_or_entity_like(_ty: &syn::Type) -> bool { - false -} - -fn is_string_type(ty: &syn::Type) -> bool { - matches!(ty, syn::Type::Path(path) if path.path.segments.last().map(|s| s.ident == "String").unwrap_or(false)) -} - -fn is_primitive_type(ty: &syn::Type) -> bool { - matches!(ty, syn::Type::Path(path) if { - let ident = path.path.segments.last().map(|s| s.ident.to_string()).unwrap_or_default(); - matches!( - ident.as_str(), - "i8" | "u8" | "i16" | "u16" | "i32" | "u32" | "i64" | "u64" | - "isize" | "usize" | "f32" | "f64" | "bool" - ) - }) -} - -fn peel_reference<'a>(ty: &'a syn::Type) -> &'a syn::Type { - if let syn::Type::Reference(reference) = ty { - &reference.elem - } else { - ty - } -} - -fn is_builtin_c_type(ty: &str) -> bool { - matches!( - ty, - "int8_t" | "uint8_t" | "int16_t" | "uint16_t" | "int32_t" | "uint32_t" | - "int64_t" | "uint64_t" | "intptr_t" | "uintptr_t" | "bool" | "float" | - "double" | "char" | "char*" | "const char*" | "void*" - ) -} - -fn is_opaque_ptr_name(name: &str) -> bool { - name.ends_with("Ptr") -} - -fn emit_structs_recursive( - name: &str, - structs: &std::collections::HashMap<String, StructDef>, - emitted: &mut std::collections::HashSet<String>, - out: &mut String, -) { - if emitted.contains(name) { - return; - } - - if is_array_type(name) { - emit_array_struct(name, structs, emitted, out); - return; - } - - if is_opaque_ptr_name(name) { - out.push_str(&format!("typedef void* {};\n\n", name)); - emitted.insert(name.to_string()); - return; - } - - if let Some(def) = structs.get(name) { - for field in &def.fields { - if is_array_type(&field.ty) { - emit_array_struct(&field.ty, structs, emitted, out); - continue; - } - if is_custom_type(&field.ty) { - emit_structs_recursive(&field.ty, structs, emitted, out); - } - } - - if !def.is_repr_c { - out.push_str("// NOTE: type is not #[repr(C)] in Rust; ensure C ABI safety.\n"); - } - - out.push_str(&format!("typedef struct {} {{\n", def.name)); - for field in &def.fields { - out.push_str(&format!(" {} {};\n", field.ty, field.name)); - } - out.push_str(&format!("}} {};\n\n", def.name)); - emitted.insert(def.name.clone()); - } else { - out.push_str(&format!("typedef struct {} {};// opaque\n\n", name, name)); - emitted.insert(name.to_string()); - } -} - -fn is_array_type(ty: &str) -> bool { - ty.ends_with("ArrayFfi") -} - -fn emit_array_struct( - name: &str, - structs: &std::collections::HashMap<String, StructDef>, - emitted: &mut std::collections::HashSet<String>, - out: &mut String, -) { - if emitted.contains(name) { - return; - } - let elem = name.trim_end_matches("ArrayFfi"); - - if is_array_type(elem) { - emit_array_struct(elem, structs, emitted, out); - } - - if is_builtin_rust_primitive(elem) { - let c_elem = map_primitive_name(elem); - if !emitted.contains(elem) { - emitted.insert(elem.to_string()); - } - out.push_str(&format!("typedef struct {} {{\n", name)); - out.push_str(&format!(" const {}* ptr;\n", c_elem)); - out.push_str(" size_t len;\n"); - out.push_str(&format!("}} {};\n\n", name)); - emitted.insert(name.to_string()); - return; - } - - if !emitted.contains(elem) { - if structs.contains_key(elem) { - emit_structs_recursive(elem, structs, emitted, out); - } else { - out.push_str(&format!("typedef struct {} {};// opaque\n\n", elem, elem)); - emitted.insert(elem.to_string()); - } - } - - out.push_str(&format!("typedef struct {} {{\n", name)); - out.push_str(&format!(" const {}* ptr;\n", elem)); - out.push_str(" size_t len;\n"); - out.push_str(&format!("}} {};\n\n", name)); - emitted.insert(name.to_string()); -} - -fn is_builtin_rust_primitive(name: &str) -> bool { - matches!( - name, - "i8" | "u8" | "i16" | "u16" | "i32" | "u32" | "i64" | "u64" | - "isize" | "usize" | "f32" | "f64" | "bool" - ) -} - -fn map_primitive_name(name: &str) -> &'static str { - match name { - "i8" => "int8_t", - "u8" => "uint8_t", - "i16" => "int16_t", - "u16" => "uint16_t", - "i32" => "int32_t", - "u32" => "uint32_t", - "i64" => "int64_t", - "u64" => "uint64_t", - "isize" => "intptr_t", - "usize" => "size_t", - "f32" => "float", - "f64" => "double", - "bool" => "bool", - _ => "void", - } -} +} @@ -1,8 +1,12 @@ pub mod texture; pub mod model; +use jni::JNIEnv; +use jni::objects::JObject; use dropbear_engine::asset::AssetKind; use crate::ptr::{AssetRegistryPtr, AssetRegistryUnwrapped}; +use crate::scripting::jni::utils::{FromJObject}; +use crate::scripting::native::DropbearNativeError; use crate::scripting::result::DropbearNativeResult; #[dropbear_macro::export( @@ -34,4 +38,21 @@ fn dropbear_asset_get_asset( } } } +} + +impl FromJObject for AssetKind { + fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> + where + Self: Sized + { + let ordinal = env + .call_method(obj, "ordinal", "()I", &[])? + .i()?; + + match ordinal { + 0 => Ok(AssetKind::Texture), + 1 => Ok(AssetKind::Model), + _ => Err(DropbearNativeError::InvalidEnumOrdinal) + } + } } @@ -1,3 +1,6 @@ +use jni::JNIEnv; +use jni::objects::{JObject, JValue}; +use jni::sys::{jdouble, jint}; use crate::scripting::native::DropbearNativeError; use crate::scripting::result::DropbearNativeResult; use crate::types::{NQuaternion, NVector2, NVector3, NVector4}; @@ -5,6 +8,7 @@ use dropbear_engine::asset::Handle; use dropbear_engine::model::{Animation, AnimationChannel, AnimationInterpolation, ChannelValues, Material, Mesh, ModelVertex, Node, NodeTransform, Skin}; use dropbear_engine::texture::Texture; use crate::ptr::{AssetRegistryPtr, AssetRegistryUnwrapped}; +use crate::scripting::jni::utils::ToJObject; #[repr(C)] #[derive(Clone, Debug)] @@ -19,6 +23,43 @@ pub struct NModelVertex { pub weights0: NVector4, } +impl ToJObject for NModelVertex { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + let class = env.find_class("com/dropbear/asset/model/ModelVertex") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; + + let position = self.position.to_jobject(env)?; + let normal = self.normal.to_jobject(env)?; + let tangent = self.tangent.to_jobject(env)?; + let tex_coords0 = self.tex_coords0.to_jobject(env)?; + let tex_coords1 = self.tex_coords1.to_jobject(env)?; + let colour0 = self.colour0.to_jobject(env)?; + let joints0 = self.joints0.as_slice().to_jobject(env)?; + let weights0 = self.weights0.to_jobject(env)?; + + let args = [ + JValue::Object(&position), + JValue::Object(&normal), + JValue::Object(&tangent), + JValue::Object(&tex_coords0), + JValue::Object(&tex_coords1), + JValue::Object(&colour0), + JValue::Object(&joints0), + JValue::Object(&weights0), + ]; + + let obj = env + .new_object( + &class, + "(Lcom/dropbear/math/Vector3f;Lcom/dropbear/math/Vector3f;Lcom/dropbear/math/Vector4f;Lcom/dropbear/math/Vector2f;Lcom/dropbear/math/Vector2f;Lcom/dropbear/math/Vector4f;[ILcom/dropbear/math/Vector4f;)V", + &args, + ) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; + + Ok(obj) + } +} + #[repr(C)] #[derive(Clone, Debug)] pub struct NMesh { @@ -28,6 +69,34 @@ pub struct NMesh { pub vertices: Vec<NModelVertex>, } +impl ToJObject for NMesh { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + let class = env.find_class("com/dropbear/asset/model/Mesh") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; + + let name = env.new_string(&self.name) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; + let vertices = self.vertices.to_jobject(env)?; + + let args = [ + JValue::Object(&name), + JValue::Int(self.num_elements), + JValue::Int(self.material_index), + JValue::Object(&vertices), + ]; + + let obj = env + .new_object( + &class, + "(Ljava/lang/String;IILjava/util/List;)V", + &args, + ) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; + + Ok(obj) + } +} + #[repr(C)] #[derive(Clone, Debug)] pub struct NMaterial { @@ -48,6 +117,62 @@ pub struct NMaterial { pub occlusion_texture: Option<u64>, } +impl ToJObject for NMaterial { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + let class = env.find_class("com/dropbear/asset/model/Material") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; + + let name = env.new_string(&self.name) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; + let diffuse_texture = new_texture(env, self.diffuse_texture)?; + let normal_texture = new_texture(env, self.normal_texture)?; + let tint = self.tint.to_jobject(env)?; + let emissive_factor = self.emissive_factor.to_jobject(env)?; + let uv_tiling = self.uv_tiling.to_jobject(env)?; + let alpha_cutoff = self.alpha_cutoff.to_jobject(env)?; + let emissive_texture = match self.emissive_texture { + Some(id) => new_texture(env, id)?, + None => JObject::null(), + }; + let metallic_roughness_texture = match self.metallic_roughness_texture { + Some(id) => new_texture(env, id)?, + None => JObject::null(), + }; + let occlusion_texture = match self.occlusion_texture { + Some(id) => new_texture(env, id)?, + None => JObject::null(), + }; + + let args = [ + JValue::Object(&name), + JValue::Object(&diffuse_texture), + JValue::Object(&normal_texture), + JValue::Object(&tint), + JValue::Object(&emissive_factor), + JValue::Double(self.metallic_factor as f64), + JValue::Double(self.roughness_factor as f64), + JValue::Object(&alpha_cutoff), + JValue::Bool(if self.double_sided { 1 } else { 0 }), + JValue::Double(self.occlusion_strength as f64), + JValue::Double(self.normal_scale as f64), + JValue::Object(&uv_tiling), + JValue::Object(&emissive_texture), + JValue::Object(&metallic_roughness_texture), + JValue::Object(&occlusion_texture), + ]; + + let obj = env + .new_object( + &class, + "(Ljava/lang/String;Lcom/dropbear/asset/Texture;Lcom/dropbear/asset/Texture;Lcom/dropbear/math/Vector4d;Lcom/dropbear/math/Vector3d;DDLjava/lang/Double;ZDDLcom/dropbear/math/Vector2d;Lcom/dropbear/asset/Texture;Lcom/dropbear/asset/Texture;Lcom/dropbear/asset/Texture;)V", + &args, + ) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; + + Ok(obj) + } +} + #[repr(C)] #[derive(Clone, Debug)] pub struct NNodeTransform { @@ -56,6 +181,33 @@ pub struct NNodeTransform { pub scale: NVector3, } +impl ToJObject for NNodeTransform { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + let class = env.find_class("com/dropbear/asset/model/NodeTransform") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; + + let translation = self.translation.to_jobject(env)?; + let rotation = self.rotation.to_jobject(env)?; + let scale = self.scale.to_jobject(env)?; + + let args = [ + JValue::Object(&translation), + JValue::Object(&rotation), + JValue::Object(&scale), + ]; + + let obj = env + .new_object( + &class, + "(Lcom/dropbear/math/Vector3d;Lcom/dropbear/math/Quaterniond;Lcom/dropbear/math/Vector3d;)V", + &args, + ) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; + + Ok(obj) + } +} + #[repr(C)] #[derive(Clone, Debug)] pub struct NNode { @@ -65,6 +217,36 @@ pub struct NNode { pub transform: NNodeTransform, } +impl ToJObject for NNode { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + let class = env.find_class("com/dropbear/asset/model/Node") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; + + let name = env.new_string(&self.name) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; + let parent = self.parent.to_jobject(env)?; + let children = self.children.as_slice().to_jobject(env)?; + let transform = self.transform.to_jobject(env)?; + + let args = [ + JValue::Object(&name), + JValue::Object(&parent), + JValue::Object(&children), + JValue::Object(&transform), + ]; + + let obj = env + .new_object( + &class, + "(Ljava/lang/String;Ljava/lang/Integer;Ljava/util/List;Lcom/dropbear/asset/model/NodeTransform;)V", + &args, + ) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; + + Ok(obj) + } +} + #[repr(C)] #[derive(Clone, Debug)] pub struct NSkin { @@ -74,6 +256,36 @@ pub struct NSkin { pub skeleton_root: Option<i32>, } +impl ToJObject for NSkin { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + let class = env.find_class("com/dropbear/asset/model/Skin") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; + + let name = env.new_string(&self.name) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; + let joints = self.joints.as_slice().to_jobject(env)?; + let inverse_bind_matrices = self.inverse_bind_matrices.as_slice().to_jobject(env)?; + let skeleton_root = self.skeleton_root.to_jobject(env)?; + + let args = [ + JValue::Object(&name), + JValue::Object(&joints), + JValue::Object(&inverse_bind_matrices), + JValue::Object(&skeleton_root), + ]; + + let obj = env + .new_object( + &class, + "(Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/lang/Integer;)V", + &args, + ) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; + + Ok(obj) + } +} + #[repr(C)] #[derive(Clone, Debug)] pub struct NAnimation { @@ -82,6 +294,33 @@ pub struct NAnimation { pub duration: f32, } +impl ToJObject for NAnimation { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + let class = env.find_class("com/dropbear/asset/model/Animation") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; + + let name = env.new_string(&self.name) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; + let channels = self.channels.to_jobject(env)?; + + let args = [ + JValue::Object(&name), + JValue::Object(&channels), + JValue::Double(self.duration as f64), + ]; + + let obj = env + .new_object( + &class, + "(Ljava/lang/String;Ljava/util/List;D)V", + &args, + ) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; + + Ok(obj) + } +} + #[repr(C)] #[derive(Clone, Debug)] pub struct NAnimationChannel { @@ -91,22 +330,127 @@ pub struct NAnimationChannel { pub interpolation: NAnimationInterpolation, } +impl ToJObject for NAnimationChannel { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + let class = env.find_class("com/dropbear/asset/model/AnimationChannel") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; + + let times = self.times.as_slice().to_jobject(env)?; + let values = self.values.to_jobject(env)?; + let interpolation = self.interpolation.to_jobject(env)?; + + let args = [ + JValue::Int(self.target_node), + JValue::Object(×), + JValue::Object(&values), + JValue::Object(&interpolation), + ]; + + let obj = env + .new_object( + &class, + "(I[DLcom/dropbear/asset/model/ChannelValues;Lcom/dropbear/asset/model/AnimationInterpolation;)V", + &args, + ) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; + + Ok(obj) + } +} + #[repr(C)] #[derive(Clone, Debug)] +#[dropbear_macro::repr_c_enum] pub enum NAnimationInterpolation { Linear, Step, CubicSpline, } +impl ToJObject for NAnimationInterpolation { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + let class = env + .find_class("com/dropbear/asset/model/AnimationInterpolation") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; + + let field_name = match self { + NAnimationInterpolation::Linear => "LINEAR", + NAnimationInterpolation::Step => "STEP", + NAnimationInterpolation::CubicSpline => "CUBIC_SPLINE", + }; + + let value = env + .get_static_field( + class, + field_name, + "Lcom/dropbear/asset/model/AnimationInterpolation;", + ) + .map_err(|_| DropbearNativeError::JNIFailedToGetField)? + .l() + .map_err(|_| DropbearNativeError::JNIUnwrapFailed)?; + + Ok(value) + } +} + #[repr(C)] #[derive(Clone, Debug)] +#[dropbear_macro::repr_c_enum] pub enum NChannelValues { Translations { values: Vec<NVector3> }, Rotations { values: Vec<NQuaternion> }, Scales { values: Vec<NVector3> }, } +impl ToJObject for NChannelValues { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + match self { + NChannelValues::Translations { values } => { + let class = env + .find_class("com/dropbear/asset/model/ChannelValues$Translations") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; + let list = values.to_jobject(env)?; + let obj = env + .new_object(&class, "(Ljava/util/List;)V", &[JValue::Object(&list)]) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; + Ok(obj) + } + NChannelValues::Rotations { values } => { + let class = env + .find_class("com/dropbear/asset/model/ChannelValues$Rotations") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; + let list = values.to_jobject(env)?; + let obj = env + .new_object(&class, "(Ljava/util/List;)V", &[JValue::Object(&list)]) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; + Ok(obj) + } + NChannelValues::Scales { values } => { + let class = env + .find_class("com/dropbear/asset/model/ChannelValues$Scales") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; + let list = values.to_jobject(env)?; + let obj = env + .new_object(&class, "(Ljava/util/List;)V", &[JValue::Object(&list)]) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; + Ok(obj) + } + } + } +} + +fn new_texture<'a>(env: &mut JNIEnv<'a>, texture_id: u64) -> DropbearNativeResult<JObject<'a>> { + let class = env.find_class("com/dropbear/asset/Texture") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; + + env.new_object( + &class, + "(J)V", + &[JValue::Long(texture_id as i64)], + ) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject) +} + fn texture_handle_id( registry: &dropbear_engine::asset::AssetRegistry, texture: &Texture, @@ -1,83 +1,48 @@ -pub mod shared { - use dropbear_engine::asset::{AssetHandle, AssetRegistry}; - use crate::scripting::native::DropbearNativeError; - use crate::scripting::result::DropbearNativeResult; +use dropbear_engine::asset::Handle; +use crate::ptr::{AssetRegistryPtr, AssetRegistryUnwrapped}; +use crate::scripting::native::DropbearNativeError; +use crate::scripting::result::DropbearNativeResult; - pub fn get_texture_name( - asset_registry: &AssetRegistry, - handle: u64, - ) -> DropbearNativeResult<String> { - let texture = asset_registry - .get_material(AssetHandle::new(handle)) - .ok_or_else(|| DropbearNativeError::NoSuchHandle)?; - - Ok(texture.name.clone()) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.asset.TextureNative", func = "getLabel"), + c(name = "dropbear_asset_texture_get_label") +)] +fn get_texture_label( + #[dropbear_macro::define(AssetRegistryPtr)] + asset_manager: &AssetRegistryUnwrapped, + texture_handle: u64, +) -> DropbearNativeResult<Option<String>> { + Ok(asset_manager.read().get_label_from_texture_handle(Handle::new(texture_handle))) } -pub mod jni { - #![allow(non_snake_case)] - use jni::JNIEnv; - use jni::sys::{jlong, jstring}; - use dropbear_engine::asset::AssetRegistry; - use jni::objects::JClass; - use crate::asset::texture::shared::get_texture_name; - use crate::scripting::native::DropbearNativeError; - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_asset_TextureHandleNative_getTextureName( - env: JNIEnv, - _class: JClass, - asset_registry_ptr: jlong, - handle: jlong, - ) -> jstring { - let asset_registry = crate::convert_ptr!(asset_registry_ptr => AssetRegistry); - let result = get_texture_name(asset_registry, handle as u64); - match result { - Ok(name) => { - let output = env.new_string(name).map_err(|_| DropbearNativeError::JNIFailedToCreateObject); - match output { - Ok(jstr) => jstr.into_raw(), - Err(e) => { - crate::ffi_error_return!("[ERROR] Failed to create Java string: {}", e) - } - } - } - Err(e) => { - crate::ffi_error_return!("[ERROR] {}", e) - } - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.asset.TextureNative", func = "getWidth"), + c(name = "dropbear_asset_texture_get_width") +)] +fn get_texture_width( + #[dropbear_macro::define(AssetRegistryPtr)] + asset_manager: &AssetRegistryUnwrapped, + texture_handle: u64, +) -> DropbearNativeResult<u32> { + asset_manager + .read() + .get_texture(Handle::new(texture_handle)) + .map(|v| v.size.width) + .ok_or(DropbearNativeError::AssetNotFound) } -#[dropbear_macro::impl_c_api] -pub mod native { - use std::ffi::CString; - use crate::ptr::AssetRegistryPtr; - use crate::scripting::native::DropbearNativeError; - use crate::scripting::result::DropbearNativeResult; - use std::ffi::c_char; - use dropbear_engine::asset::AssetRegistry; - use crate::asset::texture::shared::get_texture_name; - - pub fn dropbear_get_texture_name( - asset_registry_ptr: AssetRegistryPtr, - handle: u64, - ) -> DropbearNativeResult<*mut c_char> { - let asset_registry = crate::convert_ptr!(asset_registry_ptr => AssetRegistry); - - let result = get_texture_name(asset_registry, handle) - .map(|name| { - match CString::new(name) { - Ok(c_str) => { - Ok(c_str.into_raw()) - }, - Err(_) => { - Err(DropbearNativeError::CStringError) - } - } - })?; - - result - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.asset.TextureNative", func = "getHeight"), + c(name = "dropbear_asset_texture_get_height") +)] +fn get_texture_height( + #[dropbear_macro::define(AssetRegistryPtr)] + asset_manager: &AssetRegistryUnwrapped, + texture_handle: u64, +) -> DropbearNativeResult<u32> { + asset_manager + .read() + .get_texture(Handle::new(texture_handle)) + .map(|v| v.size.height) + .ok_or(DropbearNativeError::AssetNotFound) } @@ -5,6 +5,9 @@ use dropbear_engine::camera::{Camera, CameraBuilder, CameraSettings}; use dropbear_macro::SerializableComponent; use glam::DVec3; use serde::{Deserialize, Serialize}; +use crate::ptr::WorldPtr; +use crate::scripting::result::DropbearNativeResult; +use crate::types::NVector3; #[derive(Debug, Clone, Serialize, Deserialize, SerializableComponent)] pub struct CameraComponent { @@ -118,737 +121,396 @@ pub enum CameraAction { } pub mod shared { - use dropbear_engine::camera::Camera; - pub fn camera_exists_for_entity(world: &hecs::World, entity: hecs::Entity) -> bool { - world.get::<&Camera>(entity).is_ok() + world.get::<&dropbear_engine::camera::Camera>(entity).is_ok() } } -pub mod jni { - #![allow(non_snake_case)] - - use glam::DVec3; - use jni::JNIEnv; - use jni::objects::{JClass, JObject}; - use jni::sys::{jboolean, jdouble, jlong, jobject}; - use dropbear_engine::camera::Camera; - use crate::convert_jlong_to_entity; - use crate::scripting::jni::utils::{FromJObject, ToJObject}; - use crate::types::NVector3; - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_cameraExistsForEntity( - _env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jboolean { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - if world.get::<&Camera>(entity).is_ok() { - true.into() - } else { - false.into() - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_getCameraEye( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jobject { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - if let Ok(camera) = world.get::<&Camera>(entity) { - let eye: NVector3 = NVector3::from(camera.eye); - return match eye.to_jobject(&mut env) { - Ok(val) => val.into_raw(), - Err(_) => std::ptr::null_mut() - }; - } else { - let _ = env.throw_new("java/lang/IllegalArgumentException", format!("Entity {} missing Camera", entity_id)); - std::ptr::null_mut() - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_setCameraEye( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - eye_obj: JObject, - ) { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - let new_eye = match NVector3::from_jobject(&mut env, &eye_obj) { - Ok(v) => v, - Err(e) => { - let _ = env.throw_new("java/lang/IllegalArgumentException", format!("Invalid Vector3d: {:?}", e)); - return; - } - }; - if let Ok(mut camera) = world.get::<&mut Camera>(entity) { - camera.eye = DVec3::from(new_eye); - } else { - let _ = env.throw_new("java/lang/IllegalArgumentException", "Entity missing Camera component"); - } - } - - // TARGET - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_getCameraTarget( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jobject { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - if let Ok(camera) = world.get::<&Camera>(entity) { - let target: NVector3 = NVector3::from(camera.target); - return match target.to_jobject(&mut env) { - Ok(val) => val.into_raw(), - Err(_) => std::ptr::null_mut() - }; - } else { - let _ = env.throw_new("java/lang/IllegalArgumentException", "Entity missing Camera component"); - std::ptr::null_mut() - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_setCameraTarget( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - target_obj: JObject, - ) { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - let new_target = match NVector3::from_jobject(&mut env, &target_obj) { - Ok(v) => v, - Err(_) => return, - }; - if let Ok(mut camera) = world.get::<&mut Camera>(entity) { - camera.target = DVec3::from(new_target); - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_getCameraUp( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jobject { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - if let Ok(camera) = world.get::<&Camera>(entity) { - let up = NVector3::from(camera.up); - return match up.to_jobject(&mut env) { - Ok(val) => val.into_raw(), - Err(_) => std::ptr::null_mut() - }; - } else { - let _ = env.throw_new("java/lang/IllegalArgumentException", "Entity missing Camera component"); - std::ptr::null_mut() - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_setCameraUp( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - up_obj: JObject, - ) { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - let new_up = match NVector3::from_jobject(&mut env, &up_obj) { - Ok(v) => v, - Err(_) => return, - }; - if let Ok(mut camera) = world.get::<&mut Camera>(entity) { - camera.up = DVec3::from(new_up); - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_getCameraAspect( - _env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jdouble { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - if let Ok(camera) = world.get::<&Camera>(entity) { - camera.aspect - } else { - 0.0 - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_getCameraFovY( - _env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jdouble { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - if let Ok(camera) = world.get::<&Camera>(entity) { - camera.settings.fov_y - } else { - 0.0 - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_setCameraFovY( - _env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - value: jdouble, - ) { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - if let Ok(mut camera) = world.get::<&mut Camera>(entity) { - camera.settings.fov_y = value; - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_getCameraZNear( - _env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jdouble { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - if let Ok(camera) = world.get::<&Camera>(entity) { - camera.znear - } else { - 0.0 - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_setCameraZNear( - _env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - value: jdouble, - ) { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - if let Ok(mut camera) = world.get::<&mut Camera>(entity) { - camera.znear = value; - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_getCameraZFar( - _env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jdouble { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - if let Ok(camera) = world.get::<&Camera>(entity) { - camera.zfar - } else { - 0.0 - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_setCameraZFar( - _env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - value: jdouble, - ) { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - if let Ok(mut camera) = world.get::<&mut Camera>(entity) { - camera.zfar = value; - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_getCameraYaw( - _env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jdouble { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - if let Ok(camera) = world.get::<&Camera>(entity) { - camera.yaw - } else { - 0.0 - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_setCameraYaw( - _env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - value: jdouble, - ) { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - if let Ok(mut camera) = world.get::<&mut Camera>(entity) { - camera.yaw = value; - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_getCameraPitch( - _env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jdouble { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - if let Ok(camera) = world.get::<&Camera>(entity) { - camera.pitch - } else { - 0.0 - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_setCameraPitch( - _env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - value: jdouble, - ) { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - if let Ok(mut camera) = world.get::<&mut Camera>(entity) { - camera.pitch = value; - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_getCameraSpeed( - _env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jdouble { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - if let Ok(camera) = world.get::<&Camera>(entity) { - camera.settings.speed - } else { - 0.0 - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_setCameraSpeed( - _env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - value: jdouble, - ) { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - if let Ok(mut camera) = world.get::<&mut Camera>(entity) { - camera.settings.speed = value; - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_getCameraSensitivity( - _env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jdouble { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - if let Ok(camera) = world.get::<&Camera>(entity) { - camera.settings.sensitivity - } else { - 0.0 - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CameraNative_setCameraSensitivity( - _env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - value: jdouble, - ) { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let entity = convert_jlong_to_entity!(entity_id); - if let Ok(mut camera) = world.get::<&mut Camera>(entity) { - camera.settings.sensitivity = value; - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "cameraExistsForEntity"), + c +)] +fn exists_for_entity( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, +) -> DropbearNativeResult<bool> { + Ok(shared::camera_exists_for_entity(world, entity)) } -#[dropbear_macro::impl_c_api] -pub mod native { - use crate::ptr::WorldPtr; - use crate::convert_ptr; - use crate::scripting::native::{DropbearNativeError}; - use hecs::Entity; - use glam::DVec3; - use dropbear_engine::camera::Camera; - use crate::scripting::result::DropbearNativeResult; - use crate::types::NVector3; - - pub fn dropbear_camera_exists_for_entity( - world_ptr: WorldPtr, - entity_id: u64, - ) -> DropbearNativeResult<bool> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if world.get::<&Camera>(entity).is_ok() { - DropbearNativeResult::Ok(true) - } else { - DropbearNativeResult::Ok(false) - } - } - - pub fn dropbear_get_camera_eye( - world_ptr: WorldPtr, - entity_id: u64, - ) -> DropbearNativeResult<NVector3> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if let Ok(camera) = world.get::<&Camera>(entity) { - DropbearNativeResult::Ok(NVector3::from(camera.eye)) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "getCameraEye"), + c +)] +fn get_eye( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, +) -> DropbearNativeResult<NVector3> { + match world.get::<&Camera>(entity) { + Ok(camera) => Ok(camera.eye.into()), + Err(e) => Err(e.into()), } +} - pub fn dropbear_set_camera_eye( - world_ptr: WorldPtr, - entity_id: u64, - value: NVector3, - ) -> DropbearNativeResult<()> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if let Ok(mut camera) = world.get::<&mut Camera>(entity) { - camera.eye = DVec3::from(value); - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "setCameraEye"), + c +)] +fn set_eye( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, + eye: &NVector3, +) -> DropbearNativeResult<()> { + match world.get::<&mut Camera>(entity) { + Ok(mut camera) => { + camera.eye = (*eye).into(); + Ok(()) + }, + Err(e) => Err(e.into()), } +} - pub fn dropbear_get_camera_target( - world_ptr: WorldPtr, - entity_id: u64, - ) -> DropbearNativeResult<NVector3> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if let Ok(camera) = world.get::<&Camera>(entity) { - DropbearNativeResult::Ok(NVector3::from(camera.target)) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "getCameraTarget"), + c +)] +fn get_target( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, +) -> DropbearNativeResult<NVector3> { + match world.get::<&Camera>(entity) { + Ok(camera) => Ok(camera.target.into()), + Err(e) => Err(e.into()), } +} - pub fn dropbear_set_camera_target( - world_ptr: WorldPtr, - entity_id: u64, - value: NVector3, - ) -> DropbearNativeResult<()> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if let Ok(mut camera) = world.get::<&mut Camera>(entity) { - camera.target = DVec3::from(value); - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "setCameraTarget"), + c +)] +fn set_target( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, + target: &NVector3, +) -> DropbearNativeResult<()> { + match world.get::<&mut Camera>(entity) { + Ok(mut camera) => { + camera.target = target.into(); + Ok(()) + }, + Err(e) => Err(e.into()), } +} - pub fn dropbear_get_camera_up( - world_ptr: WorldPtr, - entity_id: u64, - ) -> DropbearNativeResult<NVector3> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if let Ok(camera) = world.get::<&Camera>(entity) { - DropbearNativeResult::Ok(NVector3::from(camera.up)) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "getCameraUp"), + c +)] +fn get_up( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, +) -> DropbearNativeResult<NVector3> { + match world.get::<&Camera>(entity) { + Ok(camera) => Ok(camera.up.into()), + Err(e) => Err(e.into()), } +} - pub fn dropbear_set_camera_up( - world_ptr: WorldPtr, - entity_id: u64, - value: NVector3, - ) -> DropbearNativeResult<()> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if let Ok(mut camera) = world.get::<&mut Camera>(entity) { - camera.up = DVec3::from(value); +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "setCameraUp"), + c +)] +fn set_up( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, + up: &NVector3, +) -> DropbearNativeResult<()> { + match world.get::<&mut Camera>(entity) { + Ok(mut camera) => { + camera.up = up.into(); Ok(()) - } else { - Err(DropbearNativeError::NoSuchComponent) - } + }, + Err(e) => Err(e.into()), } +} - pub fn dropbear_get_camera_aspect( - world_ptr: WorldPtr, - entity_id: u64, - ) -> DropbearNativeResult<f64> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if let Ok(camera) = world.get::<&Camera>(entity) { - DropbearNativeResult::Ok(camera.aspect) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "getCameraAspect"), + c +)] +fn get_aspect( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, +) -> DropbearNativeResult<f64> { + match world.get::<&Camera>(entity) { + Ok(camera) => Ok(camera.aspect.into()), + Err(e) => Err(e.into()), } +} - pub fn dropbear_get_camera_fov_y( - world_ptr: WorldPtr, - entity_id: u64, - ) -> DropbearNativeResult<f64> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if let Ok(camera) = world.get::<&Camera>(entity) { - DropbearNativeResult::Ok(camera.settings.fov_y) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "getCameraFovY"), + c +)] +fn get_fovy( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, +) -> DropbearNativeResult<f64> { + match world.get::<&Camera>(entity) { + Ok(camera) => Ok(camera.settings.fov_y.into()), + Err(e) => Err(e.into()), } +} - pub fn dropbear_set_camera_fov_y( - world_ptr: WorldPtr, - entity_id: u64, - value: f64, - ) -> DropbearNativeResult<()> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if let Ok(mut camera) = world.get::<&mut Camera>(entity) { - camera.settings.fov_y = value; - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "setCameraFovY"), + c +)] +fn set_fovy( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, + fovy: f64, +) -> DropbearNativeResult<()> { + match world.get::<&mut Camera>(entity) { + Ok(mut camera) => { + camera.settings.fov_y = fovy.into(); + Ok(()) + }, + Err(e) => Err(e.into()), } +} - pub fn dropbear_get_camera_znear( - world_ptr: WorldPtr, - entity_id: u64, - ) -> DropbearNativeResult<f64> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if let Ok(camera) = world.get::<&Camera>(entity) { - DropbearNativeResult::Ok(camera.znear) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "getCameraZNear"), + c +)] +fn get_znear( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, +) -> DropbearNativeResult<f64> { + match world.get::<&Camera>(entity) { + Ok(camera) => Ok(camera.znear.into()), + Err(e) => Err(e.into()), } +} - pub fn dropbear_set_camera_znear( - world_ptr: WorldPtr, - entity_id: u64, - value: f64, - ) -> DropbearNativeResult<()> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if let Ok(mut camera) = world.get::<&mut Camera>(entity) { - camera.znear = value; - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "setCameraZNear"), + c +)] +fn set_znear( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, + znear: f64, +) -> DropbearNativeResult<()> { + match world.get::<&mut Camera>(entity) { + Ok(mut camera) => { + camera.znear = znear.into(); + Ok(()) + }, + Err(e) => Err(e.into()), } +} - pub fn dropbear_get_camera_zfar( - world_ptr: WorldPtr, - entity_id: u64, - ) -> DropbearNativeResult<f64> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if let Ok(camera) = world.get::<&Camera>(entity) { - DropbearNativeResult::Ok(camera.zfar) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "getCameraZFar"), + c +)] +fn get_zfar( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, +) -> DropbearNativeResult<f64> { + match world.get::<&Camera>(entity) { + Ok(camera) => Ok(camera.zfar.into()), + Err(e) => Err(e.into()), } +} - pub fn dropbear_set_camera_zfar( - world_ptr: WorldPtr, - entity_id: u64, - value: f64, - ) -> DropbearNativeResult<()> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if let Ok(mut camera) = world.get::<&mut Camera>(entity) { - camera.zfar = value; - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "setCameraZFar"), + c +)] +fn set_zfar( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, + zfar: f64, +) -> DropbearNativeResult<()> { + match world.get::<&mut Camera>(entity) { + Ok(mut camera) => { + camera.zfar = zfar.into(); + Ok(()) + }, + Err(e) => Err(e.into()), } +} - pub fn dropbear_get_camera_yaw( - world_ptr: WorldPtr, - entity_id: u64, - ) -> DropbearNativeResult<f64> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if let Ok(camera) = world.get::<&Camera>(entity) { - DropbearNativeResult::Ok(camera.yaw) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "getCameraYaw"), + c +)] +fn get_yaw( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, +) -> DropbearNativeResult<f64> { + match world.get::<&Camera>(entity) { + Ok(camera) => Ok(camera.yaw.into()), + Err(e) => Err(e.into()), } +} - pub fn dropbear_set_camera_yaw( - world_ptr: WorldPtr, - entity_id: u64, - value: f64, - ) -> DropbearNativeResult<()> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if let Ok(mut camera) = world.get::<&mut Camera>(entity) { - camera.yaw = value; - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "setCameraYaw"), + c +)] +fn set_yaw( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, + yaw: f64, +) -> DropbearNativeResult<()> { + match world.get::<&mut Camera>(entity) { + Ok(mut camera) => { + camera.yaw = yaw.into(); + Ok(()) + }, + Err(e) => Err(e.into()), } +} - pub fn dropbear_get_camera_pitch( - world_ptr: WorldPtr, - entity_id: u64, - ) -> DropbearNativeResult<f64> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if let Ok(camera) = world.get::<&Camera>(entity) { - DropbearNativeResult::Ok(camera.pitch) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "getCameraPitch"), + c +)] +fn get_pitch( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, +) -> DropbearNativeResult<f64> { + match world.get::<&Camera>(entity) { + Ok(camera) => Ok(camera.pitch.into()), + Err(e) => Err(e.into()), } +} - pub fn dropbear_set_camera_pitch( - world_ptr: WorldPtr, - entity_id: u64, - value: f64, - ) -> DropbearNativeResult<()> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if let Ok(mut camera) = world.get::<&mut Camera>(entity) { - camera.pitch = value; - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "setCameraPitch"), + c +)] +fn set_pitch( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, + pitch: f64, +) -> DropbearNativeResult<()> { + match world.get::<&mut Camera>(entity) { + Ok(mut camera) => { + camera.pitch = pitch.into(); + Ok(()) + }, + Err(e) => Err(e.into()), } +} - pub fn dropbear_get_camera_speed( - world_ptr: WorldPtr, - entity_id: u64, - ) -> DropbearNativeResult<f64> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if let Ok(camera) = world.get::<&Camera>(entity) { - DropbearNativeResult::Ok(camera.settings.speed) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "getCameraSpeed"), + c +)] +fn get_speed( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, +) -> DropbearNativeResult<f64> { + match world.get::<&Camera>(entity) { + Ok(camera) => Ok(camera.settings.speed.into()), + Err(e) => Err(e.into()), } +} - pub fn dropbear_set_camera_speed( - world_ptr: WorldPtr, - entity_id: u64, - value: f64, - ) -> DropbearNativeResult<()> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if let Ok(mut camera) = world.get::<&mut Camera>(entity) { - camera.settings.speed = value; - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "setCameraSpeed"), + c +)] +fn set_speed( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, + speed: f64, +) -> DropbearNativeResult<()> { + match world.get::<&mut Camera>(entity) { + Ok(mut camera) => { + camera.settings.speed = speed.into(); + Ok(()) + }, + Err(e) => Err(e.into()), } +} - pub fn dropbear_get_camera_sensitivity( - world_ptr: WorldPtr, - entity_id: u64, - ) -> DropbearNativeResult<f64> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if let Ok(camera) = world.get::<&Camera>(entity) { - DropbearNativeResult::Ok(camera.settings.sensitivity) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "getCameraSensitivity"), + c +)] +fn get_sensitivity( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, +) -> DropbearNativeResult<f64> { + match world.get::<&Camera>(entity) { + Ok(camera) => Ok(camera.settings.sensitivity.into()), + Err(e) => Err(e.into()), } +} - pub fn dropbear_set_camera_sensitivity( - world_ptr: WorldPtr, - entity_id: u64, - value: f64, - ) -> DropbearNativeResult<()> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if let Ok(mut camera) = world.get::<&mut Camera>(entity) { - camera.settings.sensitivity = value; - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CameraNative", func = "setCameraSensitivity"), + c +)] +fn set_sensitivity( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropebear_macro::entity] + entity: hecs::Entity, + sensitivity: f64, +) -> DropbearNativeResult<()> { + match world.get::<&mut Camera>(entity) { + Ok(mut camera) => { + camera.settings.sensitivity = sensitivity.into(); + Ok(()) + }, + Err(e) => Err(e.into()), } -} +} @@ -1,86 +0,0 @@ -//! Component helper macros. - -/// Get a component and execute a closure if it exists -/// -/// # Usage -/// ``` -/// use eucalyptus_core::with_component; -/// -/// use eucalyptus_core::scene::SceneEntity; -/// -/// struct Transform { -/// position: [f32; 3], -/// } -/// -/// let scene_entity = SceneEntity::default(); -/// -/// with_component!(scene_entity, Transform, /*mut*/ |transform| { -/// transform.position.x += 1.0; -/// }); -#[macro_export] -macro_rules! with_component { - // immutable - ($entity:expr, $comp_type:ty, $closure:expr) => { - $crate::traits::SerializableComponent:: - if let Some(comp) = $entity.as_any().downcast_ref::<$comp_type>() { - $closure(comp) - } - }; - - // mutable - ($entity:expr, $comp_type:ty, mut $closure:expr) => { - if let Some(comp) = $entity.as_any_mut().downcast_mut()::<$comp_type>() { - $closure(comp) - } - }; -} - -/// Try to get a component, or execute else block -/// -/// # Usage -/// ``` -/// use eucalyptus_core::if_component; -/// -/// use eucalyptus_core::scene::SceneEntity; -/// -/// struct Transform { -/// position: [f32; 3], -/// } -/// -/// let scene_entity = SceneEntity::default(); -/// -/// if_component!(scene_entity, Transform, /*mut*/ |transform| { -/// let position = transform.position.get(0); -/// } else { -/// println!("No transform found"); -/// }); -#[macro_export] -macro_rules! if_component { - ($entity:expr, $comp_type:ty, |$comp:ident| $then:block else $else:block) => { - if let Some($comp) = $entity.as_any().downcast_ref::<$comp_type>() { - $then - } else { - $else - } - }; - - ($entity:expr, $comp_type:ty, |$comp:ident| $then:block) => { - if let Some($comp) = $entity.as_any().downcast_ref::<$comp_type>() { - $then - } - }; - - ($entity:expr, $comp_type:ty, |mut $comp:ident| $then:block else $else:block) => { - if let Some(mut $comp) = $entity.as_any_mut().downcast_mut()::<$comp_type>() { - $then - } else { - $else - } - }; - - ($entity:expr, $comp_type:ty, |mut $comp:ident| $then:block) => { - if let Some(mut $comp) = $entity.as_any_mut().downcast_mut()::<$comp_type>() { - $then - } - }; -} @@ -1,17 +1,12 @@ -use crate::ptr::WorldPtr; +use crate::ptr::{CommandBufferPtr, CommandBufferUnwrapped, WorldPtr}; use crate::scripting::result::DropbearNativeResult; -use hecs::World; pub mod shared { use crate::command::CommandBuffer; use crate::scripting::native::DropbearNativeError; use crate::scripting::result::DropbearNativeResult; use crate::states::Label; - use dropbear_engine::asset::AssetRegistry; - use dropbear_engine::utils::ResourceReference; use hecs::{Entity, World}; - use std::ffi::CStr; - use std::os::raw::c_char; pub fn get_entity(world: &World, label: &str) -> DropbearNativeResult<u64> { for (id, entity_label) in world.query::<(Entity, &Label)>().iter() { @@ -22,30 +17,12 @@ pub mod shared { Err(DropbearNativeError::EntityNotFound) } - pub fn get_asset(registry: &AssetRegistry, uri: &str) -> DropbearNativeResult<u64> { - let reference = ResourceReference::from_euca_uri(uri) - .map_err(|_| DropbearNativeError::InvalidURI)?; - - match registry.get_handle_from_reference(&reference) { - Some(handle) => Ok(handle.raw()), - None => Err(DropbearNativeError::AssetNotFound), - } - } - pub fn quit(command_buffer: &crossbeam_channel::Sender<CommandBuffer>) -> DropbearNativeResult<()> { command_buffer.send(CommandBuffer::Quit) .map_err(|_| DropbearNativeError::SendError) } - - pub unsafe fn read_str(ptr: *const c_char) -> DropbearNativeResult<String> { - if ptr.is_null() { return Err(DropbearNativeError::NullPointer); } - unsafe { CStr::from_ptr(ptr) }.to_str() - .map(|s| s.to_string()) - .map_err(|_| DropbearNativeError::InvalidUTF8) - } } -// input func #[dropbear_macro::export( kotlin( class = "com.dropbear.DropbearEngineNative", @@ -55,79 +32,22 @@ pub mod shared { )] fn get_entity( #[dropbear_macro::define(WorldPtr)] - world: &World, + world: &hecs::World, label: String, ) -> DropbearNativeResult<u64> { shared::get_entity(&world, &label) } -pub mod jni { - #![allow(non_snake_case)] - use crate::command::CommandBuffer; - use crate::return_boxed; - use dropbear_engine::asset::AssetRegistry; - use hecs::World; - use jni::objects::{JClass, JString}; - use jni::sys::{jlong, jobject}; - use jni::JNIEnv; - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_DropbearEngineNative_getEntity( - mut env: JNIEnv, - _class: JClass, - world_handle: jlong, - label: JString, - ) -> jobject { - let world = crate::convert_ptr!(world_handle => World); - let label_str = crate::convert_jstring!(env, label); - - let value_opt = super::shared::get_entity(&world, &label_str) - .ok() - .map(|id| id as i64); - - return_boxed!( - &mut env, - value_opt, - "(J)Ljava/lang/Long;", - "java/lang/Long" - ) - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_DropbearEngineNative_getAsset( - mut env: JNIEnv, - _class: JClass, - asset_handle: jlong, - label: JString, - ) -> jobject { - let asset = crate::convert_ptr!(asset_handle => AssetRegistry); - let label_str = crate::convert_jstring!(env, label); - - let value_opt = super::shared::get_asset(&asset, &label_str) - .ok() - .map(|id| id as i64); - - return_boxed!( - &mut env, - value_opt, - "(J)Ljava/lang/Long;", - "java/lang/Long" - ) - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_DropbearEngineNative_quit( - mut env: JNIEnv, - _class: JClass, - command_buffer_ptr: jlong, - ) { - let sender = crate::convert_ptr!(command_buffer_ptr => crossbeam_channel::Sender<CommandBuffer>); - - if let Err(e) = super::shared::quit(sender) { - let _ = env.throw_new( - "java/lang/RuntimeException", - format!("Failed to send quit command: {:?}", e) - ); - } - } +#[dropbear_macro::export( + kotlin( + class = "com.dropbear.DropbearEngineNative", + func = "quit", + ), + c +)] +fn quit( + #[dropbear_macro::define(CommandBufferPtr)] + command_buffer: &CommandBufferUnwrapped, +) -> DropbearNativeResult<()> { + shared::quit(command_buffer) } @@ -1,132 +1,98 @@ -pub mod jni { - #![allow(non_snake_case)] - use crate::hierarchy::{Children, Parent}; - use crate::states::Label; - use crate::{convert_jlong_to_entity, convert_jstring, convert_ptr}; - use hecs::World; - use jni::objects::{JClass, JString, JValue}; - use jni::sys::{jboolean, jlong, jlongArray, jobject, jsize, jstring}; - use jni::JNIEnv; - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_LabelNative_labelExistsForEntity( - _env: JNIEnv, - _: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jboolean { - let world = convert_ptr!(world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - world.get::<&Label>(entity).is_ok().into() - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_EntityRefNative_getEntityLabel( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jstring { - let world = crate::convert_ptr!(world_ptr => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - - let Ok(label) = world.get::<&Label>(entity) else { - let _ = env.throw_new("java/lang/InvalidArgumentException", "Unable to locate label entity"); - return std::ptr::null_mut(); - }; - - let label = label.as_str(); - - let Ok(string) = env.new_string(label) else { - let _ = env.throw_new("java/lang/OutOfMemoryException", "Unable to create new string"); - return std::ptr::null_mut(); - }; - - string.into_raw() - } - - pub extern "system" fn Java_com_dropbear_EntityRefNative_getChildren( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jlongArray { - let world = crate::convert_ptr!(world_ptr => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - - if let Ok(children) = world.query_one::<&Children>(entity).get() - { - let entity_bytes = children.children().iter().map(|c| c.to_bits().get() as i64).collect::<Vec<_>>(); - - let Ok(jarray) = env.new_long_array(entity_bytes.len() as jsize) else { - let _ = env.throw_new("java/lang/OutOfMemoryException", "Unable to create new long array"); - return std::ptr::null_mut(); - }; +use crate::hierarchy::{Children, Parent}; +use crate::ptr::WorldPtr; +use crate::scripting::result::DropbearNativeResult; +use crate::states::Label; + +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.LabelNative", func = "labelExistsForEntity"), + c +)] +fn label_exists_for_entity( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::entity] + entity: hecs::Entity +) -> DropbearNativeResult<bool> { + Ok(world.get::<&Label>(entity).is_ok()) +} - if let Err(e) = env.set_long_array_region(&jarray, 0, entity_bytes.as_slice()) { - let _ = env.throw_new("java/lang/RuntimeException", format!("Unable to populate long array: {}", e)); - return std::ptr::null_mut() - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.EntityRefNative", func = "getEntityLabel"), + c +)] +fn get_label( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::entity] + entity: hecs::Entity +) -> DropbearNativeResult<String> { + let label = world.get::<&Label>(entity)?.as_str().to_string(); + Ok(label) +} - jarray.into_raw() - } else { - // could be that the entity just doesn't have any children. - std::ptr::null_mut() - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.EntityRefNative", func = "getChildren"), + c +)] +fn get_children( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::entity] + entity: hecs::Entity +) -> DropbearNativeResult<Vec<u64>> { + if let Ok(children) = world.query_one::<&Children>(entity).get() + { + let entity_bytes = children.children().iter().map(|c| c.to_bits().get()).collect::<Vec<_>>(); + Ok(entity_bytes) + } else { + // could be that the entity just doesn't have any children, so no need to throw error + Ok(vec![]) } +} - pub extern "system" fn Java_com_dropbear_EntityRefNative_getChildByLabel( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - label: JString, - ) -> jobject { - let world = crate::convert_ptr!(world_ptr => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - let target = convert_jstring!(env, label); - - if let Ok(children) = world.query_one::<&Children>(entity).get() - { - for child in children.children() { - if let Ok(label) = world.get::<&Label>(entity) { - if label.as_str() == target { - let found = child.clone(); - - return crate::return_boxed!(&mut env, Some(JValue::Long(found.to_bits().get() as i64)), "(J)Ljava/lang/Long", "java/lang/Long"); - } - } else { - // skip if error or no entity - continue; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.EntityRefNative", func = "getChildByLabel"), + c +)] +fn get_child_by_label( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::entity] + entity: hecs::Entity, + target: String, +) -> DropbearNativeResult<Option<u64>> { + if let Ok(children) = world.query_one::<&Children>(entity).get() + { + for child in children.children() { + if let Ok(label) = world.get::<&Label>(entity) { + if label.as_str() == target { + let found = child.clone(); + return Ok(Some(found.to_bits().get())); } + } else { + // skip if error or no entity + continue; } - std::ptr::null_mut() - } else { - // could be that the entity just doesn't have any children. - std::ptr::null_mut() - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_EntityRefNative_getParent( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jobject { - let world = convert_ptr!(world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - if let Ok(parent) = world.query_one::<&Parent>(entity).get() { - crate::return_boxed!(&mut env, Some(JValue::Long(parent.parent().to_bits().get() as jlong)), "(J)Ljava/lang/Long", "java/lang/Long") - } else { - std::ptr::null_mut() } + Ok(None) + } else { + Ok(None) } } -#[dropbear_macro::impl_c_api] -pub mod native { - +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.EntityRefNative", func = "getParent"), + c +)] +fn get_parent( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::entity] + entity: hecs::Entity, +) -> DropbearNativeResult<Option<u64>> { + if let Ok(parent) = world.query_one::<&Parent>(entity).get() { + Ok(Some(parent.parent().to_bits().get())) + } else { + Ok(None) + } } @@ -78,10 +78,8 @@ impl Hierarchy { } } - // Add Parent component to child let _ = world.insert_one(child, Parent::new(parent)); - // Add child to parent's Children component if let Ok(mut children) = world.get::<&mut Children>(parent) { children.push(child); } else { @@ -11,6 +11,12 @@ use std::{ use glam::Vec2; use winit::window::Window; use winit::{event::MouseButton, keyboard::KeyCode}; +use crate::scripting::jni::utils::ToJObject; +use crate::scripting::native::DropbearNativeError; +use crate::scripting::result::DropbearNativeResult; +use jni::objects::JObject; +use jni::sys::jlong; +use jni::JNIEnv; #[allow(dead_code)] #[derive(Clone, Debug)] @@ -112,8 +118,6 @@ impl InputState { pub mod shared { use crossbeam_channel::Sender; use crate::command::{CommandBuffer, WindowCommand}; - use crate::scripting::native::DropbearNativeError; - use crate::scripting::result::DropbearNativeResult; use crate::types::NVector2; use super::*; @@ -191,266 +195,152 @@ pub mod shared { } } -pub mod jni { - #![allow(non_snake_case)] - use jni::JNIEnv; - use jni::objects::{JClass, JObject}; - use jni::sys::{jboolean, jint, jlong, jlongArray, jobject}; - use crate::input::InputState; - use crate::command::CommandBuffer; - use crate::scripting::jni::utils::ToJObject; - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_input_InputStateNative_printInputState( - _env: JNIEnv, - _class: JClass, - input_ptr: jlong, - ) { - let input = crate::convert_ptr!(input_ptr => InputState); - println!("Input State: {:?}", input); - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_input_InputStateNative_isKeyPressed( - _env: JNIEnv, - _class: JClass, - input_ptr: jlong, - key_code: jint, - ) -> jboolean { - let input = crate::convert_ptr!(input_ptr => InputState); - if super::shared::is_key_pressed(&input, key_code) { 1 } else { 0 } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_input_InputStateNative_getMousePosition( - mut env: JNIEnv, - _class: JClass, - input_ptr: jlong, - ) -> jobject { - let input = crate::convert_ptr!(input_ptr => InputState); - let vec = super::shared::get_mouse_position(&input); - match vec.to_jobject(&mut env) { - Ok(obj) => obj.into_raw(), - Err(_) => std::ptr::null_mut(), - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_input_InputStateNative_isMouseButtonPressed( - mut env: JNIEnv, - _class: JClass, - input_ptr: jlong, - mouse_button_obj: JObject, - ) -> jboolean { - let input = crate::convert_ptr!(input_ptr => InputState); - - let ordinal_res = env.call_method(&mouse_button_obj, "ordinal", "()I", &[]); - - let ordinal = match ordinal_res.and_then(|v| v.i()) { - Ok(i) => i, - Err(e) => { - eprintln!("Failed to get MouseButton ordinal: {:?}", e); - return 0; - } - }; - - if super::shared::is_mouse_button_pressed(&input, ordinal) { 1 } else { 0 } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_input_InputStateNative_getMouseDelta( - mut env: JNIEnv, - _class: JClass, - input_ptr: jlong, - ) -> jobject { - let input = crate::convert_ptr!(input_ptr => InputState); - let vec = super::shared::get_mouse_delta(&input); - match vec.to_jobject(&mut env) { - Ok(obj) => obj.into_raw(), - Err(_) => std::ptr::null_mut(), - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_input_InputStateNative_isCursorLocked( - _env: JNIEnv, - _class: JClass, - input_ptr: jlong, - ) -> jboolean { - let input = crate::convert_ptr!(input_ptr => InputState); - if input.is_cursor_locked { 1 } else { 0 } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_input_InputStateNative_setCursorLocked( - mut env: JNIEnv, - _class: JClass, - cmd_ptr: jlong, - input_ptr: jlong, - locked: jboolean, - ) { - let input = crate::convert_ptr!(mut input_ptr => InputState); - let sender = crate::convert_ptr!(cmd_ptr => crossbeam_channel::Sender<CommandBuffer>); - - if let Err(e) = super::shared::set_cursor_locked(input, sender, locked != 0) { - let _ = env.throw_new("java/lang/RuntimeException", format!("{:?}", e)); - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_input_InputStateNative_getLastMousePos( - mut env: JNIEnv, - _class: JClass, - input_ptr: jlong, - ) -> jobject { - let input = crate::convert_ptr!(input_ptr => InputState); - let vec = super::shared::get_last_mouse_pos(&input); - match vec.to_jobject(&mut env) { - Ok(obj) => obj.into_raw(), - Err(_) => std::ptr::null_mut(), - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_input_InputStateNative_isCursorHidden( - _env: JNIEnv, - _class: JClass, - input_ptr: jlong, - ) -> jboolean { - let input = crate::convert_ptr!(input_ptr => InputState); - if input.is_cursor_hidden { 1 } else { 0 } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_input_InputStateNative_setCursorHidden( - mut env: JNIEnv, - _class: JClass, - cmd_ptr: jlong, - input_ptr: jlong, - hidden: jboolean, - ) { - let input = crate::convert_ptr!(mut input_ptr => InputState); - let sender = crate::convert_ptr!(cmd_ptr => crossbeam_channel::Sender<CommandBuffer>); - - if let Err(e) = super::shared::set_cursor_hidden(input, sender, hidden != 0) { - let _ = env.throw_new("java/lang/RuntimeException", format!("{:?}", e)); - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_input_InputStateNative_getConnectedGamepads( - env: JNIEnv, - _class: JClass, - input_ptr: jlong, - ) -> jlongArray { - let input = crate::convert_ptr!(input_ptr => InputState); - let ids = super::shared::get_connected_gamepads(&input); - - let long_ids: Vec<i64> = ids.iter().map(|&id| id as i64).collect(); - - let output = match env.new_long_array(long_ids.len() as i32) { - Ok(arr) => arr, - Err(_) => return std::ptr::null_mut(), - }; - - if env.set_long_array_region(&output, 0, &long_ids).is_ok() { - output.into_raw() - } else { - std::ptr::null_mut() - } - } +#[repr(C)] +struct ConnectedGamepadIds { + ids: Vec<u64>, } -#[dropbear_macro::impl_c_api] -pub mod native { - use crate::ptr::{InputStatePtr, CommandBufferPtr}; - use crate::input::{InputState}; - use crate::command::CommandBuffer; - use crate::convert_ptr; - use crate::scripting::native::DropbearNativeError; - use crate::scripting::result::DropbearNativeResult; - use crate::types::NVector2; +impl ToJObject for ConnectedGamepadIds { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + let output = env + .new_long_array(self.ids.len() as i32) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; - pub fn dropbear_print_input_state(input_ptr: InputStatePtr) -> DropbearNativeResult<()> { - let input = convert_ptr!(input_ptr => InputState); - println!("Input State: {:?}", input); - DropbearNativeResult::Ok(()) - } - - pub fn dropbear_is_key_pressed(input_ptr: InputStatePtr, key_ordinal: i32) -> DropbearNativeResult<bool> { - let input = convert_ptr!(input_ptr => InputState); - DropbearNativeResult::Ok(super::shared::is_key_pressed(input, key_ordinal)) - } - - pub fn dropbear_get_mouse_position(input_ptr: InputStatePtr) -> DropbearNativeResult<NVector2> { - let input = convert_ptr!(input_ptr => InputState); - DropbearNativeResult::Ok(super::shared::get_mouse_position(input)) - } - - pub fn dropbear_is_mouse_button_pressed(input_ptr: InputStatePtr, btn_ordinal: i32) -> DropbearNativeResult<bool> { - let input = convert_ptr!(input_ptr => InputState); - DropbearNativeResult::Ok(super::shared::is_mouse_button_pressed(input, btn_ordinal)) - } - - pub fn dropbear_get_mouse_delta(input_ptr: InputStatePtr) -> DropbearNativeResult<NVector2> { - let input = convert_ptr!(input_ptr => InputState); - DropbearNativeResult::Ok(super::shared::get_mouse_delta(input)) - } - - pub fn dropbear_is_cursor_locked(input_ptr: InputStatePtr) -> DropbearNativeResult<bool> { - let input = convert_ptr!(input_ptr => InputState); - DropbearNativeResult::Ok(input.is_cursor_locked) + let long_ids: Vec<jlong> = self.ids.iter().map(|&id| id as jlong).collect(); + env.set_long_array_region(&output, 0, &long_ids) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; + Ok(JObject::from(output)) } +} - pub fn dropbear_set_cursor_locked( - cmd_ptr: CommandBufferPtr, - input_ptr: InputStatePtr, - locked: bool - ) -> DropbearNativeResult<()> { - let input = convert_ptr!(mut input_ptr => InputState); - let sender = convert_ptr!(cmd_ptr => crossbeam_channel::Sender<CommandBuffer>); - super::shared::set_cursor_locked(input, sender, locked) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.input.InputStateNative", func = "printInputState"), + c +)] +fn print_input_state( + #[dropbear_macro::define(crate::ptr::InputStatePtr)] + input: &InputState, +) -> DropbearNativeResult<()> { + println!("Input State: {:?}", input); + Ok(()) +} - pub fn dropbear_get_last_mouse_pos(input_ptr: InputStatePtr) -> DropbearNativeResult<NVector2> { - let input = convert_ptr!(input_ptr => InputState); - DropbearNativeResult::Ok(super::shared::get_last_mouse_pos(input)) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.input.InputStateNative", func = "isKeyPressed"), + c +)] +fn is_key_pressed( + #[dropbear_macro::define(crate::ptr::InputStatePtr)] + input: &InputState, + key_code: i32, +) -> DropbearNativeResult<bool> { + Ok(shared::is_key_pressed(input, key_code)) +} - pub fn dropbear_is_cursor_hidden(input_ptr: InputStatePtr) -> DropbearNativeResult<bool> { - let input = convert_ptr!(input_ptr => InputState); - DropbearNativeResult::Ok(input.is_cursor_hidden) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.input.InputStateNative", func = "getMousePosition"), + c +)] +fn get_mouse_position( + #[dropbear_macro::define(crate::ptr::InputStatePtr)] + input: &InputState, +) -> DropbearNativeResult<crate::types::NVector2> { + Ok(shared::get_mouse_position(input)) +} - pub fn dropbear_set_cursor_hidden( - cmd_ptr: CommandBufferPtr, - input_ptr: InputStatePtr, - hidden: bool - ) -> DropbearNativeResult<()> { - let input = convert_ptr!(mut input_ptr, InputStatePtr => InputState); - let sender = convert_ptr!(cmd_ptr => crossbeam_channel::Sender<CommandBuffer>); - super::shared::set_cursor_hidden(input, sender, hidden) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.input.InputStateNative", func = "isMouseButtonPressed"), + c +)] +fn is_mouse_button_pressed( + #[dropbear_macro::define(crate::ptr::InputStatePtr)] + input: &InputState, + button_ordinal: i32, +) -> DropbearNativeResult<bool> { + Ok(shared::is_mouse_button_pressed(input, button_ordinal)) +} - pub fn dropbear_get_connected_gamepads( - input_ptr: InputStatePtr, - out_count: *mut usize, - ) -> DropbearNativeResult<*mut u64> { - let input = convert_ptr!(input_ptr => InputState); +#[dropbear_macro::export( + kotlin(class = "com.dropbear.input.InputStateNative", func = "getMouseDelta"), + c +)] +fn get_mouse_delta( + #[dropbear_macro::define(crate::ptr::InputStatePtr)] + input: &InputState, +) -> DropbearNativeResult<crate::types::NVector2> { + Ok(shared::get_mouse_delta(input)) +} - let mut ids = super::shared::get_connected_gamepads(input); +#[dropbear_macro::export( + kotlin(class = "com.dropbear.input.InputStateNative", func = "isCursorLocked"), + c +)] +fn is_cursor_locked( + #[dropbear_macro::define(crate::ptr::InputStatePtr)] + input: &InputState, +) -> DropbearNativeResult<bool> { + Ok(input.is_cursor_locked) +} - ids.shrink_to_fit(); +#[dropbear_macro::export( + kotlin(class = "com.dropbear.input.InputStateNative", func = "setCursorLocked"), + c +)] +fn set_cursor_locked( + #[dropbear_macro::define(crate::ptr::CommandBufferPtr)] + command_buffer: &crate::ptr::CommandBufferUnwrapped, + #[dropbear_macro::define(crate::ptr::InputStatePtr)] + input: &mut InputState, + locked: bool, +) -> DropbearNativeResult<()> { + shared::set_cursor_locked(input, command_buffer, locked) +} - if out_count.is_null() { - return DropbearNativeResult::Err(DropbearNativeError::NullPointer); - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.input.InputStateNative", func = "getLastMousePos"), + c +)] +fn get_last_mouse_pos( + #[dropbear_macro::define(crate::ptr::InputStatePtr)] + input: &InputState, +) -> DropbearNativeResult<crate::types::NVector2> { + Ok(shared::get_last_mouse_pos(input)) +} - unsafe { *out_count = ids.len(); } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.input.InputStateNative", func = "isCursorHidden"), + c +)] +fn is_cursor_hidden( + #[dropbear_macro::define(crate::ptr::InputStatePtr)] + input: &InputState, +) -> DropbearNativeResult<bool> { + Ok(input.is_cursor_hidden) +} - let ptr = ids.as_mut_ptr(); - std::mem::forget(ids); +#[dropbear_macro::export( + kotlin(class = "com.dropbear.input.InputStateNative", func = "setCursorHidden"), + c +)] +fn set_cursor_hidden( + #[dropbear_macro::define(crate::ptr::CommandBufferPtr)] + command_buffer: &crate::ptr::CommandBufferUnwrapped, + #[dropbear_macro::define(crate::ptr::InputStatePtr)] + input: &mut InputState, + hidden: bool, +) -> DropbearNativeResult<()> { + shared::set_cursor_hidden(input, command_buffer, hidden) +} - DropbearNativeResult::Ok(ptr) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.input.InputStateNative", func = "getConnectedGamepads"), + c +)] +fn get_connected_gamepads( + #[dropbear_macro::define(crate::ptr::InputStatePtr)] + input: &InputState, +) -> DropbearNativeResult<ConnectedGamepadIds> { + Ok(ConnectedGamepadIds { + ids: shared::get_connected_gamepads(input), + }) } @@ -1,41 +1,44 @@ +use crate::input::InputState; +use crate::ptr::InputStatePtr; +use crate::scripting::result::DropbearNativeResult; +use crate::types::NVector2; + pub mod shared { - use dropbear_engine::gilrs::{Button, GamepadId}; use jni::JNIEnv; use jni::objects::{JObject, JValue}; - use dropbear_engine::gilrs; use crate::input::InputState; use crate::scripting::jni::utils::{FromJObject, ToJObject}; use crate::scripting::native::DropbearNativeError; use crate::scripting::result::DropbearNativeResult; use crate::types::NVector2; - fn map_int_to_gamepad_button(ordinal: i32) -> Option<Button> { + fn map_int_to_gamepad_button(ordinal: i32) -> Option<dropbear_engine::gilrs::Button> { match ordinal { - 0 => Some(gilrs::Button::Unknown), - 1 => Some(gilrs::Button::South), - 2 => Some(gilrs::Button::East), - 3 => Some(gilrs::Button::North), - 4 => Some(gilrs::Button::West), - 5 => Some(gilrs::Button::C), - 6 => Some(gilrs::Button::Z), - 7 => Some(gilrs::Button::LeftTrigger), - 8 => Some(gilrs::Button::RightTrigger), - 9 => Some(gilrs::Button::LeftTrigger2), - 10 => Some(gilrs::Button::RightTrigger2), - 11 => Some(gilrs::Button::Select), - 12 => Some(gilrs::Button::Start), - 13 => Some(gilrs::Button::Mode), - 14 => Some(gilrs::Button::LeftThumb), - 15 => Some(gilrs::Button::RightThumb), - 16 => Some(gilrs::Button::DPadUp), - 17 => Some(gilrs::Button::DPadDown), - 18 => Some(gilrs::Button::DPadLeft), - 19 => Some(gilrs::Button::DPadRight), + 0 => Some(dropbear_engine::gilrs::Button::Unknown), + 1 => Some(dropbear_engine::gilrs::Button::South), + 2 => Some(dropbear_engine::gilrs::Button::East), + 3 => Some(dropbear_engine::gilrs::Button::North), + 4 => Some(dropbear_engine::gilrs::Button::West), + 5 => Some(dropbear_engine::gilrs::Button::C), + 6 => Some(dropbear_engine::gilrs::Button::Z), + 7 => Some(dropbear_engine::gilrs::Button::LeftTrigger), + 8 => Some(dropbear_engine::gilrs::Button::RightTrigger), + 9 => Some(dropbear_engine::gilrs::Button::LeftTrigger2), + 10 => Some(dropbear_engine::gilrs::Button::RightTrigger2), + 11 => Some(dropbear_engine::gilrs::Button::Select), + 12 => Some(dropbear_engine::gilrs::Button::Start), + 13 => Some(dropbear_engine::gilrs::Button::Mode), + 14 => Some(dropbear_engine::gilrs::Button::LeftThumb), + 15 => Some(dropbear_engine::gilrs::Button::RightThumb), + 16 => Some(dropbear_engine::gilrs::Button::DPadUp), + 17 => Some(dropbear_engine::gilrs::Button::DPadDown), + 18 => Some(dropbear_engine::gilrs::Button::DPadLeft), + 19 => Some(dropbear_engine::gilrs::Button::DPadRight), _ => None, } } - pub fn get_gamepad_id(input: &InputState, target: usize) -> Option<GamepadId> { + pub fn get_gamepad_id(input: &InputState, target: usize) -> Option<dropbear_engine::gilrs::GamepadId> { input.connected_gamepads.iter().find(|g| usize::from(**g) == target).copied() } @@ -122,112 +125,39 @@ pub mod shared { } } -pub mod jni { - #![allow(non_snake_case)] - - use jni::JNIEnv; - use jni::objects::JClass; - use jni::sys::{jboolean, jint, jlong, jobject}; - use crate::input::InputState; - use crate::scripting::jni::utils::ToJObject; - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_input_GamepadNative_isGamepadButtonPressed( - _env: JNIEnv, - _class: JClass, - input_ptr: jlong, - gamepad_id: jlong, - button_ordinal: jint, - ) -> jboolean { - let input = crate::convert_ptr!(input_ptr => InputState); - if super::shared::is_gamepad_button_pressed(&input, gamepad_id as u64, button_ordinal) { - 1 - } else { - 0 - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_input_GamepadNative_getLeftStickPosition( - mut env: JNIEnv, - _class: JClass, - input_ptr: jlong, - gamepad_id: jlong, - ) -> jobject { - let input = crate::convert_ptr!(input_ptr => InputState); - let vec = super::shared::get_left_stick(&input, gamepad_id as u64); - - match vec.to_jobject(&mut env) { - Ok(obj) => obj.into_raw(), - Err(_) => std::ptr::null_mut(), - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_input_GamepadNative_getRightStickPosition( - mut env: JNIEnv, - _class: JClass, - input_ptr: jlong, - gamepad_id: jlong, - ) -> jobject { - let input = crate::convert_ptr!(input_ptr => InputState); - let vec = super::shared::get_right_stick(&input, gamepad_id as u64); - - match vec.to_jobject(&mut env) { - Ok(obj) => obj.into_raw(), - Err(_) => std::ptr::null_mut(), - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.input.GamepadNative", func = "isGamepadButtonPressed"), + c +)] +fn is_button_pressed( + #[dropbear_macro::define(InputStatePtr)] + input: &InputState, + gamepad_id: u64, + button_ordinal: i32, +) -> DropbearNativeResult<bool> { + Ok(shared::is_gamepad_button_pressed(&input, gamepad_id, button_ordinal)) } -#[dropbear_macro::impl_c_api] -pub mod native { - use crate::ptr::InputStatePtr; - use crate::input::{InputState}; - use crate::convert_ptr; - use crate::scripting::result::DropbearNativeResult; - use crate::types::NVector2; - - pub fn dropbear_is_gamepad_button_pressed( - input_ptr: InputStatePtr, - gamepad_id: u64, - button_ordinal: i32 - ) -> DropbearNativeResult<bool> { - let input = convert_ptr!(input_ptr => InputState); - let result = super::shared::is_gamepad_button_pressed(input, gamepad_id, button_ordinal); - DropbearNativeResult::Ok(result) - } - - pub fn dropbear_get_left_stick_position( - input_ptr: InputStatePtr, - gamepad_id: u64 - ) -> DropbearNativeResult<NVector2> { - let input = convert_ptr!(input_ptr => InputState); - let vec = super::shared::get_left_stick(input, gamepad_id); - DropbearNativeResult::Ok(vec) - } - - pub fn dropbear_get_right_stick_position( - input_ptr: InputStatePtr, - gamepad_id: u64 - ) -> DropbearNativeResult<NVector2> { - let input = convert_ptr!(input_ptr => InputState); - let vec = super::shared::get_right_stick(input, gamepad_id); - DropbearNativeResult::Ok(vec) - } - - pub fn dropbear_free_gamepads_array( - ptr: *mut u64, - count: usize, - ) -> DropbearNativeResult<()> { - if ptr.is_null() { - return DropbearNativeResult::Ok(()); - } - - unsafe { - let _ = Vec::from_raw_parts(ptr, count, count); - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.input.GamepadNative", func = "getLeftStickPosition"), + c +)] +fn get_left_stick_position( + #[dropbear_macro::define(InputStatePtr)] + input: &InputState, + gamepad_id: u64, +) -> DropbearNativeResult<NVector2> { + Ok(shared::get_left_stick(&input, gamepad_id)) +} - DropbearNativeResult::Ok(()) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.input.GamepadNative", func = "getRightStickPosition"), + c +)] +fn get_right_stick_position( + #[dropbear_macro::define(InputStatePtr)] + input: &InputState, + gamepad_id: u64, +) -> DropbearNativeResult<NVector2> { + Ok(shared::get_right_stick(&input, gamepad_id)) } @@ -1,12 +1,10 @@ pub mod lighting; pub mod camera; -pub mod component; pub mod config; pub mod hierarchy; pub mod input; pub mod logging; pub mod ptr; -pub mod result; pub mod runtime; pub mod scene; pub mod scripting; @@ -21,7 +19,6 @@ pub mod mesh; pub mod entity; pub mod engine; pub mod transform; -pub mod ui; pub mod asset; pub use dropbear_macro as macros; @@ -39,7 +36,6 @@ use crate::physics::collider::ColliderGroup; use crate::physics::kcc::KCC; use crate::physics::rigidbody::RigidBody; use crate::states::{Camera3D, Light, Script, SerializedMeshRenderer}; -use crate::ui::UIComponent; /// The appdata directory for storing any information. /// @@ -69,7 +65,6 @@ pub fn register_components( component_registry.register_with_default::<RigidBody>(); component_registry.register_with_default::<ColliderGroup>(); component_registry.register_with_default::<KCC>(); - component_registry.register_with_default::<UIComponent>(); component_registry.register_with_default::<AnimationComponent>(); component_registry.register_converter::<MeshRenderer, SerializedMeshRenderer, _>( @@ -1,19 +1,25 @@ +use crate::ptr::WorldPtr; use crate::scripting::jni::utils::{FromJObject, ToJObject}; use crate::scripting::native::DropbearNativeError; use crate::scripting::result::DropbearNativeResult; -use glam::DVec3; -use ::jni::objects::{JObject, JValue}; -use ::jni::JNIEnv; - +use crate::types::NVector3; +use dropbear_engine::entity::{EntityTransform, Transform}; +use dropbear_engine::lighting::{LightComponent, LightType}; +use glam::{DQuat, DVec3}; +use hecs::{Entity, World}; +use jni::objects::{JObject, JValue}; +use jni::JNIEnv; + +#[repr(C)] #[derive(Clone, Copy, Debug)] -struct JvmColour { +struct NColour { r: u8, g: u8, b: u8, a: u8, } -impl JvmColour { +impl NColour { fn to_linear_rgb(self) -> DVec3 { DVec3::new( self.r as f64 / 255.0, @@ -37,7 +43,7 @@ impl JvmColour { } } -impl FromJObject for JvmColour { +impl FromJObject for NColour { fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { let class = env .find_class("com/dropbear/utils/Colour") @@ -68,7 +74,7 @@ impl FromJObject for JvmColour { } } -impl ToJObject for JvmColour { +impl ToJObject for NColour { fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { let class = env .find_class("com/dropbear/utils/Colour") @@ -86,13 +92,14 @@ impl ToJObject for JvmColour { } } +#[repr(C)] #[derive(Clone, Copy, Debug)] -struct JvmRange { +struct NRange { start: f32, end: f32, } -impl FromJObject for JvmRange { +impl FromJObject for NRange { fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { let class = env .find_class("com/dropbear/utils/Range") @@ -121,7 +128,7 @@ impl FromJObject for JvmRange { } } -impl ToJObject for JvmRange { +impl ToJObject for NRange { fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { let class = env .find_class("com/dropbear/utils/Range") @@ -137,14 +144,15 @@ impl ToJObject for JvmRange { } } +#[repr(C)] #[derive(Clone, Copy, Debug)] -struct JvmAttenuation { +struct NAttenuation { constant: f32, linear: f32, quadratic: f32, } -impl FromJObject for JvmAttenuation { +impl FromJObject for NAttenuation { fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { let class = env .find_class("com/dropbear/lighting/Attenuation") @@ -183,7 +191,7 @@ impl FromJObject for JvmAttenuation { } } -impl ToJObject for JvmAttenuation { +impl ToJObject for NAttenuation { fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { let class = env .find_class("com/dropbear/lighting/Attenuation") @@ -201,591 +209,462 @@ impl ToJObject for JvmAttenuation { } pub mod shared { - use dropbear_engine::lighting::LightComponent; use hecs::{Entity, World}; pub fn light_exists_for_entity(world: &World, entity: Entity) -> bool { - world.get::<&LightComponent>(entity).is_ok() + world.get::<&dropbear_engine::lighting::LightComponent>(entity).is_ok() } } -pub mod jni { - #![allow(non_snake_case)] - - use super::{JvmAttenuation, JvmColour, JvmRange}; - use crate::scripting::jni::utils::{FromJObject, ToJObject}; - use crate::types::NVector3; - use crate::{convert_jlong_to_entity, convert_ptr}; - use dropbear_engine::entity::{EntityTransform, Transform}; - use dropbear_engine::lighting::{LightComponent, LightType}; - use glam::{DQuat, DVec3}; - use hecs::World; - use jni::objects::{JClass, JObject}; - use jni::sys::{jboolean, jdouble, jint, jlong, jobject}; - use jni::JNIEnv; - - fn get_transform(world: &World, entity: hecs::Entity) -> Option<Transform> { - if let Ok(et) = world.get::<&EntityTransform>(entity) { - Some(et.sync()) - } else if let Ok(t) = world.get::<&Transform>(entity) { - Some(*t) - } else { - None - } - } - - fn set_transform_position(world: &mut World, entity: hecs::Entity, position: DVec3) -> bool { - if let Ok(mut et) = world.get::<&mut EntityTransform>(entity) { - et.local_mut().position = position; - true - } else if let Ok(mut t) = world.get::<&mut Transform>(entity) { - t.position = position; - true - } else { - false - } - } - - fn set_transform_rotation(world: &mut World, entity: hecs::Entity, rotation: DQuat) -> bool { - if let Ok(mut et) = world.get::<&mut EntityTransform>(entity) { - et.local_mut().rotation = rotation; - true - } else if let Ok(mut t) = world.get::<&mut Transform>(entity) { - t.rotation = rotation; - true - } else { - false - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_lightExistsForEntity( - _env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jboolean { - let world = convert_ptr!(world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - if world.get::<&LightComponent>(entity).is_ok() { - 1 - } else { - 0 - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_getPosition( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jobject { - let world = convert_ptr!(world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let Some(t) = get_transform(world, entity) else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing Transform/EntityTransform"); - return std::ptr::null_mut(); - }; - - match NVector3::from(t.position).to_jobject(&mut env) { - Ok(obj) => obj.into_raw(), - Err(_) => std::ptr::null_mut(), - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_setPosition( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - position: JObject, - ) { - let world = convert_ptr!(mut world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let position: DVec3 = match NVector3::from_jobject(&mut env, &position) { - Ok(v) => v.into(), - Err(e) => { - let _ = env.throw_new( - "java/lang/IllegalArgumentException", - format!("Invalid Vector3d: {:?}", e), - ); - return; - } - }; - - if !set_transform_position(world, entity, position) { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing Transform/EntityTransform"); - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_getDirection( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jobject { - let world = convert_ptr!(world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let Some(t) = get_transform(world, entity) else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing Transform/EntityTransform"); - return std::ptr::null_mut(); - }; - - let forward = DVec3::new(0.0, 0.0, -1.0); - let dir = (t.rotation * forward).normalize_or_zero(); - - match NVector3::from(dir).to_jobject(&mut env) { - Ok(obj) => obj.into_raw(), - Err(_) => std::ptr::null_mut(), - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_setDirection( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - direction: JObject, - ) { - let world = convert_ptr!(mut world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let dir: DVec3 = match NVector3::from_jobject(&mut env, &direction) { - Ok(v) => DVec3::from(v), - Err(e) => { - let _ = env.throw_new( - "java/lang/IllegalArgumentException", - format!("Invalid Vector3d: {:?}", e), - ); - return; - } - }; - - let desired = dir.normalize_or_zero(); - if desired.length_squared() < 1e-12 { - let _ = env.throw_new("java/lang/IllegalArgumentException", "Direction must be non-zero"); - return; - } - - let forward = DVec3::new(0.0, 0.0, -1.0); - let rotation = DQuat::from_rotation_arc(forward, desired); - - if !set_transform_rotation(world, entity, rotation) { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing Transform/EntityTransform"); - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_getColour( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jobject { - let world = convert_ptr!(world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let Ok(light) = world.get::<&LightComponent>(entity) else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing LightComponent"); - return std::ptr::null_mut(); - }; - - let colour = JvmColour::from_linear_rgb(light.colour); - match colour.to_jobject(&mut env) { - Ok(obj) => obj.into_raw(), - Err(_) => std::ptr::null_mut(), - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_setColour( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - colour: JObject, - ) { - let world = convert_ptr!(mut world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let Ok(mut light) = world.get::<&mut LightComponent>(entity) else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing LightComponent"); - return; - }; - - let colour = match JvmColour::from_jobject(&mut env, &colour) { - Ok(c) => c, - Err(e) => { - let _ = env.throw_new( - "java/lang/IllegalArgumentException", - format!("Invalid Colour: {:?}", e), - ); - return; - } - }; - - light.colour = colour.to_linear_rgb(); - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_getLightType( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jint { - let world = convert_ptr!(world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let Ok(light) = world.get::<&LightComponent>(entity) else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing LightComponent"); - return -1; - }; - - light.light_type as i32 - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_setLightType( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - light_type: jint, - ) { - let world = convert_ptr!(mut world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let Ok(mut light) = world.get::<&mut LightComponent>(entity) else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing LightComponent"); - return; - }; - - light.light_type = match light_type { - 0 => LightType::Directional, - 1 => LightType::Point, - 2 => LightType::Spot, - _ => { - let _ = env.throw_new("java/lang/IllegalArgumentException", "Invalid lightType ordinal"); - return; - } - }; - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_getIntensity( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jdouble { - let world = convert_ptr!(world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let Ok(light) = world.get::<&LightComponent>(entity) else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing LightComponent"); - return f64::NAN; - }; - - light.intensity as f64 - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_setIntensity( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - intensity: jdouble, - ) { - let world = convert_ptr!(mut world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let Ok(mut light) = world.get::<&mut LightComponent>(entity) else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing LightComponent"); - return; - }; - - light.intensity = intensity as f32; - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_getAttenuation( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jobject { - let world = convert_ptr!(world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let Ok(light) = world.get::<&LightComponent>(entity) else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing LightComponent"); - return std::ptr::null_mut(); - }; - - let att = JvmAttenuation { - constant: light.attenuation.constant, - linear: light.attenuation.linear, - quadratic: light.attenuation.quadratic, - }; - - match att.to_jobject(&mut env) { - Ok(obj) => obj.into_raw(), - Err(_) => std::ptr::null_mut(), - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_setAttenuation( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - attenuation: JObject, - ) { - let world = convert_ptr!(mut world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let Ok(mut light) = world.get::<&mut LightComponent>(entity) else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing LightComponent"); - return; - }; +fn get_transform(world: &World, entity: Entity) -> DropbearNativeResult<Transform> { + if let Ok(et) = world.get::<&EntityTransform>(entity) { + Ok(et.sync()) + } else if let Ok(t) = world.get::<&Transform>(entity) { + Ok(*t) + } else { + Err(DropbearNativeError::MissingComponent) + } +} - let att = match JvmAttenuation::from_jobject(&mut env, &attenuation) { - Ok(a) => a, - Err(e) => { - let _ = env.throw_new( - "java/lang/IllegalArgumentException", - format!("Invalid Attenuation: {:?}", e), - ); - return; - } - }; +fn set_transform_position( + world: &mut World, + entity: Entity, + position: DVec3, +) -> DropbearNativeResult<()> { + if let Ok(mut et) = world.get::<&mut EntityTransform>(entity) { + et.local_mut().position = position; + Ok(()) + } else if let Ok(mut t) = world.get::<&mut Transform>(entity) { + t.position = position; + Ok(()) + } else { + Err(DropbearNativeError::MissingComponent) + } +} - // Kotlin exposes only coefficients; preserve existing `range`. - light.attenuation.constant = att.constant; - light.attenuation.linear = att.linear; - light.attenuation.quadratic = att.quadratic; - } +fn set_transform_rotation( + world: &mut World, + entity: Entity, + rotation: DQuat, +) -> DropbearNativeResult<()> { + if let Ok(mut et) = world.get::<&mut EntityTransform>(entity) { + et.local_mut().rotation = rotation; + Ok(()) + } else if let Ok(mut t) = world.get::<&mut Transform>(entity) { + t.rotation = rotation; + Ok(()) + } else { + Err(DropbearNativeError::MissingComponent) + } +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_getEnabled( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jboolean { - let world = convert_ptr!(world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let Ok(light) = world.get::<&LightComponent>(entity) else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing LightComponent"); - return 0; - }; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "lightExistsForEntity"), + c +)] +fn light_exists_for_entity( + #[dropbear_macro::define(WorldPtr)] + world: &World, + #[dropbear_macro::entity] + entity: Entity, +) -> DropbearNativeResult<bool> { + Ok(shared::light_exists_for_entity(world, entity)) +} - if light.enabled { 1 } else { 0 } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "getPosition"), + c +)] +fn get_position( + #[dropbear_macro::define(WorldPtr)] + world: &World, + #[dropbear_macro::entity] + entity: Entity, +) -> DropbearNativeResult<NVector3> { + let transform = get_transform(world, entity)?; + Ok(NVector3::from(transform.position)) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_setEnabled( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - enabled: jboolean, - ) { - let world = convert_ptr!(mut world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let Ok(mut light) = world.get::<&mut LightComponent>(entity) else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing LightComponent"); - return; - }; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "setPosition"), + c +)] +fn set_position( + #[dropbear_macro::define(WorldPtr)] + world: &mut World, + #[dropbear_macro::entity] + entity: Entity, + position: &NVector3, +) -> DropbearNativeResult<()> { + set_transform_position(world, entity, (*position).into()) +} - light.enabled = enabled != 0; - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "getDirection"), + c +)] +fn get_direction( + #[dropbear_macro::define(WorldPtr)] + world: &World, + #[dropbear_macro::entity] + entity: Entity, +) -> DropbearNativeResult<NVector3> { + let transform = get_transform(world, entity)?; + let forward = DVec3::new(0.0, 0.0, -1.0); + let dir = (transform.rotation * forward).normalize_or_zero(); + Ok(NVector3::from(dir)) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_getCutoffAngle( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jdouble { - let world = convert_ptr!(world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let Ok(light) = world.get::<&LightComponent>(entity) else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing LightComponent"); - return f64::NAN; - }; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "setDirection"), + c +)] +fn set_direction( + #[dropbear_macro::define(WorldPtr)] + world: &mut World, + #[dropbear_macro::entity] + entity: Entity, + direction: &NVector3, +) -> DropbearNativeResult<()> { + let dir: DVec3 = (*direction).into(); + let desired = dir.normalize_or_zero(); + if desired.length_squared() < 1e-12 { + return Err(DropbearNativeError::InvalidArgument); + } + + let forward = DVec3::new(0.0, 0.0, -1.0); + let rotation = DQuat::from_rotation_arc(forward, desired); + set_transform_rotation(world, entity, rotation) +} - light.cutoff_angle as f64 - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "getColour"), + c +)] +fn get_colour( + #[dropbear_macro::define(WorldPtr)] + world: &World, + #[dropbear_macro::entity] + entity: Entity, +) -> DropbearNativeResult<NColour> { + let light = world + .get::<&LightComponent>(entity) + .map_err(|_| DropbearNativeError::MissingComponent)?; + Ok(NColour::from_linear_rgb(light.colour)) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_setCutoffAngle( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - cutoff_angle: jdouble, - ) { - let world = convert_ptr!(mut world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let Ok(mut light) = world.get::<&mut LightComponent>(entity) else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing LightComponent"); - return; - }; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "setColour"), + c +)] +fn set_colour( + #[dropbear_macro::define(WorldPtr)] + world: &mut World, + #[dropbear_macro::entity] + entity: Entity, + colour: &NColour, +) -> DropbearNativeResult<()> { + let mut light = world + .get::<&mut LightComponent>(entity) + .map_err(|_| DropbearNativeError::MissingComponent)?; + light.colour = (*colour).to_linear_rgb(); + Ok(()) +} - light.cutoff_angle = cutoff_angle as f32; - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "getLightType"), + c +)] +fn get_light_type( + #[dropbear_macro::define(WorldPtr)] + world: &World, + #[dropbear_macro::entity] + entity: Entity, +) -> DropbearNativeResult<i32> { + let light = world + .get::<&LightComponent>(entity) + .map_err(|_| DropbearNativeError::MissingComponent)?; + Ok(light.light_type as i32) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_getOuterCutoffAngle( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jdouble { - let world = convert_ptr!(world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let Ok(light) = world.get::<&LightComponent>(entity) else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing LightComponent"); - return f64::NAN; - }; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "setLightType"), + c +)] +fn set_light_type( + #[dropbear_macro::define(WorldPtr)] + world: &mut World, + #[dropbear_macro::entity] + entity: Entity, + light_type: i32, +) -> DropbearNativeResult<()> { + let mut light = world + .get::<&mut LightComponent>(entity) + .map_err(|_| DropbearNativeError::MissingComponent)?; + + light.light_type = match light_type { + 0 => LightType::Directional, + 1 => LightType::Point, + 2 => LightType::Spot, + _ => return Err(DropbearNativeError::InvalidArgument), + }; + + Ok(()) +} - light.outer_cutoff_angle as f64 - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "getIntensity"), + c +)] +fn get_intensity( + #[dropbear_macro::define(WorldPtr)] + world: &World, + #[dropbear_macro::entity] + entity: Entity, +) -> DropbearNativeResult<f64> { + let light = world + .get::<&LightComponent>(entity) + .map_err(|_| DropbearNativeError::MissingComponent)?; + Ok(light.intensity as f64) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_setOuterCutoffAngle( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - outer_cutoff_angle: jdouble, - ) { - let world = convert_ptr!(mut world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let Ok(mut light) = world.get::<&mut LightComponent>(entity) else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing LightComponent"); - return; - }; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "setIntensity"), + c +)] +fn set_intensity( + #[dropbear_macro::define(WorldPtr)] + world: &mut World, + #[dropbear_macro::entity] + entity: Entity, + intensity: f64, +) -> DropbearNativeResult<()> { + let mut light = world + .get::<&mut LightComponent>(entity) + .map_err(|_| DropbearNativeError::MissingComponent)?; + light.intensity = intensity as f32; + Ok(()) +} - light.outer_cutoff_angle = outer_cutoff_angle as f32; - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "getAttenuation"), + c +)] +fn get_attenuation( + #[dropbear_macro::define(WorldPtr)] + world: &World, + #[dropbear_macro::entity] + entity: Entity, +) -> DropbearNativeResult<NAttenuation> { + let light = world + .get::<&LightComponent>(entity) + .map_err(|_| DropbearNativeError::MissingComponent)?; + + Ok(NAttenuation { + constant: light.attenuation.constant, + linear: light.attenuation.linear, + quadratic: light.attenuation.quadratic, + }) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_getCastsShadows( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jboolean { - let world = convert_ptr!(world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let Ok(light) = world.get::<&LightComponent>(entity) else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing LightComponent"); - return 0; - }; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "setAttenuation"), + c +)] +fn set_attenuation( + #[dropbear_macro::define(WorldPtr)] + world: &mut World, + #[dropbear_macro::entity] + entity: Entity, + attenuation: &NAttenuation, +) -> DropbearNativeResult<()> { + let mut light = world + .get::<&mut LightComponent>(entity) + .map_err(|_| DropbearNativeError::MissingComponent)?; + + light.attenuation.constant = attenuation.constant; + light.attenuation.linear = attenuation.linear; + light.attenuation.quadratic = attenuation.quadratic; + Ok(()) +} - if light.cast_shadows { 1 } else { 0 } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "getEnabled"), + c +)] +fn get_enabled( + #[dropbear_macro::define(WorldPtr)] + world: &World, + #[dropbear_macro::entity] + entity: Entity, +) -> DropbearNativeResult<bool> { + let light = world + .get::<&LightComponent>(entity) + .map_err(|_| DropbearNativeError::MissingComponent)?; + Ok(light.enabled) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_setCastsShadows( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - casts_shadows: jboolean, - ) { - let world = convert_ptr!(mut world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let Ok(mut light) = world.get::<&mut LightComponent>(entity) else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing LightComponent"); - return; - }; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "setEnabled"), + c +)] +fn set_enabled( + #[dropbear_macro::define(WorldPtr)] + world: &mut World, + #[dropbear_macro::entity] + entity: Entity, + enabled: bool, +) -> DropbearNativeResult<()> { + let mut light = world + .get::<&mut LightComponent>(entity) + .map_err(|_| DropbearNativeError::MissingComponent)?; + light.enabled = enabled; + Ok(()) +} - light.cast_shadows = casts_shadows != 0; - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "getCutoffAngle"), + c +)] +fn get_cutoff_angle( + #[dropbear_macro::define(WorldPtr)] + world: &World, + #[dropbear_macro::entity] + entity: Entity, +) -> DropbearNativeResult<f64> { + let light = world + .get::<&LightComponent>(entity) + .map_err(|_| DropbearNativeError::MissingComponent)?; + Ok(light.cutoff_angle as f64) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_getDepth( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jobject { - let world = convert_ptr!(world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let Ok(light) = world.get::<&LightComponent>(entity) else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing LightComponent"); - return std::ptr::null_mut(); - }; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "setCutoffAngle"), + c +)] +fn set_cutoff_angle( + #[dropbear_macro::define(WorldPtr)] + world: &mut World, + #[dropbear_macro::entity] + entity: Entity, + cutoff_angle: f64, +) -> DropbearNativeResult<()> { + let mut light = world + .get::<&mut LightComponent>(entity) + .map_err(|_| DropbearNativeError::MissingComponent)?; + light.cutoff_angle = cutoff_angle as f32; + Ok(()) +} - let range = JvmRange { - start: light.depth.start, - end: light.depth.end, - }; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "getOuterCutoffAngle"), + c +)] +fn get_outer_cutoff_angle( + #[dropbear_macro::define(WorldPtr)] + world: &World, + #[dropbear_macro::entity] + entity: Entity, +) -> DropbearNativeResult<f64> { + let light = world + .get::<&LightComponent>(entity) + .map_err(|_| DropbearNativeError::MissingComponent)?; + Ok(light.outer_cutoff_angle as f64) +} - match range.to_jobject(&mut env) { - Ok(obj) => obj.into_raw(), - Err(_) => std::ptr::null_mut(), - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "setOuterCutoffAngle"), + c +)] +fn set_outer_cutoff_angle( + #[dropbear_macro::define(WorldPtr)] + world: &mut World, + #[dropbear_macro::entity] + entity: Entity, + outer_cutoff_angle: f64, +) -> DropbearNativeResult<()> { + let mut light = world + .get::<&mut LightComponent>(entity) + .map_err(|_| DropbearNativeError::MissingComponent)?; + light.outer_cutoff_angle = outer_cutoff_angle as f32; + Ok(()) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_lighting_LightNative_setDepth( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - depth: JObject, - ) { - let world = convert_ptr!(mut world_ptr => World); - let entity = convert_jlong_to_entity!(entity_id); - - let Ok(mut light) = world.get::<&mut LightComponent>(entity) else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity missing LightComponent"); - return; - }; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "getCastsShadows"), + c +)] +fn get_casts_shadows( + #[dropbear_macro::define(WorldPtr)] + world: &World, + #[dropbear_macro::entity] + entity: Entity, +) -> DropbearNativeResult<bool> { + let light = world + .get::<&LightComponent>(entity) + .map_err(|_| DropbearNativeError::MissingComponent)?; + Ok(light.cast_shadows) +} - let range = match JvmRange::from_jobject(&mut env, &depth) { - Ok(r) => r, - Err(e) => { - let _ = env.throw_new( - "java/lang/IllegalArgumentException", - format!("Invalid Range: {:?}", e), - ); - return; - } - }; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "setCastsShadows"), + c +)] +fn set_casts_shadows( + #[dropbear_macro::define(WorldPtr)] + world: &mut World, + #[dropbear_macro::entity] + entity: Entity, + casts_shadows: bool, +) -> DropbearNativeResult<()> { + let mut light = world + .get::<&mut LightComponent>(entity) + .map_err(|_| DropbearNativeError::MissingComponent)?; + light.cast_shadows = casts_shadows; + Ok(()) +} - if !(range.start.is_finite() && range.end.is_finite()) { - let _ = env.throw_new("java/lang/IllegalArgumentException", "Depth range must be finite"); - return; - } - if range.end <= range.start { - let _ = env.throw_new("java/lang/IllegalArgumentException", "Depth range must satisfy start < end"); - return; - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "getDepth"), + c +)] +fn get_depth( + #[dropbear_macro::define(WorldPtr)] + world: &World, + #[dropbear_macro::entity] + entity: Entity, +) -> DropbearNativeResult<NRange> { + let light = world + .get::<&LightComponent>(entity) + .map_err(|_| DropbearNativeError::MissingComponent)?; + + Ok(NRange { + start: light.depth.start, + end: light.depth.end, + }) +} - light.depth = range.start..range.end; - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.lighting.LightNative", func = "setDepth"), + c +)] +fn set_depth( + #[dropbear_macro::define(WorldPtr)] + world: &mut World, + #[dropbear_macro::entity] + entity: Entity, + depth: &NRange, +) -> DropbearNativeResult<()> { + if !(depth.start.is_finite() && depth.end.is_finite()) { + return Err(DropbearNativeError::InvalidArgument); + } + if depth.end <= depth.start { + return Err(DropbearNativeError::InvalidArgument); + } + + let mut light = world + .get::<&mut LightComponent>(entity) + .map_err(|_| DropbearNativeError::MissingComponent)?; + light.depth = depth.start..depth.end; + Ok(()) } @@ -1,427 +1,263 @@ pub mod shared { + use dropbear_engine::asset::AssetRegistry; use dropbear_engine::entity::MeshRenderer; + use dropbear_engine::model::Model; use hecs::{Entity, World}; pub fn mesh_renderer_exists_for_entity(world: &World, entity: Entity) -> bool { world.get::<&MeshRenderer>(entity).is_ok() } - pub fn resolve_target_material_name( - renderer: &MeshRenderer, - target_identifier: &str - ) -> Option<String> { - if let Some(cached) = renderer.resolve_texture_identifier(target_identifier) { - return Some(cached.to_string()); - } - - let model = renderer.model(); - - model.materials.iter().find_map(|mat| { - if mat.name == target_identifier { return Some(mat.name.clone()); } - if let Some(tag) = &mat.texture_tag { if tag == target_identifier { return Some(mat.name.clone()); } } - None - }) + fn matches_material_label(material: &dropbear_engine::model::Material, target: &str) -> bool { + material.texture_tag.as_deref() == Some(target) || material.name == target } -} - -pub mod jni { - #![allow(non_snake_case)] - use crate::return_boxed; - use dropbear_engine::asset::PointerKind::Const; - use dropbear_engine::asset::{AssetHandle, AssetRegistry}; - use dropbear_engine::entity::MeshRenderer; - use dropbear_engine::model::Model; - use hecs::World; - use jni::objects::{JClass, JString}; - use jni::sys::{jboolean, jlong, jlongArray, jobject, jsize}; - use jni::JNIEnv; - use parking_lot::Mutex; - use std::collections::HashMap; - use std::sync::Arc; - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_MeshRendererNative_meshRendererExistsForEntity( - _env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jboolean { - let world = crate::convert_ptr!(world_ptr => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - super::shared::mesh_renderer_exists_for_entity(&world, entity) as jboolean - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_MeshRendererNative_getModel( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jlong { - let world = crate::convert_ptr!(world_ptr => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - - if let Ok(mesh) = world.get::<&MeshRenderer>(entity) { - mesh.model_id().raw() as jlong - } else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity does not have a MeshRenderer component"); - -1 - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_MeshRendererNative_setModel( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - asset_ptr: jlong, - entity_id: jlong, - model_id: jlong, - ) { - let world = crate::convert_ptr!(world_ptr => World); - let asset = crate::convert_ptr!(asset_ptr => AssetRegistry); - let entity = crate::convert_jlong_to_entity!(entity_id); - - if let Ok(mut mesh) = world.get::<&mut MeshRenderer>(entity) { - match mesh.set_asset_handle_raw(asset, AssetHandle::new(model_id as u32)) { - Ok(_) => {} - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to set model: {}", e)); - } - } - } else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity does not have a MeshRenderer component"); - } + pub fn resolve_target_material_index( + model: &Model, + target_identifier: &str, + ) -> Option<usize> { + model + .materials + .iter() + .position(|mat| matches_material_label(mat, target_identifier)) } - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_MeshRendererNative_getAllTextureIds( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - asset_ptr: jlong, - entity_id: jlong, - ) -> jlongArray { - let world = crate::convert_ptr!(world_ptr => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - let asset = crate::convert_ptr!(asset_ptr => AssetRegistry); - - if let Ok(renderer) = world.get::<&mut MeshRenderer>(entity) { - let handles = renderer.collect_all_material_handles_raw(&asset); - let jarray = match env.new_long_array(handles.len() as jsize) { - Ok(val) => val, - Err(_) => { - let _ = env.throw_new("java/lang/OutOfMemoryError", "Could not allocate texture ID array"); - return std::ptr::null_mut(); - } - }; - - if let Err(e) = env.set_long_array_region(&jarray, 0, handles.iter().map(|v| v.raw() as jlong).collect::<Vec<_>>().as_slice()) { - let _ = env.throw_new("java/lang/RuntimeException", format!("{:?}", e)); - return std::ptr::null_mut(); - } - - jarray.into_raw() - } else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity does not have a MeshRenderer component"); - std::ptr::null_mut() - } + pub fn resolve_target_material_name( + model: &Model, + target_identifier: &str, + ) -> Option<String> { + model + .materials + .iter() + .find(|mat| matches_material_label(mat, target_identifier)) + .map(|mat| mat.name.clone()) } - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_MeshRendererNative_getTexture( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - asset_ptr: jlong, - entity_id: jlong, - material_name: JString, - ) -> jobject { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let asset = crate::convert_ptr!(asset_ptr => dropbear_engine::asset::AssetRegistry); - let entity = crate::convert_jlong_to_entity!(entity_id); - let name = crate::convert_jstring!(env, material_name); - - let handle_value: Option<i64> = if let Ok(renderer) = world.get::<&dropbear_engine::entity::MeshRenderer>(entity) { - renderer.material_handle_raw(asset, &name) - .map(|h| h.raw() as i64) - } else { - None - }; - - return_boxed!(&mut env, handle_value, "(J)Ljava/lang/Long;", "java/lang/Long") + pub fn model_for_renderer<'a>( + registry: &'a AssetRegistry, + renderer: &MeshRenderer, + ) -> Option<&'a Model> { + registry.get_model(renderer.model()) } +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_MeshRendererNative_setTextureOverride( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - asset_handle: jlong, - entity_id: jlong, - material_name: JString, - texture_handle: jlong, - ) { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let asset = crate::convert_ptr!(asset_handle => dropbear_engine::asset::AssetRegistry); - let entity = crate::convert_jlong_to_entity!(entity_id); - let target_identifier = crate::convert_jstring!(env, material_name); - let new_texture_handle = dropbear_engine::asset::AssetHandle::new(texture_handle as u64); - - if let Ok(mut mesh) = world.get::<&mut dropbear_engine::entity::MeshRenderer>(entity) { - let resolved_target = super::shared::resolve_target_material_name(&mesh, &target_identifier); - - let Some(target_material_name) = resolved_target else { - let _ = env.throw_new( - "java/lang/IllegalArgumentException", - format!( - "Could not resolve material identifier '{}' on model '{}'", - target_identifier, - mesh.model().label - ), - ); - return; - }; - - if !asset.contains_handle(new_texture_handle) { - let _ = env.throw_new("java/lang/IllegalArgumentException", "Invalid texture handle provided"); - return; - } - - if !asset.is_material(new_texture_handle) { - let _ = env.throw_new("java/lang/IllegalArgumentException", "Handle provided is not a material/texture"); - return; - } - - let Some(source_material) = asset.get_material(new_texture_handle) else { return; }; - - let Some(owner_model_id) = asset.material_owner(new_texture_handle) else { - let _ = env.throw_new("java/lang/IllegalStateException", "Texture handle has no owner model in registry"); - return; - }; - - let Some(owner_model_handle) = asset.model_handle_from_id(owner_model_id) else { - let _ = env.throw_new("java/lang/IllegalStateException", "Texture owner model not found in registry"); - return; - }; - - let Some(source_reference) = asset.model_reference_for_handle(owner_model_handle) else { - let _ = env.throw_new("java/lang/IllegalStateException", "Texture owner model has no resource reference"); - return; - }; - - let Some(model_cache) = asset.get_pointer(Const("model_cache")) else { - let _ = env.throw_new("java/lang/IllegalArgumentException", "Unable to locate model_cache pointer within the asset registry"); - return; - }; - - let model_cache = model_cache as *const Mutex<HashMap<String, Arc<Model>>>; - if model_cache.is_null() { - let _ = env.throw_new("java/lang/IllegalStateException", "Model cache cannot be null"); - return; - } - - let model_cache = unsafe { &*model_cache }; - - if let Err(e) = mesh.apply_material_override_raw( - asset, - model_cache, - &target_material_name, - source_reference, - &source_material.name, - ) { - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to apply texture override: {}", e)); - } +use crate::ptr::{AssetRegistryPtr, AssetRegistryUnwrapped, GraphicsContextPtr, WorldPtr}; +use crate::scripting::native::DropbearNativeError; +use crate::scripting::result::DropbearNativeResult; +use dropbear_engine::asset::Handle; +use dropbear_engine::entity::MeshRenderer; +use dropbear_engine::graphics::SharedGraphicsContext; +use dropbear_engine::texture::Texture; +use std::collections::HashSet; + +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.MeshRendererNative", func = "meshRendererExistsForEntity") +)] +fn mesh_renderer_exists_for_entity( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::entity] + entity: hecs::Entity, +) -> DropbearNativeResult<bool> { + Ok(shared::mesh_renderer_exists_for_entity(world, entity)) +} - } else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity does not have a MeshRenderer component"); - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.MeshRendererNative", func = "getModel") +)] +fn get_model( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::entity] + entity: hecs::Entity, +) -> DropbearNativeResult<u64> { + if let Ok(mesh) = world.get::<&MeshRenderer>(entity) { + Ok(mesh.model().id) + } else { + Err(DropbearNativeError::NoSuchComponent) } } -#[dropbear_macro::impl_c_api] -pub mod native { - use parking_lot::Mutex; - use std::collections::HashMap; - use std::os::raw::c_char; - use std::sync::Arc; - - use hecs::{Entity, World}; - - use dropbear_engine::asset::{AssetHandle, AssetRegistry, PointerKind}; - use dropbear_engine::entity::MeshRenderer; - use dropbear_engine::model::Model; - - use crate::convert_ptr; - use crate::engine::shared::read_str; - use crate::ptr::{AssetRegistryPtr, WorldPtr}; - use crate::scripting::native::DropbearNativeError; - use crate::scripting::result::DropbearNativeResult; - - pub fn dropbear_mesh_renderer_exists_for_entity( - world_ptr: WorldPtr, - entity_id: u64, - ) -> DropbearNativeResult<bool> { - let world = convert_ptr!(world_ptr => World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - DropbearNativeResult::Ok(super::shared::mesh_renderer_exists_for_entity(world, entity)) +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.MeshRendererNative", func = "setModel") +)] +fn set_model( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::define(AssetRegistryPtr)] + asset: &AssetRegistryUnwrapped, + #[dropbear_macro::entity] + entity: hecs::Entity, + model_handle: u64, +) -> DropbearNativeResult<()> { + let handle = Handle::new(model_handle); + if asset.read().get_model(handle).is_none() { + return Err(DropbearNativeError::InvalidHandle); } - - pub fn dropbear_get_model( - world_ptr: WorldPtr, - entity_id: u64, - ) -> DropbearNativeResult<u64> { - let world = convert_ptr!(world_ptr => World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - if let Ok(mesh) = world.get::<&MeshRenderer>(entity) { - DropbearNativeResult::Ok(mesh.model_id().raw()) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } + if let Ok(mut mesh) = world.get::<&mut MeshRenderer>(entity) { + mesh.set_model(handle); + Ok(()) + } else { + Err(DropbearNativeError::NoSuchComponent) } - - pub fn dropbear_set_model( - world_ptr: WorldPtr, - asset_ptr: AssetRegistryPtr, - entity_id: u64, - model_id: u64, - ) -> DropbearNativeResult<()> { - let world = convert_ptr!(world_ptr => World); - let asset = convert_ptr!(asset_ptr => AssetRegistry); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; +} - if let Ok(mut mesh) = world.get::<&mut MeshRenderer>(entity) { - match mesh.set_asset_handle_raw(asset, AssetHandle::new(model_id)) { - Ok(_) => DropbearNativeResult::Ok(()), - Err(_) => DropbearNativeResult::Err(DropbearNativeError::UnknownError), +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.MeshRendererNative", func = "getAllTextureIds") +)] +fn get_all_texture_ids( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::define(AssetRegistryPtr)] + asset: &AssetRegistryUnwrapped, + #[dropbear_macro::entity] + entity: hecs::Entity, +) -> DropbearNativeResult<Vec<u64>> { + let reader = asset.read(); + let renderer = world + .get::<&MeshRenderer>(entity) + .map_err(|_| DropbearNativeError::NoSuchComponent)?; + let model = shared::model_for_renderer(&reader, &renderer) + .ok_or(DropbearNativeError::AssetNotFound)?; + + let mut ids = HashSet::new(); + let mut push_handle = |texture: &Texture| { + if let Some(hash) = texture.hash { + if let Some(handle) = reader.texture_handle_by_hash(hash) { + ids.insert(handle.id); } - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) } - } - - pub fn dropbear_get_all_texture_ids( - world_ptr: WorldPtr, - asset_ptr: AssetRegistryPtr, - entity_id: u64, - out_count: *mut usize, - ) -> DropbearNativeResult<*mut u64> { - let world = convert_ptr!(world_ptr => World); - let asset = convert_ptr!(asset_ptr => AssetRegistry); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; + }; - if out_count.is_null() { - return DropbearNativeResult::Err(DropbearNativeError::NullPointer); + for material in &model.materials { + push_handle(&material.diffuse_texture); + push_handle(&material.normal_texture); + if let Some(tex) = &material.emissive_texture { + push_handle(tex); } - - if let Ok(renderer) = world.get::<&MeshRenderer>(entity) { - let handles = renderer.collect_all_material_handles_raw(asset); - - let mut raw_ids: Vec<u64> = handles.iter().map(|h| h.raw()).collect(); - - unsafe { *out_count = raw_ids.len(); } - - let ptr = raw_ids.as_mut_ptr(); - std::mem::forget(raw_ids); - - DropbearNativeResult::Ok(ptr) - } else { - unsafe { *out_count = 0; } - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) + if let Some(tex) = &material.metallic_roughness_texture { + push_handle(tex); } - } - - pub fn dropbear_get_texture( - world_ptr: WorldPtr, - asset_ptr: AssetRegistryPtr, - entity_id: u64, - material_name: *const c_char, - ) -> DropbearNativeResult<u64> { - let world = convert_ptr!(world_ptr => World); - let asset = convert_ptr!(asset_ptr => AssetRegistry); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - let target = unsafe { read_str(material_name)? }; - - if let Ok(renderer) = world.get::<&MeshRenderer>(entity) { - match renderer.material_handle_raw(asset, &target) { - Some(handle) => DropbearNativeResult::Ok(handle.raw()), - None => DropbearNativeResult::Err(DropbearNativeError::UnknownError), - } - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) + if let Some(tex) = &material.occlusion_texture { + push_handle(tex); } } - - pub fn dropbear_set_texture_override( - world_ptr: WorldPtr, - asset_ptr: AssetRegistryPtr, - entity_id: u64, - material_name: *const c_char, - texture_handle: u64, - ) -> DropbearNativeResult<()> { - let world = convert_ptr!(world_ptr => World); - let asset = convert_ptr!(asset_ptr => AssetRegistry); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - let target_identifier = unsafe { read_str(material_name)? }; - let new_texture_handle = AssetHandle::new(texture_handle); - - if let Ok(mut mesh) = world.get::<&mut MeshRenderer>(entity) { - let resolved_target = super::shared::resolve_target_material_name(&mesh, &target_identifier); - let target_material_name = match resolved_target { - Some(name) => name, - None => return DropbearNativeResult::Err(DropbearNativeError::InvalidArgument), - }; - - if !asset.contains_handle(new_texture_handle) || !asset.is_material(new_texture_handle) { - return DropbearNativeResult::Err(DropbearNativeError::InvalidArgument); - } - - let source_material = match asset.get_material(new_texture_handle) { - Some(m) => m, - None => return DropbearNativeResult::Err(DropbearNativeError::UnknownError), - }; - let owner_model_id = match asset.material_owner(new_texture_handle) { - Some(id) => id, - None => return DropbearNativeResult::Err(DropbearNativeError::QueryFailed), - }; - - let owner_model_handle = match asset.model_handle_from_id(owner_model_id) { - Some(h) => h, - None => return DropbearNativeResult::Err(DropbearNativeError::QueryFailed), - }; - - let source_reference = match asset.model_reference_for_handle(owner_model_handle) { - Some(r) => r, - None => return DropbearNativeResult::Err(DropbearNativeError::QueryFailed), - }; + Ok(ids.into_iter().collect()) +} - let model_cache_ptr = match asset.get_pointer(PointerKind::Const("model_cache")) { - Some(ptr) => ptr as *const Mutex<HashMap<String, Arc<Model>>>, - None => return DropbearNativeResult::Err(DropbearNativeError::NullPointer), // Cache not found - }; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.MeshRendererNative", func = "getTexture"), + c +)] +fn get_texture( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::define(AssetRegistryPtr)] + asset: &AssetRegistryUnwrapped, + #[dropbear_macro::entity] + entity: hecs::Entity, + material_name: String, +) -> DropbearNativeResult<Option<u64>> { + let reader = asset.read(); + let renderer = world + .get::<&MeshRenderer>(entity) + .map_err(|_| DropbearNativeError::NoSuchComponent)?; + let model = shared::model_for_renderer(&reader, &renderer) + .ok_or(DropbearNativeError::AssetNotFound)?; + let idx = match shared::resolve_target_material_index(model, &material_name) { + Some(value) => value, + None => return Ok(None), + }; + let material = model + .materials + .get(idx) + .ok_or(DropbearNativeError::InvalidArgument)?; + + Ok(material + .diffuse_texture + .hash + .and_then(|hash| reader.texture_handle_by_hash(hash)) + .map(|handle| handle.id)) +} - if model_cache_ptr.is_null() { - return DropbearNativeResult::Err(DropbearNativeError::NullPointer); - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.MeshRendererNative", func = "setTextureOverride"), + c +)] +fn set_texture_override( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::define(AssetRegistryPtr)] + asset: &AssetRegistryUnwrapped, + #[dropbear_macro::entity] + entity: hecs::Entity, + material_name: String, + texture_handle: u64, +) -> DropbearNativeResult<()> { + let reader = asset.read(); + let renderer = world + .get::<&MeshRenderer>(entity) + .map_err(|_| DropbearNativeError::NoSuchComponent)?; + let model = shared::model_for_renderer(&reader, &renderer) + .ok_or(DropbearNativeError::AssetNotFound)?; + let _ = shared::resolve_target_material_name(model, &material_name) + .ok_or(DropbearNativeError::InvalidArgument)?; + + let handle = Handle::<dropbear_engine::texture::Texture>::new(texture_handle); + if reader.get_texture(handle).is_none() { + return Err(DropbearNativeError::InvalidHandle); + } - let model_cache = unsafe { &*model_cache_ptr }; + drop(reader); - match mesh.apply_material_override_raw( - asset, - model_cache, - &target_material_name, - source_reference, - &source_material.name, - ) { - Ok(_) => DropbearNativeResult::Ok(()), - Err(_) => DropbearNativeResult::Err(DropbearNativeError::WorldInsertError), - } + let mut renderer = world + .get::<&mut MeshRenderer>(entity) + .map_err(|_| DropbearNativeError::NoSuchComponent)?; + renderer.set_texture_override(handle); + Ok(()) +} - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.MeshRendererNative", func = "setMaterialTint"), + c +)] +fn set_material_tint( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::define(AssetRegistryPtr)] + asset: &AssetRegistryUnwrapped, + #[dropbear_macro::define(GraphicsContextPtr)] + graphics: &SharedGraphicsContext, + #[dropbear_macro::entity] + entity: hecs::Entity, + material_name: String, + r: f32, + g: f32, + b: f32, + a: f32, +) -> DropbearNativeResult<()> { + let renderer = world + .get::<&MeshRenderer>(entity) + .map_err(|_| DropbearNativeError::NoSuchComponent)?; + let handle = renderer.model(); + + let mut registry = asset.write(); + let model = registry + .get_model(handle) + .cloned() + .ok_or(DropbearNativeError::AssetNotFound)?; + let mut model = model; + + let index = shared::resolve_target_material_index(&model, &material_name) + .ok_or(DropbearNativeError::InvalidArgument)?; + + if let Some(material) = model.materials.get_mut(index) { + material.tint = [r, g, b, a]; + material.sync_uniform(graphics); } + + registry.update_model(handle, model); + Ok(()) } @@ -9,6 +9,10 @@ use rapier3d::prelude::*; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use rapier3d::control::CharacterCollision; +use rapier3d::parry::query::{DefaultQueryDispatcher, ShapeCastOptions}; +use crate::ptr::PhysicsStatePtr; +use crate::scripting::result::DropbearNativeResult; +use crate::types::{IndexNative, NVector3, RayHit, NShapeCastHit, NCollider}; pub mod rigidbody; pub mod collider; @@ -328,383 +332,245 @@ pub mod shared { } } -pub mod jni { - #![allow(non_snake_case)] - - use crate::physics::nalgebra; - use crate::physics::PhysicsState; - use crate::scripting::jni::utils::{FromJObject, ToJObject}; - use crate::types::{NCollider, IndexNative, RayHit, ShapeCastHitFFI, NVector3}; - use hecs::Entity; - use jni::objects::{JClass, JObject}; - use jni::sys::{jboolean, jdouble, jlong, jobject}; - use jni::JNIEnv; - use rapier3d::parry::query::DefaultQueryDispatcher; - use rapier3d::pipeline::QueryFilter; - use rapier3d::prelude::{point, vector, Ray}; - use rapier3d::parry::query::ShapeCastOptions; - use rapier3d::math::{Pose3, Vec3}; - use crate::physics::collider::ColliderShape; - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_PhysicsNative_getGravity( - mut env: JNIEnv, - _: JClass, - physics_handle: jlong, - ) -> jobject { - let physics = crate::convert_ptr!(physics_handle => PhysicsState); - - match super::shared::get_gravity(&physics).to_jobject(&mut env) { - Ok(v) => v.into_raw(), - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Unable to create new Vector3d object for gravity: {}", e)); - std::ptr::null_mut() - } - } - - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_PhysicsNative_setGravity( - mut env: JNIEnv, - _: JClass, - physics_handle: jlong, - new_gravity: JObject, - ) { - let mut physics = crate::convert_ptr!(mut physics_handle => PhysicsState); - let vec3 = match NVector3::from_jobject(&mut env, &new_gravity) { - Ok(v) => v, - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Unable to create new Vector3d object for gravity: {}", e)); - return; - } - }; - - super::shared::set_gravity(&mut physics, vec3); - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_PhysicsNative_raycast( - mut env: JNIEnv, - _: JClass, - physics_handle: jlong, - origin: JObject, - direction: JObject, - time_of_impact: jdouble, - solid: jboolean, - ) -> jobject { - let physics = crate::convert_ptr!(mut physics_handle => PhysicsState); - - let qp = physics.broad_phase.as_query_pipeline(&DefaultQueryDispatcher, &physics.bodies, &physics.colliders, QueryFilter::new()); - - let origin = match NVector3::from_jobject(&mut env, &origin) { - Ok(v) => v, - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Unable to create a new rust Vector3 object: {}", e)); - return std::ptr::null_mut(); - } - }; - - let dir = match NVector3::from_jobject(&mut env, &direction) { - Ok(v) => v, - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Unable to create a new rust Vector3 object: {}", e)); - return std::ptr::null_mut(); - } - }; - - let ray = Ray::new( - point![origin.x as f32, origin.y as f32, origin.z as f32].into(), - vector![dir.x as f32, dir.y as f32, dir.z as f32].into(), - ); - - if let Some((hit, distance)) = qp.cast_ray(&ray, time_of_impact as f32, solid != 0) { - let raw = hit.0; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.PhysicsNative", func = "getGravity"), + c +)] +fn get_gravity( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, +) -> DropbearNativeResult<NVector3> { + Ok(shared::get_gravity(physics)) +} - let mut found = None; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.PhysicsNative", func = "setGravity"), + c +)] +fn set_gravity( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + gravity: &NVector3, +) -> DropbearNativeResult<()> { + Ok(shared::set_gravity(physics, *gravity)) +} - for (l, colliders) in physics.colliders_entity_map.iter() { - for (_, c) in colliders { - if c.0 == hit.0 { - found = Some((l, c.0)); - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.PhysicsNative", func = "raycast"), + c +)] +fn raycast( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + origin: &NVector3, + dir: &NVector3, + time_of_impact: f64, + solid: bool, +) -> DropbearNativeResult<Option<RayHit>> { + let qp = physics.broad_phase.as_query_pipeline(&DefaultQueryDispatcher, &physics.bodies, &physics.colliders, QueryFilter::new()); + + let ray = Ray::new( + point![origin.x as f32, origin.y as f32, origin.z as f32].into(), + vector![dir.x as f32, dir.y as f32, dir.z as f32].into(), + ); + + if let Some((hit, distance)) = qp.cast_ray(&ray, time_of_impact as f32, solid) { + let raw = hit.0; + + let mut found = None; + + for (l, colliders) in physics.colliders_entity_map.iter() { + for (_, c) in colliders { + if c.0 == hit.0 { + found = Some((l, c.0)); } } + } - if let Some((label, _)) = found { - let entity = physics.entity_label_map.iter().find(|(_, l)| *l == label); - if let Some((e, _)) = entity { - let rayhit = RayHit { - collider: crate::types::NCollider { - index: IndexNative::from(raw), - entity_id: e.to_bits().get(), - id: raw.into_raw_parts().0, - }, - distance: distance as f64, - }; - - match rayhit.to_jobject(&mut env) { - Ok(v) => v.into_raw(), - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Unable to create a new rust RayHit object: {}", e)); - return std::ptr::null_mut(); - } - } - } else { - std::ptr::null_mut() - } - } else { - eprintln!("Unknown collider, still returning value without entity_id"); - + if let Some((label, _)) = found { + let entity = physics.entity_label_map.iter().find(|(_, l)| *l == label); + if let Some((e, _)) = entity { let rayhit = RayHit { collider: crate::types::NCollider { index: IndexNative::from(raw), - entity_id: Entity::DANGLING.to_bits().get(), + entity_id: e.to_bits().get(), id: raw.into_raw_parts().0, }, distance: distance as f64, }; - match rayhit.to_jobject(&mut env) { - Ok(v) => v.into_raw(), - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Unable to create a new rust RayHit object: {}", e)); - return std::ptr::null_mut(); - } - } + Ok(Some(rayhit)) + } else { + Ok(None) } } else { - std::ptr::null_mut() + eprintln!("Unknown collider, still returning value without entity_id"); + + let rayhit = RayHit { + collider: crate::types::NCollider { + index: IndexNative::from(raw), + entity_id: Entity::DANGLING.to_bits().get(), + id: raw.into_raw_parts().0, + }, + distance: distance as f64, + }; + Ok(Some(rayhit)) + } + } else { + Ok(None) } +} - fn collider_ffi_from_handle(physics: &PhysicsState, handle: rapier3d::prelude::ColliderHandle) -> NCollider { - let (idx, generation) = handle.into_raw_parts(); - - let mut found_label = None; - for (label, colliders) in physics.colliders_entity_map.iter() { - for (_, c) in colliders { - if c.0 == handle.0 { - found_label = Some(label); - break; - } - } - if found_label.is_some() { - break; - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.PhysicsNative", func = "shapeCast"), + c +)] +fn shape_cast( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + origin: &NVector3, + direction: &NVector3, + shape: &collider::ColliderShape, + time_of_impact: f64, + solid: bool, +) -> DropbearNativeResult<Option<NShapeCastHit>> { + let qp = physics.broad_phase.as_query_pipeline( + &DefaultQueryDispatcher, + &physics.bodies, + &physics.colliders, + QueryFilter::new(), + ); + + let dir_len = ((direction.x * direction.x) + (direction.y * direction.y) + (direction.z * direction.z)).sqrt(); + if dir_len <= f64::EPSILON { + return Ok(None); + } - let entity_id = if let Some(label) = found_label { - physics - .entity_label_map - .iter() - .find(|(_, l)| *l == label) - .map(|(e, _)| e.to_bits().get()) - .unwrap_or(Entity::DANGLING.to_bits().get()) - } else { - Entity::DANGLING.to_bits().get() - }; + let dir_unit = NVector3 { + x: direction.x / dir_len, + y: direction.y / dir_len, + z: direction.z / dir_len, + }; - NCollider { - index: IndexNative { index: idx, generation }, - entity_id, - id: idx, - } - } - fn shared_shape_from_collider_shape(shape: &ColliderShape) -> rapier3d::geometry::SharedShape { + let cast_shape = { match shape { - ColliderShape::Box { half_extents } => { + crate::physics::collider::ColliderShape::Box { half_extents } => { rapier3d::geometry::SharedShape::cuboid(half_extents[0], half_extents[1], half_extents[2]) } - ColliderShape::Sphere { radius } => rapier3d::geometry::SharedShape::ball(*radius), - ColliderShape::Capsule { half_height, radius } => { + crate::physics::collider::ColliderShape::Sphere { radius } => rapier3d::geometry::SharedShape::ball(*radius), + crate::physics::collider::ColliderShape::Capsule { half_height, radius } => { rapier3d::geometry::SharedShape::capsule_y(*half_height, *radius) } - ColliderShape::Cylinder { half_height, radius } => { + crate::physics::collider::ColliderShape::Cylinder { half_height, radius } => { rapier3d::geometry::SharedShape::cylinder(*half_height, *radius) } - ColliderShape::Cone { half_height, radius } => { + crate::physics::collider::ColliderShape::Cone { half_height, radius } => { rapier3d::geometry::SharedShape::cone(*half_height, *radius) } } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_PhysicsNative_shapeCast( - mut env: JNIEnv, - _: JClass, - physics_handle: jlong, - origin: JObject, - direction: JObject, - shape: JObject, - time_of_impact: jdouble, - solid: jboolean, - ) -> jobject { - let physics = crate::convert_ptr!(mut physics_handle => PhysicsState); - - let qp = physics.broad_phase.as_query_pipeline( - &DefaultQueryDispatcher, - &physics.bodies, - &physics.colliders, - QueryFilter::new(), - ); - - let origin = match NVector3::from_jobject(&mut env, &origin) { - Ok(v) => v, - Err(e) => { - let _ = env.throw_new( - "java/lang/RuntimeException", - format!("Unable to convert origin to Vector3: {e}"), - ); - return std::ptr::null_mut(); - } - }; - - let direction = match NVector3::from_jobject(&mut env, &direction) { - Ok(v) => v, - Err(e) => { - let _ = env.throw_new( - "java/lang/RuntimeException", - format!("Unable to convert direction to Vector3: {e}"), - ); - return std::ptr::null_mut(); - } - }; - - let shape = match ColliderShape::from_jobject(&mut env, &shape) { - Ok(v) => v, - Err(e) => { - let _ = env.throw_new( - "java/lang/RuntimeException", - format!("Unable to convert shape to ColliderShape: {e}"), - ); - return std::ptr::null_mut(); - } - }; - - let dir_len = ((direction.x * direction.x) + (direction.y * direction.y) + (direction.z * direction.z)).sqrt(); - if dir_len <= f64::EPSILON { - return std::ptr::null_mut(); - } - - let dir_unit = NVector3 { - x: direction.x / dir_len, - y: direction.y / dir_len, - z: direction.z / dir_len, - }; - - let cast_shape = shared_shape_from_collider_shape(&shape); - let iso: Pose3 = nalgebra::Isometry3::translation(origin.x as f32, origin.y as f32, origin.z as f32).into(); - let vel: Vec3 = vector![dir_unit.x as f32, dir_unit.y as f32, dir_unit.z as f32].into(); + }; + let iso: Pose3 = nalgebra::Isometry3::translation(origin.x as f32, origin.y as f32, origin.z as f32).into(); + let vel: Vec3 = vector![dir_unit.x as f32, dir_unit.y as f32, dir_unit.z as f32].into(); + + let options = ShapeCastOptions { + max_time_of_impact: time_of_impact as f32, + target_distance: 0.0, + stop_at_penetration: solid, + compute_impact_geometry_on_penetration: true, + }; + + let Some((hit_handle, toi)) = qp.cast_shape(&iso, vel, cast_shape.as_ref(), options) else { + return Ok(None); + }; + + let collider = collider_ffi_from_handle(&physics, hit_handle); + + let hit = NShapeCastHit { + collider, + distance: toi.time_of_impact as f64, + witness1: NVector3::from([toi.witness1.x, toi.witness1.y, toi.witness1.z]), + witness2: NVector3::from([toi.witness2.x, toi.witness2.y, toi.witness2.z]), + normal1: NVector3::from([toi.normal1.x, toi.normal1.y, toi.normal1.z]), + normal2: NVector3::from([toi.normal2.x, toi.normal2.y, toi.normal2.z]), + status: toi.status.into(), + }; + + Ok(Some(hit)) +} - let options = ShapeCastOptions { - max_time_of_impact: time_of_impact as f32, - target_distance: 0.0, - stop_at_penetration: solid != 0, - compute_impact_geometry_on_penetration: true, - }; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.PhysicsNative", func = "isOverlapping"), + c +)] +fn is_overlapping( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + collider1: &NCollider, + collider2: &NCollider, +) -> DropbearNativeResult<bool> { + Ok(shared::overlapping(physics, collider1, collider2)) +} - let Some((hit_handle, toi)) = qp.cast_shape(&iso, vel, cast_shape.as_ref(), options) else { - return std::ptr::null_mut(); - }; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.PhysicsNative", func = "isTriggering"), + c +)] +fn is_triggering( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + collider1: &NCollider, + collider2: &NCollider, +) -> DropbearNativeResult<bool> { + Ok(shared::triggering(physics, collider1, collider2)) +} - let collider = collider_ffi_from_handle(&physics, hit_handle); +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.PhysicsNative", func = "isTouching"), + c +)] +fn is_touching( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + #[dropbear_macro::entity] + entity1: Entity, + #[dropbear_macro::entity] + entity2: Entity, +) -> DropbearNativeResult<bool> { + Ok(shared::touching(physics, entity1, entity2)) +} - let hit = ShapeCastHitFFI { - collider, - distance: toi.time_of_impact as f64, - witness1: NVector3::from([toi.witness1.x, toi.witness1.y, toi.witness1.z]), - witness2: NVector3::from([toi.witness2.x, toi.witness2.y, toi.witness2.z]), - normal1: NVector3::from([toi.normal1.x, toi.normal1.y, toi.normal1.z]), - normal2: NVector3::from([toi.normal2.x, toi.normal2.y, toi.normal2.z]), - status: toi.status, - }; +fn collider_ffi_from_handle(physics: &PhysicsState, handle: rapier3d::prelude::ColliderHandle) -> NCollider { + let (idx, generation) = handle.into_raw_parts(); - match hit.to_jobject(&mut env) { - Ok(v) => v.into_raw(), - Err(e) => { - let _ = env.throw_new( - "java/lang/RuntimeException", - format!("Unable to create ShapeCastHit object: {e}"), - ); - std::ptr::null_mut() + let mut found_label = None; + for (label, colliders) in physics.colliders_entity_map.iter() { + for (_, c) in colliders { + if c.0 == handle.0 { + found_label = Some(label); + break; } } + if found_label.is_some() { + break; + } } - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_PhysicsNative_isOverlapping( - mut env: JNIEnv, - _: JClass, - physics_handle: jlong, - collider1: JObject, - collider2: JObject, - ) -> jboolean { - let physics = crate::convert_ptr!(physics_handle => PhysicsState); - let Ok(collider1) = NCollider::from_jobject(&mut env, &collider1) else { - let _ = env.throw_new( - "java/lang/RuntimeException", - "Unable to convert a Collider object [collider1] to a rust ColliderFFI" - ); - return false.into(); - }; - - let Ok(collider2) = NCollider::from_jobject(&mut env, &collider2) else { - let _ = env.throw_new( - "java/lang/RuntimeException", - "Unable to convert a Collider object [collider2] to a rust ColliderFFI" - ); - return false.into(); - }; - - super::shared::overlapping(&physics, &collider1, &collider2).into() - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_PhysicsNative_isTriggering( - mut env: JNIEnv, - _: JClass, - physics_handle: jlong, - collider1: JObject, - collider2: JObject, - ) -> jboolean { - let physics = crate::convert_ptr!(physics_handle => PhysicsState); - let Ok(collider1) = NCollider::from_jobject(&mut env, &collider1) else { - let _ = env.throw_new( - "java/lang/RuntimeException", - "Unable to convert a Collider object [collider1] to a rust ColliderFFI" - ); - return false.into(); - }; - - let Ok(collider2) = NCollider::from_jobject(&mut env, &collider2) else { - let _ = env.throw_new( - "java/lang/RuntimeException", - "Unable to convert a Collider object [collider2] to a rust ColliderFFI" - ); - return false.into(); - }; - - super::shared::triggering(&physics, &collider1, &collider2).into() - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_PhysicsNative_isTouching( - _env: JNIEnv, - _: JClass, - physics_handle: jlong, - entity1: jlong, - entity2: jlong, - ) -> jboolean { - let physics = crate::convert_ptr!(physics_handle => PhysicsState); - let entity1 = crate::convert_jlong_to_entity!(entity1); - let entity2 = crate::convert_jlong_to_entity!(entity2); - - super::shared::touching(&physics, entity1, entity2).into() + let entity_id = if let Some(label) = found_label { + physics + .entity_label_map + .iter() + .find(|(_, l)| *l == label) + .map(|(e, _)| e.to_bits().get()) + .unwrap_or(Entity::DANGLING.to_bits().get()) + } else { + Entity::DANGLING.to_bits().get() + }; + + NCollider { + index: IndexNative { index: idx, generation }, + entity_id, + id: idx, } } - -pub mod native { - -} @@ -14,11 +14,9 @@ //! - `-colonly` (invisible collision mesh) pub mod shader; -pub mod collidergroup; +pub mod collider_group; use crate::scripting::jni::utils::{FromJObject, ToJObject}; -use crate::scripting::native::DropbearNativeError; -use crate::scripting::result::DropbearNativeResult; use crate::states::Label; use dropbear_engine::graphics::SharedGraphicsContext; use dropbear_engine::wgpu::util::{BufferInitDescriptor, DeviceExt}; @@ -30,7 +28,14 @@ use ::jni::JNIEnv; use rapier3d::prelude::ColliderBuilder; use serde::{Deserialize, Serialize}; use std::sync::Arc; -use rapier3d::math::Vector; +use crate::physics::collider::shared::{get_collider, get_collider_mut}; +use crate::scripting::native::DropbearNativeError; +use crate::scripting::result::DropbearNativeResult; +use crate::types::{NCollider, NVector3}; +use glam::DQuat; +use rapier3d::prelude::{Rotation, SharedShape, TypedShape, Vector}; +use crate::physics::PhysicsState; +use crate::ptr::PhysicsStatePtr; #[derive(Debug, Default, Serialize, Deserialize, Clone, SerializableComponent)] pub struct ColliderGroup { @@ -136,6 +141,7 @@ impl From<&ColliderShape> for ColliderShapeKey { #[repr(C)] #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +#[dropbear_macro::repr_c_enum] pub enum ColliderShape { /// Box shape with half-extents (half-width, half-height, half-depth). Box { half_extents: [f32; 3] }, @@ -632,650 +638,292 @@ pub mod shared { } } -pub mod jni { - #![allow(non_snake_case)] - use crate::physics::collider::shared::{get_collider, get_collider_mut}; - use crate::physics::collider::ColliderShape; - use crate::physics::PhysicsState; - use crate::scripting::jni::utils::{FromJObject, ToJObject}; - use crate::types::NCollider; - use glam::DQuat; - use jni::objects::{JClass, JObject}; - use jni::sys::{jboolean, jdouble, jlong, jobject}; - use jni::JNIEnv; - - use rapier3d::prelude::{ColliderHandle, Rotation, SharedShape, TypedShape, Vector}; - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_ColliderNative_getColliderShape( - mut env: JNIEnv, - _class: JClass, - physics_ptr: jlong, - collider_obj: JObject, - ) -> jobject { - let physics = crate::convert_ptr!(physics_ptr => PhysicsState); - - let ffi = match NCollider::from_jobject(&mut env, &collider_obj) { - Ok(v) => v, - Err(_) => return std::ptr::null_mut(), - }; - - if let Some(collider) = get_collider(&physics, &ffi) { - let rapier_shape = collider.shape(); - - let my_shape = match rapier_shape.as_typed_shape() { - TypedShape::Cuboid(c) => { - let he = c.half_extents; - ColliderShape::Box { - half_extents: [he.x, he.y, he.z] - } - }, - TypedShape::Ball(b) => { - ColliderShape::Sphere { - radius: b.radius - } - }, - TypedShape::Capsule(c) => { - let height = c.segment.length(); - ColliderShape::Capsule { - half_height: height * 0.5, - radius: c.radius - } - }, - TypedShape::Cylinder(c) => { - ColliderShape::Cylinder { - half_height: c.half_height, - radius: c.radius - } - }, - TypedShape::Cone(c) => { - ColliderShape::Cone { - half_height: c.half_height, - radius: c.radius - } - }, - _ => { - eprintln!("Unsupported collider shape type found."); - return std::ptr::null_mut(); - } - }; - - match my_shape.to_jobject(&mut env) { - Ok(obj) => obj.into_raw(), - Err(_) => std::ptr::null_mut(), - } - - } else { - let _ = env.throw_new("java/lang/RuntimeException", "Collider handle invalid"); - std::ptr::null_mut() - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_ColliderNative_setColliderShape( - mut env: JNIEnv, - _class: JClass, - physics_ptr: jlong, - collider_obj: JObject, - shape_obj: JObject, - ) { - let physics = crate::convert_ptr!(mut physics_ptr => PhysicsState); - - let ffi = match NCollider::from_jobject(&mut env, &collider_obj) { - Ok(v) => v, - Err(_) => return, - }; - - let handle = ColliderHandle::from_raw_parts(ffi.index.index, ffi.index.generation); - - let Some(collider) = physics.colliders.get_mut(handle) else { - let _ = env.throw_new("java/lang/IllegalArgumentException", "Collider handle invalid"); - return; - }; - - let Ok(shape) = ColliderShape::from_jobject(&mut env, &shape_obj) else { - let _ = env.throw_new("java/lang/IllegalArgumentException", "Collider shape is invalid"); - return; - }; - - let new_shape = match shape { - ColliderShape::Box { half_extents } => { - SharedShape::cuboid(half_extents[0], half_extents[1], half_extents[2]) - } - ColliderShape::Sphere { radius } => { - SharedShape::ball(radius) - } - ColliderShape::Capsule { half_height, radius } => { - SharedShape::capsule_y(half_height, radius) - } - ColliderShape::Cylinder { half_height, radius } => { - SharedShape::cylinder(half_height, radius) - } - ColliderShape::Cone { half_height, radius } => { - SharedShape::cone(half_height, radius) - } - }; - - collider.set_shape(new_shape); - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_ColliderNative_getColliderDensity( - mut env: JNIEnv, - _class: JClass, - physics_ptr: jlong, - collider_obj: JObject, - ) -> jdouble { - let physics = crate::convert_ptr!(physics_ptr => PhysicsState); - let ffi = NCollider::from_jobject(&mut env, &collider_obj).ok().unwrap(); - - if let Some(col) = get_collider(&physics, &ffi) { - col.density() as jdouble - } else { - 0.0 - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_ColliderNative_setColliderDensity( - mut env: JNIEnv, - _class: JClass, - physics_ptr: jlong, - collider_obj: JObject, - density: jdouble, - ) { - let physics = crate::convert_ptr!(mut physics_ptr => PhysicsState); - if let Ok(ffi) = NCollider::from_jobject(&mut env, &collider_obj) { - if let Some(col) = get_collider_mut(physics, &ffi) { - col.set_density(density as f32); - } - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_ColliderNative_getColliderFriction( - mut env: JNIEnv, - _class: JClass, - physics_ptr: jlong, - collider_obj: JObject, - ) -> jdouble { - let physics = crate::convert_ptr!(physics_ptr => PhysicsState); - let ffi = NCollider::from_jobject(&mut env, &collider_obj).ok().unwrap(); - if let Some(col) = get_collider(&physics, &ffi) { - col.friction() as jdouble - } else { 0.0 } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_ColliderNative_setColliderFriction( - mut env: JNIEnv, - _class: JClass, - physics_ptr: jlong, - collider_obj: JObject, - friction: jdouble, - ) { - let physics = crate::convert_ptr!(mut physics_ptr => PhysicsState); - if let Ok(ffi) = NCollider::from_jobject(&mut env, &collider_obj) { - if let Some(col) = get_collider_mut(physics, &ffi) { - col.set_friction(friction as f32); - } - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_ColliderNative_getColliderRestitution( - mut env: JNIEnv, - _class: JClass, - physics_ptr: jlong, - collider_obj: JObject, - ) -> jdouble { - let physics = crate::convert_ptr!(physics_ptr => PhysicsState); - let ffi = NCollider::from_jobject(&mut env, &collider_obj).ok().unwrap(); - if let Some(col) = get_collider(&physics, &ffi) { - col.restitution() as jdouble - } else { 0.0 } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_ColliderNative_setColliderRestitution( - mut env: JNIEnv, - _class: JClass, - physics_ptr: jlong, - collider_obj: JObject, - restitution: jdouble, - ) { - let physics = crate::convert_ptr!(mut physics_ptr => PhysicsState); - if let Ok(ffi) = NCollider::from_jobject(&mut env, &collider_obj) { - if let Some(col) = get_collider_mut(physics, &ffi) { - col.set_restitution(restitution as f32); +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.ColliderNative", func = "getColliderShape"), + c +)] +fn get_collider_shape( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + collider: &NCollider, +) -> DropbearNativeResult<ColliderShape> { + let collider = get_collider(physics, &collider) + .ok_or(DropbearNativeError::PhysicsObjectNotFound)?; + + let rapier_shape = collider.shape(); + let my_shape = match rapier_shape.as_typed_shape() { + TypedShape::Cuboid(c) => { + let he = c.half_extents; + ColliderShape::Box { + half_extents: [he.x, he.y, he.z], } } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_ColliderNative_getColliderMass( - mut env: JNIEnv, - _class: JClass, - physics_ptr: jlong, - collider_obj: JObject, - ) -> jdouble { - let physics = crate::convert_ptr!(physics_ptr => PhysicsState); - let ffi = NCollider::from_jobject(&mut env, &collider_obj).ok().unwrap(); - if let Some(col) = get_collider(&physics, &ffi) { - col.mass() as jdouble - } else { 0.0 } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_ColliderNative_setColliderMass( - mut env: JNIEnv, - _class: JClass, - physics_ptr: jlong, - collider_obj: JObject, - mass: jdouble, - ) { - let physics = crate::convert_ptr!(mut physics_ptr => PhysicsState); - if let Ok(ffi) = NCollider::from_jobject(&mut env, &collider_obj) { - if let Some(col) = get_collider_mut(physics, &ffi) { - col.set_mass(mass as f32); - } - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_ColliderNative_getColliderIsSensor( - mut env: JNIEnv, - _class: JClass, - physics_ptr: jlong, - collider_obj: JObject, - ) -> jboolean { - let physics = crate::convert_ptr!(physics_ptr => PhysicsState); - let ffi = NCollider::from_jobject(&mut env, &collider_obj).ok().unwrap(); - if let Some(col) = get_collider(&physics, &ffi) { - if col.is_sensor() { 1 } else { 0 } - } else { 0 } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_ColliderNative_setColliderIsSensor( - mut env: JNIEnv, - _class: JClass, - physics_ptr: jlong, - collider_obj: JObject, - is_sensor: jboolean, - ) { - let physics = crate::convert_ptr!(mut physics_ptr => PhysicsState); - if let Ok(ffi) = NCollider::from_jobject(&mut env, &collider_obj) { - if let Some(col) = get_collider_mut(physics, &ffi) { - col.set_sensor(is_sensor != 0); - } - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_ColliderNative_getColliderTranslation( - mut env: JNIEnv, - _class: JClass, - physics_ptr: jlong, - collider_obj: JObject, - ) -> jobject { - let physics = crate::convert_ptr!(physics_ptr => PhysicsState); - let ffi = match NCollider::from_jobject(&mut env, &collider_obj) { - Ok(v) => v, - Err(_) => return std::ptr::null_mut(), - }; - - if let Some(col) = get_collider(&physics, &ffi) { - let t: Vector = col.translation(); - let vec = crate::types::NVector3::new(t.x as f64, t.y as f64, t.z as f64); - match vec.to_jobject(&mut env) { - Ok(o) => o.into_raw(), - Err(_) => std::ptr::null_mut(), + TypedShape::Ball(b) => ColliderShape::Sphere { radius: b.radius }, + TypedShape::Capsule(c) => { + let height = c.segment.length(); + ColliderShape::Capsule { + half_height: height * 0.5, + radius: c.radius, } - } else { - std::ptr::null_mut() } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_ColliderNative_setColliderTranslation( - mut env: JNIEnv, - _class: JClass, - physics_ptr: jlong, - collider_obj: JObject, - vec_obj: JObject, - ) { - let physics = crate::convert_ptr!(mut physics_ptr => PhysicsState); - if let Ok(ffi) = NCollider::from_jobject(&mut env, &collider_obj) { - if let Ok(vec) = crate::types::NVector3::from_jobject(&mut env, &vec_obj) { - if let Some(col) = get_collider_mut(physics, &ffi) { - let t = Vector::new(vec.x as f32, vec.y as f32, vec.z as f32); - col.set_translation(t); - } - } - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_ColliderNative_getColliderRotation( - mut env: JNIEnv, - _class: JClass, - physics_ptr: jlong, - collider_obj: JObject, - ) -> jobject { - let physics = crate::convert_ptr!(physics_ptr => PhysicsState); - let ffi = match NCollider::from_jobject(&mut env, &collider_obj) { - Ok(v) => v, - Err(_) => return std::ptr::null_mut(), - }; - - if let Some(col) = get_collider(&physics, &ffi) { - let r: Rotation = col.rotation(); - let q = DQuat::from_xyzw(r.x as f64, r.y as f64, r.z as f64, r.w as f64); - let euler = q.to_euler(glam::EulerRot::XYZ); - let vec = crate::types::NVector3::new(euler.0, euler.1, euler.2); - - match vec.to_jobject(&mut env) { - Ok(o) => o.into_raw(), - Err(_) => std::ptr::null_mut(), - } - } else { - std::ptr::null_mut() - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_ColliderNative_setColliderRotation( - mut env: JNIEnv, - _class: JClass, - physics_ptr: jlong, - collider_obj: JObject, - vec_obj: JObject, - ) { - let physics = crate::convert_ptr!(mut physics_ptr => PhysicsState); - if let Ok(ffi) = NCollider::from_jobject(&mut env, &collider_obj) { - if let Ok(vec) = crate::types::NVector3::from_jobject(&mut env, &vec_obj) { - if let Some(col) = get_collider_mut(physics, &ffi) { - let q = DQuat::from_euler(glam::EulerRot::XYZ, vec.x, vec.y, vec.z); - let r = Rotation::from_array([q.w as f32, q.x as f32, q.y as f32, q.z as f32]); - col.set_rotation(r); - } - } - } - } + TypedShape::Cylinder(c) => ColliderShape::Cylinder { + half_height: c.half_height, + radius: c.radius, + }, + TypedShape::Cone(c) => ColliderShape::Cone { + half_height: c.half_height, + radius: c.radius, + }, + _ => return Err(DropbearNativeError::InvalidArgument), + }; + + Ok(my_shape) } -// #[dropbear_macro::impl_c_api] -pub mod native { - use crate::physics::Rotation; - use crate::convert_ptr; - use crate::physics::collider::shared::{get_collider, get_collider_mut}; - use crate::physics::PhysicsState; - use crate::ptr::PhysicsStatePtr; - use crate::types::NVector3; - - use crate::scripting::native::DropbearNativeError; - use crate::scripting::result::DropbearNativeResult; - use crate::types::{NCollider, NColliderShape, ColliderShapeType}; - use glam::DQuat; - use rapier3d::prelude::{SharedShape, TypedShape, Vector}; - - pub fn dropbear_get_collider_shape( - physics_ptr: PhysicsStatePtr, - ffi: NCollider, - ) -> DropbearNativeResult<NColliderShape> { - let physics = convert_ptr!(physics_ptr => PhysicsState); - - if let Some(collider) = get_collider(physics, &ffi) { - let rapier_shape = collider.shape(); - let mut result = NColliderShape { - shape_type: ColliderShapeType::Box, - radius: 0.0, half_height: 0.0, - half_extents_x: 0.0, half_extents_y: 0.0, half_extents_z: 0.0, - }; - - match rapier_shape.as_typed_shape() { - TypedShape::Cuboid(c) => { - result.shape_type = ColliderShapeType::Box; - result.half_extents_x = c.half_extents.x; - result.half_extents_y = c.half_extents.y; - result.half_extents_z = c.half_extents.z; - }, - TypedShape::Ball(b) => { - result.shape_type = ColliderShapeType::Sphere; - result.radius = b.radius; - }, - TypedShape::Capsule(c) => { - result.shape_type = ColliderShapeType::Capsule; - result.radius = c.radius; - result.half_height = c.segment.length() * 0.5; - }, - TypedShape::Cylinder(c) => { - result.shape_type = ColliderShapeType::Cylinder; - result.radius = c.radius; - result.half_height = c.half_height; - }, - TypedShape::Cone(c) => { - result.shape_type = ColliderShapeType::Cone; - result.radius = c.radius; - result.half_height = c.half_height; - }, - _ => return DropbearNativeResult::Err(DropbearNativeError::GenericError), - } - DropbearNativeResult::Ok(result) - } else { - DropbearNativeResult::Err(DropbearNativeError::InvalidHandle) - } - } - - pub fn dropbear_set_collider_shape( - physics_ptr: PhysicsStatePtr, - ffi: NCollider, - shape: NColliderShape, - ) -> DropbearNativeResult<()> { - let physics = convert_ptr!(mut physics_ptr => PhysicsState); - - if let Some(collider) = get_collider_mut(physics, &ffi) { - let new_shape = match shape.shape_type { - ColliderShapeType::Box => SharedShape::cuboid(shape.half_extents_x, shape.half_extents_y, shape.half_extents_z), - ColliderShapeType::Sphere => SharedShape::ball(shape.radius), - ColliderShapeType::Capsule => SharedShape::capsule_y(shape.half_height, shape.radius), - ColliderShapeType::Cylinder => SharedShape::cylinder(shape.half_height, shape.radius), - ColliderShapeType::Cone => SharedShape::cone(shape.half_height, shape.radius), - }; - collider.set_shape(new_shape); - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchHandle) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.ColliderNative", func = "setColliderShape"), + c +)] +fn set_collider_shape( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + collider: &NCollider, + shape: &ColliderShape, +) -> DropbearNativeResult<()> { + let collider = get_collider_mut(physics, &collider) + .ok_or(DropbearNativeError::PhysicsObjectNotFound)?; + + let new_shape = match shape { + ColliderShape::Box { half_extents } => { + SharedShape::cuboid(half_extents[0], half_extents[1], half_extents[2]) + } + ColliderShape::Sphere { radius } => SharedShape::ball(*radius), + ColliderShape::Capsule { half_height, radius } => { + SharedShape::capsule_y(*half_height, *radius) + } + ColliderShape::Cylinder { half_height, radius } => { + SharedShape::cylinder(*half_height, *radius) + } + ColliderShape::Cone { half_height, radius } => SharedShape::cone(*half_height, *radius), + }; + + collider.set_shape(new_shape); + Ok(()) +} - pub fn dropbear_get_collider_density( - physics_ptr: PhysicsStatePtr, - ffi: NCollider, - ) -> DropbearNativeResult<f64> { - let physics = convert_ptr!(physics_ptr => PhysicsState); - if let Some(col) = get_collider(physics, &ffi) { - DropbearNativeResult::Ok(col.density() as f64) - } else { - DropbearNativeResult::Err(DropbearNativeError::InvalidHandle) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.ColliderNative", func = "getColliderDensity"), + c +)] +fn get_collider_density( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + collider: &NCollider, +) -> DropbearNativeResult<f64> { + let collider = get_collider(physics, &collider) + .ok_or(DropbearNativeError::PhysicsObjectNotFound)?; + Ok(collider.density() as f64) +} - pub fn dropbear_set_collider_density( - physics_ptr: PhysicsStatePtr, - ffi: NCollider, - density: f64, - ) -> DropbearNativeResult<()> { - let physics = convert_ptr!(mut physics_ptr => PhysicsState); - if let Some(col) = get_collider_mut(physics, &ffi) { - col.set_density(density as f32); - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::InvalidHandle) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.ColliderNative", func = "setColliderDensity"), + c +)] +fn set_collider_density( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + collider: &NCollider, + density: f64, +) -> DropbearNativeResult<()> { + let collider = get_collider_mut(physics, &collider) + .ok_or(DropbearNativeError::PhysicsObjectNotFound)?; + collider.set_density(density as f32); + Ok(()) +} - pub fn dropbear_get_collider_friction( - physics_ptr: PhysicsStatePtr, - ffi: NCollider, - ) -> DropbearNativeResult<f64> { - let physics = convert_ptr!(physics_ptr => PhysicsState); - if let Some(col) = get_collider(physics, &ffi) { - DropbearNativeResult::Ok(col.friction() as f64) - } else { - DropbearNativeResult::Err(DropbearNativeError::InvalidHandle) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.ColliderNative", func = "getColliderFriction"), + c +)] +fn get_collider_friction( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + collider: &NCollider, +) -> DropbearNativeResult<f64> { + let collider = get_collider(physics, &collider) + .ok_or(DropbearNativeError::PhysicsObjectNotFound)?; + Ok(collider.friction() as f64) +} - pub fn dropbear_set_collider_friction( - physics_ptr: PhysicsStatePtr, - ffi: NCollider, - friction: f64, - ) -> DropbearNativeResult<()> { - let physics = convert_ptr!(mut physics_ptr => PhysicsState); - if let Some(col) = get_collider_mut(physics, &ffi) { - col.set_friction(friction as f32); - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::InvalidHandle) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.ColliderNative", func = "setColliderFriction"), + c +)] +fn set_collider_friction( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + collider: &NCollider, + friction: f64, +) -> DropbearNativeResult<()> { + let collider = get_collider_mut(physics, &collider) + .ok_or(DropbearNativeError::PhysicsObjectNotFound)?; + collider.set_friction(friction as f32); + Ok(()) +} - pub fn dropbear_get_collider_restitution( - physics_ptr: PhysicsStatePtr, - ffi: NCollider, - ) -> DropbearNativeResult<f64> { - let physics = convert_ptr!(physics_ptr => PhysicsState); - if let Some(col) = get_collider(physics, &ffi) { - DropbearNativeResult::Ok(col.restitution() as f64) - } else { - DropbearNativeResult::Err(DropbearNativeError::InvalidHandle) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.ColliderNative", func = "getColliderRestitution"), + c +)] +fn get_collider_restitution( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + collider: &NCollider, +) -> DropbearNativeResult<f64> { + let collider = get_collider(physics, &collider) + .ok_or(DropbearNativeError::PhysicsObjectNotFound)?; + Ok(collider.restitution() as f64) +} - pub fn dropbear_set_collider_restitution( - physics_ptr: PhysicsStatePtr, - ffi: NCollider, - restitution: f64, - ) -> DropbearNativeResult<()> { - let physics = convert_ptr!(mut physics_ptr => PhysicsState); - if let Some(col) = get_collider_mut(physics, &ffi) { - col.set_restitution(restitution as f32); - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::InvalidHandle) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.ColliderNative", func = "setColliderRestitution"), + c +)] +fn set_collider_restitution( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + collider: &NCollider, + restitution: f64, +) -> DropbearNativeResult<()> { + let collider = get_collider_mut(physics, &collider) + .ok_or(DropbearNativeError::PhysicsObjectNotFound)?; + collider.set_restitution(restitution as f32); + Ok(()) +} - pub fn dropbear_get_collider_mass( - physics_ptr: PhysicsStatePtr, - ffi: NCollider, - ) -> DropbearNativeResult<f64> { - let physics = convert_ptr!(physics_ptr => PhysicsState); - if let Some(col) = get_collider(physics, &ffi) { - DropbearNativeResult::Ok(col.mass() as f64) - } else { - DropbearNativeResult::Err(DropbearNativeError::InvalidHandle) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.ColliderNative", func = "getColliderMass"), + c +)] +fn get_collider_mass( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + collider: &NCollider, +) -> DropbearNativeResult<f64> { + let collider = get_collider(physics, &collider) + .ok_or(DropbearNativeError::PhysicsObjectNotFound)?; + Ok(collider.mass() as f64) +} - pub fn dropbear_set_collider_mass( - physics_ptr: PhysicsStatePtr, - ffi: NCollider, - mass: f64, - ) -> DropbearNativeResult<()> { - let physics = convert_ptr!(mut physics_ptr => PhysicsState); - if let Some(col) = get_collider_mut(physics, &ffi) { - col.set_mass(mass as f32); - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::InvalidHandle) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.ColliderNative", func = "setColliderMass"), + c +)] +fn set_collider_mass( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + collider: &NCollider, + mass: f64, +) -> DropbearNativeResult<()> { + let collider = get_collider_mut(physics, &collider) + .ok_or(DropbearNativeError::PhysicsObjectNotFound)?; + collider.set_mass(mass as f32); + Ok(()) +} - pub fn dropbear_get_collider_is_sensor( - physics_ptr: PhysicsStatePtr, - ffi: NCollider, - ) -> DropbearNativeResult<bool> { - let physics = convert_ptr!(physics_ptr => PhysicsState); - if let Some(col) = get_collider(physics, &ffi) { - DropbearNativeResult::Ok(col.is_sensor()) - } else { - DropbearNativeResult::Err(DropbearNativeError::InvalidHandle) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.ColliderNative", func = "getColliderIsSensor"), + c +)] +fn get_collider_is_sensor( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + collider: &NCollider, +) -> DropbearNativeResult<bool> { + let collider = get_collider(physics, &collider) + .ok_or(DropbearNativeError::PhysicsObjectNotFound)?; + Ok(collider.is_sensor()) +} - pub fn dropbear_set_collider_is_sensor( - physics_ptr: PhysicsStatePtr, - ffi: NCollider, - is_sensor: bool, - ) -> DropbearNativeResult<()> { - let physics = convert_ptr!(mut physics_ptr => PhysicsState); - if let Some(col) = get_collider_mut(physics, &ffi) { - col.set_sensor(is_sensor); - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::InvalidHandle) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.ColliderNative", func = "setColliderIsSensor"), + c +)] +fn set_collider_is_sensor( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + collider: &NCollider, + is_sensor: bool, +) -> DropbearNativeResult<()> { + let collider = get_collider_mut(physics, &collider) + .ok_or(DropbearNativeError::PhysicsObjectNotFound)?; + collider.set_sensor(is_sensor); + Ok(()) +} - pub fn dropbear_get_collider_translation( - physics_ptr: PhysicsStatePtr, - ffi: NCollider, - ) -> DropbearNativeResult<NVector3> { - let physics = convert_ptr!(physics_ptr => PhysicsState); - if let Some(col) = get_collider(physics, &ffi) { - let t = col.translation(); - DropbearNativeResult::Ok(NVector3 { x: t.x as f64, y: t.y as f64, z: t.z as f64 }) - } else { - DropbearNativeResult::Err(DropbearNativeError::InvalidHandle) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.ColliderNative", func = "getColliderTranslation"), + c +)] +fn get_collider_translation( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + collider: &NCollider, +) -> DropbearNativeResult<NVector3> { + let collider = get_collider(physics, &collider) + .ok_or(DropbearNativeError::PhysicsObjectNotFound)?; + let t: Vector = collider.translation(); + Ok(NVector3::new(t.x as f64, t.y as f64, t.z as f64)) +} - pub fn dropbear_set_collider_translation( - physics_ptr: PhysicsStatePtr, - ffi: NCollider, - translation: NVector3, - ) -> DropbearNativeResult<()> { - let physics = convert_ptr!(mut physics_ptr => PhysicsState); - if let Some(col) = get_collider_mut(physics, &ffi) { - let t = Vector::new(translation.x as f32, translation.y as f32, translation.z as f32); - col.set_translation(t); - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::InvalidHandle) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.ColliderNative", func = "setColliderTranslation"), + c +)] +fn set_collider_translation( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + collider: &NCollider, + translation: &NVector3, +) -> DropbearNativeResult<()> { + let collider = get_collider_mut(physics, &collider) + .ok_or(DropbearNativeError::PhysicsObjectNotFound)?; + let t = Vector::new(translation.x as f32, translation.y as f32, translation.z as f32); + collider.set_translation(t); + Ok(()) +} - pub fn dropbear_get_collider_rotation( - physics_ptr: PhysicsStatePtr, - ffi: NCollider, - ) -> DropbearNativeResult<NVector3> { - let physics = convert_ptr!(physics_ptr => PhysicsState); - if let Some(col) = get_collider(physics, &ffi) { - let r = col.rotation(); - let q: DQuat = DQuat::from_xyzw(r.x as f64, r.y as f64, r.z as f64, r.w as f64); - let (x, y, z) = q.to_euler(glam::EulerRot::XYZ); - DropbearNativeResult::Ok(NVector3 { x, y, z }) - } else { - DropbearNativeResult::Err(DropbearNativeError::InvalidHandle) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.ColliderNative", func = "getColliderRotation"), + c +)] +fn get_collider_rotation( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + collider: &NCollider, +) -> DropbearNativeResult<NVector3> { + let collider = get_collider(physics, &collider) + .ok_or(DropbearNativeError::PhysicsObjectNotFound)?; + let r: Rotation = collider.rotation(); + let q = DQuat::from_xyzw(r.x as f64, r.y as f64, r.z as f64, r.w as f64); + let euler = q.to_euler(glam::EulerRot::XYZ); + Ok(NVector3::new(euler.0, euler.1, euler.2)) +} - pub fn dropbear_set_collider_rotation( - physics_ptr: PhysicsStatePtr, - ffi: NCollider, - rotation: NVector3, - ) -> DropbearNativeResult<()> { - let physics = convert_ptr!(mut physics_ptr => PhysicsState); - if let Some(col) = get_collider_mut(physics, &ffi) { - let q = DQuat::from_euler(glam::EulerRot::XYZ, rotation.x, rotation.y, rotation.z); - let r = Rotation::from(q.as_quat()); - col.set_rotation(r); - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::InvalidHandle) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.ColliderNative", func = "setColliderRotation"), + c +)] +fn set_collider_rotation( + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + collider: &NCollider, + rotation: &NVector3, +) -> DropbearNativeResult<()> { + let collider = get_collider_mut(physics, &collider) + .ok_or(DropbearNativeError::PhysicsObjectNotFound)?; + let q = DQuat::from_euler(glam::EulerRot::XYZ, rotation.x, rotation.y, rotation.z); + let r = Rotation::from_array([q.w as f32, q.x as f32, q.y as f32, q.z as f32]); + collider.set_rotation(r); + Ok(()) } @@ -0,0 +1,62 @@ +//! Scripting module for collider groups. + +use crate::physics::collider::ColliderGroup; +use crate::physics::PhysicsState; +use crate::ptr::WorldPtr; +use crate::scripting::native::DropbearNativeError; +use crate::scripting::result::DropbearNativeResult; +use crate::types::{IndexNative, NCollider}; + +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.ColliderGroupNative", func = "colliderGroupExistsForEntity"), + c +)] +fn exists_for_entity( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::entity] + entity: hecs::Entity +) -> DropbearNativeResult<bool> { + Ok(world.get::<&ColliderGroup>(entity).is_ok()) +} + +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.ColliderGroupNative", func = "getColliderGroupColliders"), + c +)] +fn get_colliders( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::define(crate::ptr::PhysicsStatePtr)] + physics: &PhysicsState, + #[dropbear_macro::entity] + entity: hecs::Entity +) -> DropbearNativeResult<Vec<NCollider>> { + if world.get::<&ColliderGroup>(entity).is_ok() { + let handles_opt = physics.entity_label_map + .get(&entity) + .and_then(|label| physics.colliders_entity_map.get(label)); + + let mut colliders: Vec<NCollider> = Vec::new(); + + if let Some(handles) = handles_opt { + for (_, handle) in handles { + let (idx, generation) = handle.into_raw_parts(); + + let col = NCollider { + index: IndexNative { + index: idx, + generation, + }, + entity_id: entity.to_bits().get(), + id: idx, + }; + colliders.push(col); + } + } + + Ok(colliders) + } else { + Err(DropbearNativeError::MissingComponent)? + } +} @@ -1,252 +0,0 @@ -//! Scripting module for collider groups. - -use crate::scripting::jni::utils::{FromJObject, ToJObject}; -use crate::scripting::native::DropbearNativeError; -use crate::scripting::result::DropbearNativeResult; -use crate::types::IndexNative; -use ::jni::objects::{JObject, JValue}; -use ::jni::JNIEnv; - -impl ToJObject for IndexNative { - fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { - let cls = env.find_class("com/dropbear/physics/Index") - .map_err(|e| { - eprintln!("[JNI Error] Could not find Index class: {:?}", e); - DropbearNativeError::GenericError - })?; - - let obj = env.new_object( - cls, - "(II)V", - &[ - JValue::Int(self.index as i32), - JValue::Int(self.generation as i32) - ] - ).map_err(|e| { - eprintln!("[JNI Error] Failed to create Index object: {:?}", e); - DropbearNativeError::GenericError - })?; - - Ok(obj) - } -} - -impl FromJObject for IndexNative { - fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> - where - Self: Sized - { - let idx_val = env.get_field(obj, "index", "I") - .map_err(|_| DropbearNativeError::JNIFailedToGetField)? - .i() - .map_err(|_| DropbearNativeError::JNIUnwrapFailed)?; - - let gen_val = env.get_field(obj, "generation", "I") - .map_err(|_| DropbearNativeError::JNIFailedToGetField)? - .i() - .map_err(|_| DropbearNativeError::JNIUnwrapFailed)?; - - Ok(IndexNative { - index: idx_val as u32, - generation: gen_val as u32, - }) - } -} - -pub mod shared { - use crate::physics::collider::ColliderGroup; - use hecs::{Entity, World}; - - pub fn collider_group_exists_for_entity(world: &World, entity: Entity) -> bool { - world.get::<&ColliderGroup>(entity).is_ok() - } -} - -pub mod jni { - #![allow(non_snake_case)] - use crate::physics::collider::ColliderGroup; - use crate::types::{NCollider, IndexNative}; - use hecs::World; - use jni::objects::{JClass, JObject}; - use jni::sys::{jboolean, jlong, jobjectArray}; - use jni::JNIEnv; - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_ColliderGroupNative_colliderGroupExistsForEntity( - _env: JNIEnv, - _class: JClass, - world_ptr: jlong, - entity_id: jlong, - ) -> jboolean { - let world = crate::convert_ptr!(world_ptr => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - - if super::shared::collider_group_exists_for_entity(&world, entity) { - true.into() - } else { - false.into() - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_ColliderGroupNative_getColliderGroupColliders( - mut env: JNIEnv, - _class: JClass, - world_ptr: jlong, - physics_ptr: jlong, - entity_id: jlong, - ) -> jobjectArray { - let world = crate::convert_ptr!(world_ptr => hecs::World); - let physics = crate::convert_ptr!(physics_ptr => crate::physics::PhysicsState); - let entity = crate::convert_jlong_to_entity!(entity_id); - - // We check if the ColliderGroup component exists first - if world.get::<&ColliderGroup>(entity).is_ok() { - let handles_opt = physics.entity_label_map - .get(&entity) - .and_then(|label| physics.colliders_entity_map.get(label)); - - let mut colliders: Vec<NCollider> = Vec::new(); - - if let Some(handles) = handles_opt { - for (_, handle) in handles { - let (idx, generation) = handle.into_raw_parts(); - - let col = NCollider { - index: IndexNative { - index: idx, - generation, - }, - entity_id: entity_id as u64, - id: idx, - }; - colliders.push(col); - } - } - - let collider_cls = match env.find_class("com/dropbear/physics/Collider") { - Ok(cls) => cls, - Err(e) => { - eprintln!("[JNI Error] Could not find Collider class: {:?}", e); - return std::ptr::null_mut(); - } - }; - - let output_array = match env.new_object_array(colliders.len() as i32, &collider_cls, JObject::null()) { - Ok(arr) => arr, - Err(e) => { - eprintln!("[JNI Error] Failed to allocate Collider array: {:?}", e); - let _ = env.throw_new("java/lang/OutOfMemoryError", "Could not allocate collider array"); - return std::ptr::null_mut(); - } - }; - - use crate::scripting::jni::utils::ToJObject; - - for (i, ffi) in colliders.iter().enumerate() { - let java_obj = match ffi.to_jobject(&mut env) { - Ok(obj) => obj, - Err(_) => return std::ptr::null_mut(), - }; - - if let Err(e) = env.set_object_array_element(&output_array, i as i32, java_obj) { - eprintln!("[JNI Error] Failed to set array element: {:?}", e); - return std::ptr::null_mut(); - } - } - - output_array.into_raw() - - } else { - let _ = env.throw_new("java/lang/RuntimeException", "Entity does not have a ColliderGroup component"); - std::ptr::null_mut() - } - } -} - -#[dropbear_macro::impl_c_api] -pub mod native { - use crate::convert_ptr; - use crate::physics::collider::ColliderGroup; - use crate::physics::PhysicsState; - use crate::ptr::{PhysicsStatePtr, WorldPtr}; - use crate::scripting::native::DropbearNativeError; - use crate::scripting::result::DropbearNativeResult; - use crate::types::{NCollider, IndexNative}; - use hecs::Entity; - - pub fn dropbear_collider_group_exists_for_entity( - world_ptr: WorldPtr, - entity_id: u64, - ) -> DropbearNativeResult<bool> { - let world = convert_ptr!(world_ptr => hecs::World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - DropbearNativeResult::Ok(super::shared::collider_group_exists_for_entity(world, entity)) - } - - pub fn dropbear_get_collider_group_colliders( - world_ptr: WorldPtr, - physics_ptr: PhysicsStatePtr, - entity_id: u64, - out_count: *mut usize, - ) -> DropbearNativeResult<*mut NCollider> { - let world = convert_ptr!(world_ptr => hecs::World); - let physics = convert_ptr!(physics_ptr => PhysicsState); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - if out_count.is_null() { - return DropbearNativeResult::Err(DropbearNativeError::NullPointer); - } - - if world.get::<&ColliderGroup>(entity).is_err() { - unsafe { *out_count = 0; } - return DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent); - } - - let handles_opt = physics.entity_label_map - .get(&entity) - .and_then(|label| physics.colliders_entity_map.get(label)); - - let mut colliders: Vec<NCollider> = Vec::new(); - - if let Some(handles) = handles_opt { - for (_, handle) in handles { - let (idx, generation) = handle.into_raw_parts(); - - let col = NCollider { - index: IndexNative { - index: idx, - generation, - }, - entity_id, - id: idx, - }; - colliders.push(col); - } - } - - unsafe { *out_count = colliders.len(); } - - colliders.shrink_to_fit(); - let ptr = colliders.as_mut_ptr(); - std::mem::forget(colliders); - - DropbearNativeResult::Ok(ptr) - } - - pub fn dropbear_free_collider_array( - ptr: *mut NCollider, - count: usize, - ) -> DropbearNativeResult<()> { - if ptr.is_null() { - return DropbearNativeResult::Ok(()); - } - - unsafe { - let _ = Vec::from_raw_parts(ptr, count, count); - } - - DropbearNativeResult::Ok(()) - } -} @@ -8,6 +8,17 @@ use rapier3d::control::{CharacterCollision, KinematicCharacterController}; use serde::{Deserialize, Serialize}; use dropbear_macro::SerializableComponent; use crate::states::Label; +use crate::physics::PhysicsState; +use crate::scripting::jni::utils::ToJObject; +use crate::scripting::native::DropbearNativeError; +use crate::scripting::result::DropbearNativeResult; +use crate::types::{IndexNative, NQuaternion, NVector3}; +use jni::objects::{JObject, JValue}; +use jni::JNIEnv; +use rapier3d::dynamics::RigidBodyType; +use rapier3d::math::Rotation; +use rapier3d::prelude::QueryFilter; +use crate::ptr::WorldPtr; /// The kinematic character controller (kcc) component. #[derive(Debug, Default, Serialize, Deserialize, Clone, SerializableComponent)] @@ -28,280 +39,225 @@ impl KCC { } } -pub mod shared { - +#[repr(C)] +struct CharacterCollisionArray { + entity_id: u64, + collisions: Vec<IndexNative>, } -pub mod jni { - #![allow(non_snake_case)] - - use hecs::World; - use jni::JNIEnv; - use jni::objects::{JClass, JObject}; - use jni::sys::{jboolean, jdouble, jlong}; - use rapier3d::dynamics::RigidBodyType; - use rapier3d::math::Rotation; - use rapier3d::prelude::QueryFilter; - use crate::{convert_jlong_to_entity, convert_ptr}; - use crate::physics::kcc::KCC; - use crate::physics::PhysicsState; - use crate::scripting::jni::utils::FromJObject; - use crate::states::Label; - use crate::types::NVector3; - use jni::objects::JValue; - use jni::sys::{jint, jobjectArray}; - use crate::types::IndexNative; - use crate::scripting::jni::utils::ToJObject; - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_KinematicCharacterControllerNative_existsForEntity( - _env: JNIEnv, - _: JClass, - world_handle: jlong, - entity: jlong, - ) -> jboolean { - let world = convert_ptr!(world_handle => World); - let entity = convert_jlong_to_entity!(entity); - - let result = world.get::<&KCC>(entity).is_ok(); - if result { 1 } else { 0 } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_KinematicCharacterControllerNative_moveCharacter( - mut env: JNIEnv, - _: JClass, - world_handle: jlong, - physics_handle: jlong, - entity: jlong, - translation: JObject, - delta_time: jdouble, - ) { - let world = convert_ptr!(world_handle => World); - let physics_state = convert_ptr!(mut physics_handle => PhysicsState); - let entity = convert_jlong_to_entity!(entity); - - let movement = match NVector3::from_jobject(&mut env, &translation) { - Ok(v) => v, - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Unable to convert JObject to Vector3: {}", e)); - return; - } - }; - - if let Ok((label, kcc)) = world.query_one::<(&Label, &KCC)>(entity).get() - { - let Some(rigid_body_handle) = physics_state.bodies_entity_map.get(label) else { - return; - }; - - let (body_type, body_pos) = { - let Some(body) = physics_state.bodies.get(*rigid_body_handle) else { - return; - }; - - (body.body_type(), *body.position()) - }; - - match body_type { - RigidBodyType::KinematicPositionBased => {} - _ => return, - } +impl ToJObject for CharacterCollisionArray { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + let collision_cls = env.find_class("com/dropbear/physics/CharacterCollision") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; - let Some(collider_handles) = physics_state.colliders_entity_map.get(label) else { - return; - }; - let Some((_, collider_handle)) = collider_handles.first() else { - return; - }; - let Some(collider) = physics_state.colliders.get(*collider_handle) else { - return; - }; + let entity_cls = env.find_class("com/dropbear/EntityId") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; - let character_pos = if let Some(pos_wrt_parent) = collider.position_wrt_parent() { - body_pos * (*pos_wrt_parent) - } else { - *collider.position() - }; + let entity_obj = env.new_object(&entity_cls, "(J)V", &[JValue::Long(self.entity_id as i64)]) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; - let filter = QueryFilter::default().exclude_rigid_body(*rigid_body_handle); - let query_pipeline = physics_state.broad_phase.as_query_pipeline( - physics_state.narrow_phase.query_dispatcher(), - &physics_state.bodies, - &physics_state.colliders, - filter, - ); + let out = env.new_object_array(self.collisions.len() as i32, &collision_cls, JObject::null()) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; - let movement = kcc.controller.move_shape( - delta_time as f32, - &query_pipeline, - collider.shape(), - &character_pos, - rapier3d::prelude::Vector::new(movement.x as f32, movement.y as f32, movement.z as f32), - |collision| { - if let Some(collisions) = physics_state.collision_events_to_deal_with.get_mut(&entity) { - collisions.push(collision) - } else { - physics_state.collision_events_to_deal_with.insert(entity, vec![collision]); - } - }, - ); + for (i, handle) in self.collisions.iter().enumerate() { + let index_obj = handle.to_jobject(env)?; + let collision_obj = env.new_object( + &collision_cls, + "(Lcom/dropbear/EntityId;Lcom/dropbear/physics/Index;)V", + &[JValue::Object(&entity_obj), JValue::Object(&index_obj)], + ) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; - if let Some(body) = physics_state.bodies.get_mut(*rigid_body_handle) { - let current_pos = body.translation(); - let new_pos = current_pos + movement.translation; - body.set_next_kinematic_translation(new_pos); - } + env.set_object_array_element(&out, i as i32, collision_obj) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; } + + Ok(JObject::from(out)) } +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_KinematicCharacterControllerNative_setRotation( - mut env: JNIEnv, - _: JClass, - world_handle: jlong, - physics_handle: jlong, - entity: jlong, - rotation: JObject, - ) { - let world = convert_ptr!(world_handle => World); - let physics_state = convert_ptr!(mut physics_handle => PhysicsState); - let entity = convert_jlong_to_entity!(entity); +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.KinematicCharacterControllerNative", func = "existsForEntity"), + c +)] +fn kcc_exists_for_entity( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::entity] + entity: hecs::Entity, +) -> DropbearNativeResult<bool> { + Ok(world.get::<&KCC>(entity).is_ok()) +} - let class = match env.find_class("com/dropbear/math/Quaterniond") { - Ok(cls) => cls, - Err(_) => { - let _ = env.throw_new("java/lang/RuntimeException", "Unable to find Quaterniond class"); - return; - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.KinematicCharacterControllerNative", func = "moveCharacter"), + c +)] +fn move_character( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::define(crate::ptr::PhysicsStatePtr)] + physics_state: &mut PhysicsState, + #[dropbear_macro::entity] + entity: hecs::Entity, + translation: &NVector3, + delta_time: f64, +) -> DropbearNativeResult<()> { + if let Ok((label, kcc)) = world.query_one::<(&Label, &KCC)>(entity).get() { + let rigid_body_handle = physics_state + .bodies_entity_map + .get(label) + .ok_or(DropbearNativeError::NoSuchHandle)?; + + let (body_type, body_pos) = { + let body = physics_state + .bodies + .get(*rigid_body_handle) + .ok_or(DropbearNativeError::PhysicsObjectNotFound)?; + (body.body_type(), *body.position()) }; - if let Ok(false) = env.is_instance_of(&rotation, &class) { - let _ = env.throw_new("java/lang/IllegalArgumentException", "rotation must be Quaterniond"); - return; + if body_type != RigidBodyType::KinematicPositionBased { + return Err(DropbearNativeError::InvalidArgument); } - let mut get_double = |field: &str| -> Option<f64> { - env.get_field(&rotation, field, "D").ok()?.d().ok() - }; - - let Some(rx) = get_double("x") else { return; }; - let Some(ry) = get_double("y") else { return; }; - let Some(rz) = get_double("z") else { return; }; - let Some(rw) = get_double("w") else { return; }; - - let len = (rx * rx + ry * ry + rz * rz + rw * rw).sqrt(); - let (x, y, z, w) = if len > 0.0 { - (rx / len, ry / len, rz / len, rw / len) + let collider_handles = physics_state + .colliders_entity_map + .get(label) + .ok_or(DropbearNativeError::NoSuchHandle)?; + let (_, collider_handle) = collider_handles + .first() + .ok_or(DropbearNativeError::NoSuchHandle)?; + let collider = physics_state + .colliders + .get(*collider_handle) + .ok_or(DropbearNativeError::PhysicsObjectNotFound)?; + + let character_pos = if let Some(pos_wrt_parent) = collider.position_wrt_parent() { + body_pos * (*pos_wrt_parent) } else { - (0.0, 0.0, 0.0, 1.0) + *collider.position() }; - if let Ok((label, _kcc)) = world.query_one::<(&Label, &KCC)>(entity).get() { - let Some(rigid_body_handle) = physics_state.bodies_entity_map.get(label) else { - return; - }; - - let body_type = { - let Some(body) = physics_state.bodies.get(*rigid_body_handle) else { - return; - }; - body.body_type() - }; - - match body_type { - RigidBodyType::KinematicPositionBased => {} - _ => return, - } + let filter = QueryFilter::default().exclude_rigid_body(*rigid_body_handle); + let query_pipeline = physics_state.broad_phase.as_query_pipeline( + physics_state.narrow_phase.query_dispatcher(), + &physics_state.bodies, + &physics_state.colliders, + filter, + ); + + let movement = kcc.controller.move_shape( + delta_time as f32, + &query_pipeline, + collider.shape(), + &character_pos, + rapier3d::prelude::Vector::new( + translation.x as f32, + translation.y as f32, + translation.z as f32, + ), + |collision| { + if let Some(collisions) = physics_state.collision_events_to_deal_with.get_mut(&entity) { + collisions.push(collision) + } else { + physics_state.collision_events_to_deal_with.insert(entity, vec![collision]); + } + }, + ); - if let Some(body) = physics_state.bodies.get_mut(*rigid_body_handle) { - let rot = Rotation::from_xyzw(x as f32, y as f32, z as f32, w as f32); - body.set_next_kinematic_rotation(rot); - } + if let Some(body) = physics_state.bodies.get_mut(*rigid_body_handle) { + let current_pos = body.translation(); + let new_pos = current_pos + movement.translation; + body.set_next_kinematic_translation(new_pos); } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_KinematicCharacterControllerNative_getHitNative( - mut env: JNIEnv, - _: JClass, - world_handle: jlong, - entity: jlong, - ) -> jobjectArray { - let world = convert_ptr!(world_handle => World); - let entity = convert_jlong_to_entity!(entity); - let Ok(kcc) = world.get::<&KCC>(entity) else { - return std::ptr::null_mut(); - }; - - let collision_cls = match env.find_class("com/dropbear/physics/CharacterCollision") { - Ok(cls) => cls, - Err(e) => { - eprintln!("[JNI Error] Could not find CharacterCollision class: {:?}", e); - return std::ptr::null_mut(); - } - }; + Ok(()) + } else { + Err(DropbearNativeError::MissingComponent) + } +} - let entity_cls = match env.find_class("com/dropbear/EntityId") { - Ok(cls) => cls, - Err(e) => { - eprintln!("[JNI Error] Could not find EntityId class: {:?}", e); - return std::ptr::null_mut(); - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.KinematicCharacterControllerNative", func = "setRotation"), + c +)] +fn set_rotation( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::define(crate::ptr::PhysicsStatePtr)] + physics_state: &mut PhysicsState, + #[dropbear_macro::entity] + entity: hecs::Entity, + rotation: &NQuaternion, +) -> DropbearNativeResult<()> { + if let Ok((label, _)) = world.query_one::<(&Label, &KCC)>(entity).get() { + let rigid_body_handle = physics_state + .bodies_entity_map + .get(label) + .ok_or(DropbearNativeError::NoSuchHandle)?; + + let body_type = { + let body = physics_state + .bodies + .get(*rigid_body_handle) + .ok_or(DropbearNativeError::PhysicsObjectNotFound)?; + body.body_type() }; - let out = match env.new_object_array(kcc.collisions.len() as jint, &collision_cls, JObject::null()) { - Ok(arr) => arr, - Err(e) => { - eprintln!("[JNI Error] Failed to allocate CharacterCollision array: {:?}", e); - let _ = env.throw_new("java/lang/OutOfMemoryError", "Could not allocate CharacterCollision array"); - return std::ptr::null_mut(); - } - }; + if body_type != RigidBodyType::KinematicPositionBased { + return Err(DropbearNativeError::InvalidArgument); + } - let entity_id_obj = match env.new_object(&entity_cls, "(J)V", &[JValue::Long(entity.to_bits().get() as i64)]) { - Ok(obj) => obj, - Err(e) => { - eprintln!("[JNI Error] Failed to create EntityId object: {:?}", e); - return std::ptr::null_mut(); - } + let len = (rotation.x * rotation.x + + rotation.y * rotation.y + + rotation.z * rotation.z + + rotation.w * rotation.w) + .sqrt(); + let (x, y, z, w) = if len > 0.0 { + ( + rotation.x / len, + rotation.y / len, + rotation.z / len, + rotation.w / len, + ) + } else { + (0.0, 0.0, 0.0, 1.0) }; - for (i, _) in kcc.collisions.iter().enumerate() { - let collision = &kcc.collisions[i]; - let (idx, generation) = collision.handle.into_raw_parts(); - let index_obj = match (IndexNative { - index: idx, - generation, - }) - .to_jobject(&mut env) - { - Ok(obj) => obj, - Err(e) => { - eprintln!("[JNI Error] Failed to create Index object: {e}"); - return std::ptr::null_mut(); - } - }; - - let collision_obj = match env.new_object( - &collision_cls, - "(Lcom/dropbear/EntityId;Lcom/dropbear/physics/Index;)V", - &[JValue::Object(&entity_id_obj), JValue::Object(&index_obj)], - ) { - Ok(obj) => obj, - Err(e) => { - eprintln!("[JNI Error] Failed to create CharacterCollision object: {:?}", e); - return std::ptr::null_mut(); - } - }; - - if let Err(e) = env.set_object_array_element(&out, i as jint, collision_obj) { - eprintln!("[JNI Error] Failed to set array element: {:?}", e); - return std::ptr::null_mut(); - } + if let Some(body) = physics_state.bodies.get_mut(*rigid_body_handle) { + let rot = Rotation::from_xyzw(x as f32, y as f32, z as f32, w as f32); + body.set_next_kinematic_rotation(rot); } - out.into_raw() + Ok(()) + } else { + Err(DropbearNativeError::MissingComponent) } +} + +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.KinematicCharacterControllerNative", func = "getHit"), + c +)] +fn get_hit( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::entity] + entity: hecs::Entity, +) -> DropbearNativeResult<CharacterCollisionArray> { + let kcc = world + .get::<&KCC>(entity) + .map_err(|_| DropbearNativeError::NoSuchComponent)?; + + let mut collisions = Vec::with_capacity(kcc.collisions.len()); + for collision in &kcc.collisions { + let (idx, generation) = collision.handle.into_raw_parts(); + collisions.push(IndexNative { index: idx, generation }); + } + + Ok(CharacterCollisionArray { + entity_id: entity.to_bits().get(), + collisions, + }) } @@ -3,16 +3,16 @@ use ::jni::objects::{JObject, JValue}; use crate::scripting::jni::utils::ToJObject; use crate::scripting::native::DropbearNativeError; use crate::scripting::result::DropbearNativeResult; -use crate::types::{NCollider, IndexNative, NVector3}; -use dropbear_engine::entity::Transform as DbTransform; +use crate::types::{IndexNative, NCollider, NShapeCastStatus, NTransform, NVector3}; +use dropbear_engine::entity::Transform; use hecs::{Entity, World}; use rapier3d::control::CharacterCollision; -use rapier3d::parry::query::ShapeCastStatus; use crate::physics::collider::ColliderGroup; use crate::physics::kcc::KCC; +use crate::ptr::WorldPtr; -fn get_collision_from_world(world: &World, entity: Entity, collision_handle: IndexNative) -> DropbearNativeResult<CharacterCollision> { +fn get_collision_from_world(world: &World, entity: Entity, collision_handle: &IndexNative) -> DropbearNativeResult<CharacterCollision> { let kcc = world .get::<&KCC>(entity) .map_err(|_| DropbearNativeError::NoSuchComponent)?; @@ -43,17 +43,17 @@ fn collider_ffi_from_handle(world: &World, handle: rapier3d::prelude::ColliderHa None } -impl ToJObject for ShapeCastStatus { +impl ToJObject for NShapeCastStatus { fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { let class = env .find_class("com/dropbear/physics/ShapeCastStatus") .map_err(|_| DropbearNativeError::JNIClassNotFound)?; let name = match self { - ShapeCastStatus::OutOfIterations => "OutOfIterations", - ShapeCastStatus::Converged => "Converged", - ShapeCastStatus::Failed => "Failed", - ShapeCastStatus::PenetratingOrWithinTargetDist => "PenetratingOrWithinTargetDist", + NShapeCastStatus::OutOfIterations => "OutOfIterations", + NShapeCastStatus::Converged => "Converged", + NShapeCastStatus::Failed => "Failed", + NShapeCastStatus::PenetratingOrWithinTargetDist => "PenetratingOrWithinTargetDist", }; let name_jstring = env @@ -79,389 +79,212 @@ pub mod shared { use super::*; use glam::{DQuat, DVec3}; use rapier3d::na::Quaternion; + use crate::types::NVector3; - pub fn get_collider(world: &World, entity: Entity, collision_handle: IndexNative) -> DropbearNativeResult<NCollider> { - let collision = super::get_collision_from_world(world, entity, collision_handle)?; + pub fn get_collider(world: &World, entity: Entity, collision_handle: &IndexNative) -> DropbearNativeResult<NCollider> { + let collision = get_collision_from_world(world, entity, collision_handle)?; collider_ffi_from_handle(world, collision.handle) .ok_or(DropbearNativeError::PhysicsObjectNotFound) } - pub fn get_character_position(world: &World, entity: Entity, collision_handle: IndexNative) -> DropbearNativeResult<DbTransform> { - let collision = super::get_collision_from_world(world, entity, collision_handle)?; + pub fn get_character_position(world: &World, entity: Entity, collision_handle: &IndexNative) -> DropbearNativeResult<NTransform> { + let collision = get_collision_from_world(world, entity, collision_handle)?; let iso = collision.character_pos; let t = iso.translation; let rot = iso.rotation; let q: Quaternion<f32> = Quaternion::from(rot); - Ok(DbTransform { - position: DVec3::new(t.x as f64, t.y as f64, t.z as f64), - rotation: DQuat::from_xyzw(q.i as f64, q.j as f64, q.k as f64, q.w as f64), - scale: DVec3::ONE, + Ok(NTransform { + position: DVec3::new(t.x as f64, t.y as f64, t.z as f64).into(), + rotation: DQuat::from_xyzw(q.i as f64, q.j as f64, q.k as f64, q.w as f64).into(), + scale: DVec3::ONE.into(), }) } - pub fn get_translation_applied(world: &World, entity: Entity, collision_handle: IndexNative) -> DropbearNativeResult<NVector3> { - let collision = super::get_collision_from_world(world, entity, collision_handle)?; + pub fn get_translation_applied(world: &World, entity: Entity, collision_handle: &IndexNative) -> DropbearNativeResult<NVector3> { + let collision = get_collision_from_world(world, entity, collision_handle)?; let v = collision.translation_applied; Ok(NVector3 { x: v.x as f64, y: v.y as f64, z: v.z as f64 }) } - pub fn get_translation_remaining(world: &World, entity: Entity, collision_handle: IndexNative) -> DropbearNativeResult<NVector3> { - let collision = super::get_collision_from_world(world, entity, collision_handle)?; + pub fn get_translation_remaining(world: &World, entity: Entity, collision_handle: &IndexNative) -> DropbearNativeResult<NVector3> { + let collision = get_collision_from_world(world, entity, collision_handle)?; let v = collision.translation_remaining; Ok(NVector3 { x: v.x as f64, y: v.y as f64, z: v.z as f64 }) } - pub fn get_time_of_impact(world: &World, entity: Entity, collision_handle: IndexNative) -> DropbearNativeResult<f64> { - let collision = super::get_collision_from_world(world, entity, collision_handle)?; + pub fn get_time_of_impact(world: &World, entity: Entity, collision_handle: &IndexNative) -> DropbearNativeResult<f64> { + let collision = get_collision_from_world(world, entity, collision_handle)?; Ok(collision.hit.time_of_impact as f64) } - pub fn get_witness1(world: &World, entity: Entity, collision_handle: IndexNative) -> DropbearNativeResult<NVector3> { - let collision = super::get_collision_from_world(world, entity, collision_handle)?; + pub fn get_witness1(world: &World, entity: Entity, collision_handle: &IndexNative) -> DropbearNativeResult<NVector3> { + let collision = get_collision_from_world(world, entity, collision_handle)?; let p = collision.hit.witness1; Ok(NVector3 { x: p.x as f64, y: p.y as f64, z: p.z as f64 }) } - pub fn get_witness2(world: &World, entity: Entity, collision_handle: IndexNative) -> DropbearNativeResult<NVector3> { - let collision = super::get_collision_from_world(world, entity, collision_handle)?; + pub fn get_witness2(world: &World, entity: Entity, collision_handle: &IndexNative) -> DropbearNativeResult<NVector3> { + let collision = get_collision_from_world(world, entity, collision_handle)?; let p = collision.hit.witness2; Ok(NVector3 { x: p.x as f64, y: p.y as f64, z: p.z as f64 }) } - pub fn get_normal1(world: &World, entity: Entity, collision_handle: IndexNative) -> DropbearNativeResult<NVector3> { - let collision = super::get_collision_from_world(world, entity, collision_handle)?; + pub fn get_normal1(world: &World, entity: Entity, collision_handle: &IndexNative) -> DropbearNativeResult<NVector3> { + let collision = get_collision_from_world(world, entity, collision_handle)?; let n = collision.hit.normal1; Ok(NVector3 { x: n.x as f64, y: n.y as f64, z: n.z as f64 }) } - pub fn get_normal2(world: &World, entity: Entity, collision_handle: IndexNative) -> DropbearNativeResult<NVector3> { - let collision = super::get_collision_from_world(world, entity, collision_handle)?; + pub fn get_normal2(world: &World, entity: Entity, collision_handle: &IndexNative) -> DropbearNativeResult<NVector3> { + let collision = get_collision_from_world(world, entity, collision_handle)?; let n = collision.hit.normal2; Ok(NVector3 { x: n.x as f64, y: n.y as f64, z: n.z as f64 }) } - pub fn get_status(world: &World, entity: Entity, collision_handle: IndexNative) -> DropbearNativeResult<ShapeCastStatus> { - let collision = super::get_collision_from_world(world, entity, collision_handle)?; - Ok(collision.hit.status) + pub fn get_status(world: &World, entity: Entity, collision_handle: &IndexNative) -> DropbearNativeResult<NShapeCastStatus> { + let collision = get_collision_from_world(world, entity, collision_handle)?; + Ok(collision.hit.status.into()) } } -pub mod jni { - #![allow(non_snake_case)] - - use hecs::World; - use jni::objects::JClass; - use jni::sys::{jdouble, jlong, jobject}; - use jni::JNIEnv; - use crate::convert_jlong_to_entity; - use crate::convert_ptr; - use crate::scripting::jni::utils::{FromJObject, ToJObject}; - use crate::types::IndexNative; - use jni::objects::JObject; - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_CharacterCollisionNative_getCollider( - mut env: JNIEnv, - _: JClass, - world_handle: jlong, - entity: jlong, - collision_handle: JObject, - ) -> jobject { - let world = convert_ptr!(world_handle => World); - let entity = convert_jlong_to_entity!(entity); - - let Ok(index_native) = IndexNative::from_jobject(&mut env, &collision_handle) else { - let _ = env.throw_new("java/lang/RuntimeException", "Failed to read Index for collision handle"); - return std::ptr::null_mut(); - }; - - match super::shared::get_collider(&world, entity, index_native) { - Ok(ffi) => match ffi.to_jobject(&mut env) { - Ok(obj) => obj.into_raw(), - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to create Collider object: {e}")); - std::ptr::null_mut() - } - }, - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to resolve collider: {e:?}")); - std::ptr::null_mut() - } - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_CharacterCollisionNative_getCharacterPosition( - mut env: JNIEnv, - _: JClass, - world_handle: jlong, - entity: jlong, - collision_handle: JObject, - ) -> jobject { - let world = convert_ptr!(world_handle => World); - let entity = convert_jlong_to_entity!(entity); - - let Ok(index_native) = IndexNative::from_jobject(&mut env, &collision_handle) else { - let _ = env.throw_new("java/lang/RuntimeException", "Failed to read Index for collision handle"); - return std::ptr::null_mut(); - }; - - match super::shared::get_character_position(&world, entity, index_native) { - Ok(transform) => match transform.to_jobject(&mut env) { - Ok(obj) => obj.into_raw(), - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to create Transform object: {e}")); - std::ptr::null_mut() - } - }, - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to resolve character position: {e:?}")); - std::ptr::null_mut() - } - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_CharacterCollisionNative_getTranslationApplied( - mut env: JNIEnv, - _: JClass, - world_handle: jlong, - entity: jlong, - collision_handle: JObject, - ) -> jobject { - let world = convert_ptr!(world_handle => World); - let entity = convert_jlong_to_entity!(entity); - - let Ok(index_native) = IndexNative::from_jobject(&mut env, &collision_handle) else { - let _ = env.throw_new("java/lang/RuntimeException", "Failed to read Index for collision handle"); - return std::ptr::null_mut(); - }; - - match super::shared::get_translation_applied(&world, entity, index_native) { - Ok(v) => match v.to_jobject(&mut env) { - Ok(obj) => obj.into_raw(), - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to create Vector3d: {e}")); - std::ptr::null_mut() - } - }, - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to resolve translation applied: {e:?}")); - std::ptr::null_mut() - } - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_CharacterCollisionNative_getTranslationRemaining( - mut env: JNIEnv, - _: JClass, - world_handle: jlong, - entity: jlong, - collision_handle: JObject, - ) -> jobject { - let world = convert_ptr!(world_handle => World); - let entity = convert_jlong_to_entity!(entity); - - let Ok(index_native) = IndexNative::from_jobject(&mut env, &collision_handle) else { - let _ = env.throw_new("java/lang/RuntimeException", "Failed to read Index for collision handle"); - return std::ptr::null_mut(); - }; - - match super::shared::get_translation_remaining(&world, entity, index_native) { - Ok(v) => match v.to_jobject(&mut env) { - Ok(obj) => obj.into_raw(), - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to create Vector3d: {e}")); - std::ptr::null_mut() - } - }, - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to resolve translation remaining: {e:?}")); - std::ptr::null_mut() - } - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_CharacterCollisionNative_getTimeOfImpact( - mut env: JNIEnv, - _: JClass, - world_handle: jlong, - entity: jlong, - collision_handle: JObject, - ) -> jdouble { - let world = convert_ptr!(world_handle => World); - let entity = convert_jlong_to_entity!(entity); - - let Ok(index_native) = IndexNative::from_jobject(&mut env, &collision_handle) else { - let _ = env.throw_new("java/lang/RuntimeException", "Failed to read Index for collision handle"); - return -1.0 as jdouble; - }; - - match super::shared::get_time_of_impact(&world, entity, index_native) { - Ok(v) => v as jdouble, - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to resolve time of impact: {e:?}")); - -1.0 as jdouble - } - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_CharacterCollisionNative_getWitness1( - mut env: JNIEnv, - _: JClass, - world_handle: jlong, - entity: jlong, - collision_handle: JObject, - ) -> jobject { - let world = convert_ptr!(world_handle => World); - let entity = convert_jlong_to_entity!(entity); - - let Ok(index_native) = IndexNative::from_jobject(&mut env, &collision_handle) else { - let _ = env.throw_new("java/lang/RuntimeException", "Failed to read Index for collision handle"); - return std::ptr::null_mut(); - }; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.CharacterCollisionNative", func = "getCollider"), + c +)] +fn get_character_collision_collider( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::entity] + entity: hecs::Entity, + collision_handle: &IndexNative, +) -> DropbearNativeResult<crate::types::NCollider> { + shared::get_collider(world, entity, collision_handle) +} - match super::shared::get_witness1(&world, entity, index_native) { - Ok(v) => match v.to_jobject(&mut env) { - Ok(obj) => obj.into_raw(), - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to create Vector3d: {e}")); - std::ptr::null_mut() - } - }, - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to resolve witness1: {e:?}")); - std::ptr::null_mut() - } - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.CharacterCollisionNative", func = "getCharacterPosition"), + c +)] +fn get_character_collision_position( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::entity] + entity: hecs::Entity, + collision_handle: &IndexNative, +) -> DropbearNativeResult<NTransform> { + shared::get_character_position(world, entity, collision_handle) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_CharacterCollisionNative_getWitness2( - mut env: JNIEnv, - _: JClass, - world_handle: jlong, - entity: jlong, - collision_handle: JObject, - ) -> jobject { - let world = convert_ptr!(world_handle => World); - let entity = convert_jlong_to_entity!(entity); - - let Ok(index_native) = IndexNative::from_jobject(&mut env, &collision_handle) else { - let _ = env.throw_new("java/lang/RuntimeException", "Failed to read Index for collision handle"); - return std::ptr::null_mut(); - }; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.CharacterCollisionNative", func = "getTranslationApplied"), + c +)] +fn get_character_collision_translation_applied( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::entity] + entity: hecs::Entity, + collision_handle: &IndexNative, +) -> DropbearNativeResult<NVector3> { + shared::get_translation_applied(world, entity, collision_handle) +} - match super::shared::get_witness2(&world, entity, index_native) { - Ok(v) => match v.to_jobject(&mut env) { - Ok(obj) => obj.into_raw(), - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to create Vector3d: {e}")); - std::ptr::null_mut() - } - }, - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to resolve witness2: {e:?}")); - std::ptr::null_mut() - } - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.CharacterCollisionNative", func = "getTranslationRemaining"), + c +)] +fn get_character_collision_translation_remaining( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::entity] + entity: hecs::Entity, + collision_handle: &IndexNative, +) -> DropbearNativeResult<NVector3> { + shared::get_translation_remaining(world, entity, collision_handle) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_CharacterCollisionNative_getNormal1( - mut env: JNIEnv, - _: JClass, - world_handle: jlong, - entity: jlong, - collision_handle: JObject, - ) -> jobject { - let world = convert_ptr!(world_handle => World); - let entity = convert_jlong_to_entity!(entity); - - let Ok(index_native) = IndexNative::from_jobject(&mut env, &collision_handle) else { - let _ = env.throw_new("java/lang/RuntimeException", "Failed to read Index for collision handle"); - return std::ptr::null_mut(); - }; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.CharacterCollisionNative", func = "getTimeOfImpact"), + c +)] +fn get_character_collision_time_of_impact( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::entity] + entity: hecs::Entity, + collision_handle: &IndexNative, +) -> DropbearNativeResult<f64> { + shared::get_time_of_impact(world, entity, collision_handle) +} - match super::shared::get_normal1(&world, entity, index_native) { - Ok(v) => match v.to_jobject(&mut env) { - Ok(obj) => obj.into_raw(), - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to create Vector3d: {e}")); - std::ptr::null_mut() - } - }, - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to resolve normal1: {e:?}")); - std::ptr::null_mut() - } - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.CharacterCollisionNative", func = "getWitness1"), + c +)] +fn get_character_collision_witness1( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::entity] + entity: hecs::Entity, + collision_handle: &IndexNative, +) -> DropbearNativeResult<NVector3> { + shared::get_witness1(world, entity, collision_handle) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_CharacterCollisionNative_getNormal2( - mut env: JNIEnv, - _: JClass, - world_handle: jlong, - entity: jlong, - collision_handle: JObject, - ) -> jobject { - let world = convert_ptr!(world_handle => World); - let entity = convert_jlong_to_entity!(entity); - - let Ok(index_native) = IndexNative::from_jobject(&mut env, &collision_handle) else { - let _ = env.throw_new("java/lang/RuntimeException", "Failed to read Index for collision handle"); - return std::ptr::null_mut(); - }; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.CharacterCollisionNative", func = "getWitness2"), + c +)] +fn get_character_collision_witness2( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::entity] + entity: hecs::Entity, + collision_handle: &IndexNative, +) -> DropbearNativeResult<NVector3> { + shared::get_witness2(world, entity, collision_handle) +} - match super::shared::get_normal2(&world, entity, index_native) { - Ok(v) => match v.to_jobject(&mut env) { - Ok(obj) => obj.into_raw(), - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to create Vector3d: {e}")); - std::ptr::null_mut() - } - }, - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to resolve normal2: {e:?}")); - std::ptr::null_mut() - } - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.CharacterCollisionNative", func = "getNormal1"), + c +)] +fn get_character_collision_normal1( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::entity] + entity: hecs::Entity, + collision_handle: &IndexNative, +) -> DropbearNativeResult<NVector3> { + shared::get_normal1(world, entity, collision_handle) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_CharacterCollisionNative_getStatus( - mut env: JNIEnv, - _: JClass, - world_handle: jlong, - entity: jlong, - collision_handle: JObject, - ) -> jobject { - let world = convert_ptr!(world_handle => World); - let entity = convert_jlong_to_entity!(entity); - - let Ok(index_native) = IndexNative::from_jobject(&mut env, &collision_handle) else { - let _ = env.throw_new("java/lang/RuntimeException", "Failed to read Index for collision handle"); - return std::ptr::null_mut(); - }; +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.CharacterCollisionNative", func = "getNormal2"), + c +)] +fn get_character_collision_normal2( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::entity] + entity: hecs::Entity, + collision_handle: &IndexNative, +) -> DropbearNativeResult<NVector3> { + shared::get_normal2(world, entity, collision_handle) +} - match super::shared::get_status(&world, entity, index_native) { - Ok(status) => match status.to_jobject(&mut env) { - Ok(obj) => obj.into_raw(), - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to create ShapeCastStatus: {e}")); - std::ptr::null_mut() - } - }, - Err(e) => { - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to resolve status: {e:?}")); - std::ptr::null_mut() - } - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.CharacterCollisionNative", func = "getStatus"), + c +)] +fn get_character_collision_status( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::entity] + entity: hecs::Entity, + collision_handle: &IndexNative, +) -> DropbearNativeResult<NShapeCastStatus> { + shared::get_status(world, entity, collision_handle) } @@ -10,6 +10,9 @@ use ::jni::objects::{JObject, JValue}; use ::jni::JNIEnv; use rapier3d::prelude::RigidBodyType; use serde::{Deserialize, Serialize}; +use crate::types::{IndexNative, NCollider, RigidBodyContext, NVector3}; +use crate::physics::PhysicsState; +use crate::ptr::{PhysicsStatePtr, WorldPtr}; /// How this entity behaves in the physics simulation. /// @@ -226,7 +229,7 @@ pub mod shared { } } - pub fn get_rigidbody_type(physics: &PhysicsState, rb_context: RigidBodyContext) -> DropbearNativeResult<RigidBodyType> { + pub fn get_rigidbody_type(physics: &PhysicsState, rb_context: &RigidBodyContext) -> DropbearNativeResult<RigidBodyType> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get(handle) { Ok(rb.body_type()) @@ -235,7 +238,7 @@ pub mod shared { } } - pub fn set_rigidbody_type(physics: &mut PhysicsState, world: &World, rb_context: RigidBodyContext, mode: i64) -> DropbearNativeResult<()> { + pub fn set_rigidbody_type(physics: &mut PhysicsState, world: &World, rb_context: &RigidBodyContext, mode: i64) -> DropbearNativeResult<()> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get_mut(handle) { let mode = match mode { @@ -260,7 +263,7 @@ pub mod shared { } } - pub fn get_rigidbody_gravity_scale(physics: &PhysicsState, rb_context: RigidBodyContext) -> DropbearNativeResult<f64> { + pub fn get_rigidbody_gravity_scale(physics: &PhysicsState, rb_context: &RigidBodyContext) -> DropbearNativeResult<f64> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get(handle) { Ok(rb.gravity_scale().into()) @@ -269,7 +272,7 @@ pub mod shared { } } - pub fn set_rigidbody_gravity_scale(physics: &mut PhysicsState, world: &World, rb_context: RigidBodyContext, new_scale: f64) -> DropbearNativeResult<()> { + pub fn set_rigidbody_gravity_scale(physics: &mut PhysicsState, world: &World, rb_context: &RigidBodyContext, new_scale: f64) -> DropbearNativeResult<()> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get_mut(handle) { rb.set_gravity_scale(new_scale as f32, true); @@ -286,7 +289,7 @@ pub mod shared { } } - pub fn get_rigidbody_linear_damping(physics: &PhysicsState, rb_context: RigidBodyContext) -> DropbearNativeResult<f64> { + pub fn get_rigidbody_linear_damping(physics: &PhysicsState, rb_context: &RigidBodyContext) -> DropbearNativeResult<f64> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get(handle) { Ok(rb.linear_damping().into()) @@ -295,7 +298,7 @@ pub mod shared { } } - pub fn set_rigidbody_linear_damping(physics: &mut PhysicsState, world: &World, rb_context: RigidBodyContext, new: f64) -> DropbearNativeResult<()> { + pub fn set_rigidbody_linear_damping(physics: &mut PhysicsState, world: &World, rb_context: &RigidBodyContext, new: f64) -> DropbearNativeResult<()> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get_mut(handle) { rb.set_linear_damping(new as f32); @@ -312,7 +315,7 @@ pub mod shared { } } - pub fn get_rigidbody_angular_damping(physics: &PhysicsState, rb_context: RigidBodyContext) -> DropbearNativeResult<f64> { + pub fn get_rigidbody_angular_damping(physics: &PhysicsState, rb_context: &RigidBodyContext) -> DropbearNativeResult<f64> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get(handle) { Ok(rb.angular_damping().into()) @@ -321,7 +324,7 @@ pub mod shared { } } - pub fn set_rigidbody_angular_damping(physics: &mut PhysicsState, world: &World, rb_context: RigidBodyContext, new: f64) -> DropbearNativeResult<()> { + pub fn set_rigidbody_angular_damping(physics: &mut PhysicsState, world: &World, rb_context: &RigidBodyContext, new: f64) -> DropbearNativeResult<()> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get_mut(handle) { rb.set_angular_damping(new as f32); @@ -338,7 +341,7 @@ pub mod shared { } } - pub fn get_rigidbody_sleep(physics: &PhysicsState, rb_context: RigidBodyContext) -> DropbearNativeResult<bool> { + pub fn get_rigidbody_sleep(physics: &PhysicsState, rb_context: &RigidBodyContext) -> DropbearNativeResult<bool> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get(handle) { Ok(rb.is_sleeping().into()) @@ -347,7 +350,7 @@ pub mod shared { } } - pub fn set_rigidbody_sleep(physics: &mut PhysicsState, world: &World, rb_context: RigidBodyContext, new: bool) -> DropbearNativeResult<()> { + pub fn set_rigidbody_sleep(physics: &mut PhysicsState, world: &World, rb_context: &RigidBodyContext, new: bool) -> DropbearNativeResult<()> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get_mut(handle) { if new { @@ -368,7 +371,7 @@ pub mod shared { } } - pub fn get_rigidbody_ccd(physics: &PhysicsState, rb_context: RigidBodyContext) -> DropbearNativeResult<bool> { + pub fn get_rigidbody_ccd(physics: &PhysicsState, rb_context: &RigidBodyContext) -> DropbearNativeResult<bool> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get(handle) { Ok(rb.is_ccd_enabled().into()) @@ -377,7 +380,7 @@ pub mod shared { } } - pub fn set_rigidbody_ccd(physics: &mut PhysicsState, world: &World, rb_context: RigidBodyContext, new: bool) -> DropbearNativeResult<()> { + pub fn set_rigidbody_ccd(physics: &mut PhysicsState, world: &World, rb_context: &RigidBodyContext, new: bool) -> DropbearNativeResult<()> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get_mut(handle) { rb.enable_ccd(new); @@ -394,7 +397,7 @@ pub mod shared { } } - pub fn get_rigidbody_linvel(physics: &PhysicsState, rb_context: RigidBodyContext) -> DropbearNativeResult<NVector3> { + pub fn get_rigidbody_linvel(physics: &PhysicsState, rb_context: &RigidBodyContext) -> DropbearNativeResult<NVector3> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get(handle) { let linvel = rb.linvel().clone(); @@ -404,7 +407,7 @@ pub mod shared { } } - pub fn set_rigidbody_linvel(physics: &mut PhysicsState, world: &World, rb_context: RigidBodyContext, new: NVector3) -> DropbearNativeResult<()> { + pub fn set_rigidbody_linvel(physics: &mut PhysicsState, world: &World, rb_context: &RigidBodyContext, new: NVector3) -> DropbearNativeResult<()> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get_mut(handle) { rb.set_linvel(Vector::new(new.x as f32, new.y as f32, new.z as f32), true); @@ -421,7 +424,7 @@ pub mod shared { } } - pub fn get_rigidbody_angvel(physics: &PhysicsState, rb_context: RigidBodyContext) -> DropbearNativeResult<NVector3> { + pub fn get_rigidbody_angvel(physics: &PhysicsState, rb_context: &RigidBodyContext) -> DropbearNativeResult<NVector3> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get(handle) { let angvel = rb.angvel().clone(); @@ -431,7 +434,7 @@ pub mod shared { } } - pub fn set_rigidbody_angvel(physics: &mut PhysicsState, world: &World, rb_context: RigidBodyContext, new: NVector3) -> DropbearNativeResult<()> { + pub fn set_rigidbody_angvel(physics: &mut PhysicsState, world: &World, rb_context: &RigidBodyContext, new: NVector3) -> DropbearNativeResult<()> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get_mut(handle) { rb.set_angvel(Vector::new(new.x as f32, new.y as f32, new.z as f32), true); @@ -448,7 +451,7 @@ pub mod shared { } } - pub fn get_rigidbody_lock_translation(physics: &PhysicsState, rb_context: RigidBodyContext) -> DropbearNativeResult<AxisLock> { + pub fn get_rigidbody_lock_translation(physics: &PhysicsState, rb_context: &RigidBodyContext) -> DropbearNativeResult<AxisLock> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get(handle) { let lock = rb.locked_axes(); @@ -463,7 +466,7 @@ pub mod shared { } } - pub fn set_rigidbody_lock_translation(physics: &mut PhysicsState, world: &World, rb_context: RigidBodyContext, new: AxisLock) -> DropbearNativeResult<()> { + pub fn set_rigidbody_lock_translation(physics: &mut PhysicsState, world: &World, rb_context: &RigidBodyContext, new: AxisLock) -> DropbearNativeResult<()> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get_mut(handle) { let mut bits = rb.locked_axes().clone(); @@ -496,7 +499,7 @@ pub mod shared { } } - pub fn get_rigidbody_lock_rotation(physics: &PhysicsState, rb_context: RigidBodyContext) -> DropbearNativeResult<AxisLock> { + pub fn get_rigidbody_lock_rotation(physics: &PhysicsState, rb_context: &RigidBodyContext) -> DropbearNativeResult<AxisLock> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get(handle) { let lock = rb.locked_axes(); @@ -511,7 +514,7 @@ pub mod shared { } } - pub fn set_rigidbody_lock_rotation(physics: &mut PhysicsState, world: &World, rb_context: RigidBodyContext, new: AxisLock) -> DropbearNativeResult<()> { + pub fn set_rigidbody_lock_rotation(physics: &mut PhysicsState, world: &World, rb_context: &RigidBodyContext, new: AxisLock) -> DropbearNativeResult<()> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get_mut(handle) { let mut bits = rb.locked_axes().clone(); @@ -544,7 +547,7 @@ pub mod shared { } } - pub fn get_rigidbody_children(physics: &PhysicsState, rb_context: RigidBodyContext) -> DropbearNativeResult<Vec<ColliderHandle>> { + pub fn get_rigidbody_children(physics: &PhysicsState, rb_context: &RigidBodyContext) -> DropbearNativeResult<Vec<ColliderHandle>> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get(handle) { let children = rb.colliders().to_vec(); @@ -554,7 +557,7 @@ pub mod shared { } } - pub fn apply_impulse(physics: &mut PhysicsState, _world: &World, rb_context: RigidBodyContext, new: NVector3) -> DropbearNativeResult<()> { + pub fn apply_impulse(physics: &mut PhysicsState, _world: &World, rb_context: &RigidBodyContext, new: NVector3) -> DropbearNativeResult<()> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get_mut(handle) { rb.apply_impulse(Vector::new(new.x as f32, new.y as f32, new.z as f32), true); @@ -565,7 +568,7 @@ pub mod shared { } } - pub fn apply_torque_impulse(physics: &mut PhysicsState, _world: &World, rb_context: RigidBodyContext, new: NVector3) -> DropbearNativeResult<()> { + pub fn apply_torque_impulse(physics: &mut PhysicsState, _world: &World, rb_context: &RigidBodyContext, new: NVector3) -> DropbearNativeResult<()> { let handle = RigidBodyHandle::from_raw_parts(rb_context.index.index, rb_context.index.generation); if let Some(rb) = physics.bodies.get_mut(handle) { rb.apply_torque_impulse(Vector::new(new.x as f32, new.y as f32, new.z as f32), true); @@ -577,710 +580,376 @@ pub mod shared { } } -pub mod jni { - #![allow(non_snake_case)] - use crate::physics::rigidbody::AxisLock; - use crate::physics::PhysicsState; - use crate::scripting::jni::utils::{FromJObject, ToJObject}; - use crate::types::{IndexNative, RigidBodyContext, NVector3}; - use crate::{convert_jlong_to_entity, convert_ptr}; - use hecs::World; - use jni::objects::{JClass, JObject}; - use jni::sys::{jboolean, jdouble, jint, jlong, jobject, jobjectArray, jsize}; - use jni::JNIEnv; - use rapier3d::dynamics::RigidBodyType; - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_rigidBodyExistsForEntity( - mut env: JNIEnv, - _: JClass, - world_ptr: jlong, - physics_ptr: jlong, - entity_id: jlong, - ) -> jobject { - let world = convert_ptr!(world_ptr => World); - let physics = convert_ptr!(physics_ptr => PhysicsState); - let entity = convert_jlong_to_entity!(entity_id); - - match super::shared::rigid_body_exists_for_entity(world, physics, entity) { - Some(v) => { - match v.to_jobject(&mut env) { - Ok(val) => val.into_raw(), - Err(e) => { - eprintln!("Failed to create new Index jobject: {}", e); - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to create new Index jobject: {}", e)); - std::ptr::null_mut() - } - } - } - None => std::ptr::null_mut() - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_getRigidBodyMode( - mut env: JNIEnv, - _: JClass, - _world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - ) -> jint { - let physics = convert_ptr!(physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", "Unable to convert com/dropbear/physics/RigidBody into a Rust rigidbody"); - return -1 as jint; - }; - - match super::shared::get_rigidbody_type(physics, rb_context) { - Ok(v) => { - match v { - RigidBodyType::Dynamic => 0 as jint, - RigidBodyType::Fixed => 1 as jint, - RigidBodyType::KinematicPositionBased => 2 as jint, - RigidBodyType::KinematicVelocityBased => 3 as jint, - } - } - Err(e) => { - eprintln!("Failed to get RigidBody type: {}", e); - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to get RigidBody type: {}", e)); - -1 as jint - } - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "rigidBodyExistsForEntity"), + c +)] +fn rigid_body_exists_for_entity( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + #[dropbear_macro::entity] + entity: hecs::Entity, +) -> DropbearNativeResult<Option<IndexNative>> { + Ok(shared::rigid_body_exists_for_entity(world, physics, entity)) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_setRigidBodyMode( - mut env: JNIEnv, - _: JClass, - world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - mode: jint, - ) { - let world = convert_ptr!(world_ptr => World); - let mut physics = convert_ptr!(mut physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return; - }; - - if let Err(e) = super::shared::set_rigidbody_type(&mut physics, world, rb_context, mode as i64) { - eprintln!("Failed to set RigidBody Type: {}", e); - let _ = env.throw_new("java/lang/IllegalArgumentException", format!("Failed to set RigidBody type: {}", e)); - return; - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "getRigidBodyMode"), + c +)] +fn get_rigidbody_mode( + #[dropbear_macro::define(WorldPtr)] + _world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + rigidbody: &RigidBodyContext, +) -> DropbearNativeResult<i32> { + let body_type = shared::get_rigidbody_type(physics, rigidbody)?; + Ok(match body_type { + RigidBodyType::Dynamic => 0, + RigidBodyType::Fixed => 1, + RigidBodyType::KinematicPositionBased => 2, + RigidBodyType::KinematicVelocityBased => 3, + }) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_getRigidBodyGravityScale( - mut env: JNIEnv, - _: JClass, - _world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - ) -> jdouble { - let physics = convert_ptr!(physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return -1 as jdouble; - }; - - match super::shared::get_rigidbody_gravity_scale(physics, rb_context) { - Ok(v) => v as jdouble, - Err(e) => { - eprintln!("Failed to get RigidBody component: {}", e); - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to get RigidBody component: {}", e)); - -1 as jdouble - } - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "setRigidBodyMode"), + c +)] +fn set_rigidbody_mode( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + rigidbody: &RigidBodyContext, + mode: i32, +) -> DropbearNativeResult<()> { + shared::set_rigidbody_type(physics, world, rigidbody, mode as i64) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_setRigidBodyGravityScale( - mut env: JNIEnv, - _: JClass, - world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - gravity_scale: jdouble, - ) { - let world = convert_ptr!(world_ptr => World); - let mut physics = convert_ptr!(mut physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return; - }; - - if let Err(e) = super::shared::set_rigidbody_gravity_scale(&mut physics, world, rb_context, gravity_scale as f64) { - eprintln!("Failed to set RigidBody gravity scale: {}", e); - let _ = env.throw_new("java/lang/IllegalArgumentException", format!("Failed to set RigidBody gravity scale: {}", e)); - return; - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "getRigidBodyGravityScale"), + c +)] +fn get_rigidbody_gravity_scale( + #[dropbear_macro::define(WorldPtr)] + _world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + rigidbody: &RigidBodyContext, +) -> DropbearNativeResult<f64> { + shared::get_rigidbody_gravity_scale(physics, rigidbody) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_getRigidBodyLinearDamping( - mut env: JNIEnv, - _: JClass, - _world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - ) -> jdouble { - let physics = convert_ptr!(physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return -1 as jdouble; - }; - - match super::shared::get_rigidbody_linear_damping(physics, rb_context) { - Ok(v) => v as jdouble, - Err(e) => { - eprintln!("Failed to get RigidBody linear damping: {}", e); - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to get RigidBody linear damping: {}", e)); - -1 as jdouble - } - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "setRigidBodyGravityScale"), + c +)] +fn set_rigidbody_gravity_scale( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + rigidbody: &RigidBodyContext, + gravity_scale: f64, +) -> DropbearNativeResult<()> { + shared::set_rigidbody_gravity_scale(physics, world, rigidbody, gravity_scale) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_setRigidBodyLinearDamping( - mut env: JNIEnv, - _: JClass, - world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - linear_damping: jdouble, - ) { - let world = convert_ptr!(world_ptr => World); - let mut physics = convert_ptr!(mut physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return; - }; - - if let Err(e) = super::shared::set_rigidbody_linear_damping(&mut physics, world, rb_context, linear_damping as f64) { - eprintln!("Failed to set RigidBody linear damping: {}", e); - let _ = env.throw_new("java/lang/IllegalArgumentException", format!("Failed to set RigidBody linear damping: {}", e)); - return; - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "getRigidBodyLinearDamping"), + c +)] +fn get_rigidbody_linear_damping( + #[dropbear_macro::define(WorldPtr)] + _world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + rigidbody: &RigidBodyContext, +) -> DropbearNativeResult<f64> { + shared::get_rigidbody_linear_damping(physics, rigidbody) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_getRigidBodyAngularDamping( - mut env: JNIEnv, - _: JClass, - _world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - ) -> jdouble { - let physics = convert_ptr!(physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return -1 as jdouble; - }; - - match super::shared::get_rigidbody_angular_damping(physics, rb_context) { - Ok(v) => v as jdouble, - Err(e) => { - eprintln!("Failed to get RigidBody angular damping: {}", e); - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to get RigidBody angular damping: {}", e)); - -1 as jdouble - } - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "setRigidBodyLinearDamping"), + c +)] +fn set_rigidbody_linear_damping( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + rigidbody: &RigidBodyContext, + linear_damping: f64, +) -> DropbearNativeResult<()> { + shared::set_rigidbody_linear_damping(physics, world, rigidbody, linear_damping) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_setRigidBodyAngularDamping( - mut env: JNIEnv, - _: JClass, - world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - angular_damping: jdouble, - ) { - let world = convert_ptr!(world_ptr => World); - let mut physics = convert_ptr!(mut physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return; - }; - - if let Err(e) = super::shared::set_rigidbody_angular_damping(&mut physics, world, rb_context, angular_damping as f64) { - eprintln!("Failed to set RigidBody angular damping: {}", e); - let _ = env.throw_new("java/lang/IllegalArgumentException", format!("Failed to set RigidBody angular damping: {}", e)); - return; - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "getRigidBodyAngularDamping"), + c +)] +fn get_rigidbody_angular_damping( + #[dropbear_macro::define(WorldPtr)] + _world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + rigidbody: &RigidBodyContext, +) -> DropbearNativeResult<f64> { + shared::get_rigidbody_angular_damping(physics, rigidbody) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_getRigidBodySleep( - mut env: JNIEnv, - _: JClass, - _world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - ) -> jboolean { - let physics = convert_ptr!(physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return 0 as jboolean; - }; - - match super::shared::get_rigidbody_sleep(physics, rb_context) { - Ok(v) => v as jboolean, - Err(e) => { - eprintln!("Failed to get RigidBody sleep state: {}", e); - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to get RigidBody sleep state: {}", e)); - 0 as jboolean - } - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "setRigidBodyAngularDamping"), + c +)] +fn set_rigidbody_angular_damping( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + rigidbody: &RigidBodyContext, + angular_damping: f64, +) -> DropbearNativeResult<()> { + shared::set_rigidbody_angular_damping(physics, world, rigidbody, angular_damping) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_setRigidBodySleep( - mut env: JNIEnv, - _: JClass, - world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - sleep: jboolean, - ) { - let world = convert_ptr!(world_ptr => World); - let mut physics = convert_ptr!(mut physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return; - }; - - if let Err(e) = super::shared::set_rigidbody_sleep(&mut physics, world, rb_context, sleep != 0) { - eprintln!("Failed to set RigidBody sleep state: {}", e); - let _ = env.throw_new("java/lang/IllegalArgumentException", format!("Failed to set RigidBody sleep state: {}", e)); - return; - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "getRigidBodySleep"), + c +)] +fn get_rigidbody_sleep( + #[dropbear_macro::define(WorldPtr)] + _world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + rigidbody: &RigidBodyContext, +) -> DropbearNativeResult<bool> { + shared::get_rigidbody_sleep(physics, rigidbody) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_getRigidBodyCcdEnabled( - mut env: JNIEnv, - _: JClass, - _world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - ) -> jboolean { - let physics = convert_ptr!(physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return 0 as jboolean; - }; - - match super::shared::get_rigidbody_ccd(physics, rb_context) { - Ok(v) => v as jboolean, - Err(e) => { - eprintln!("Failed to get RigidBody CCD state: {}", e); - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to get RigidBody CCD state: {}", e)); - 0 as jboolean - } - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "setRigidBodySleep"), + c +)] +fn set_rigidbody_sleep( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + rigidbody: &RigidBodyContext, + sleep: bool, +) -> DropbearNativeResult<()> { + shared::set_rigidbody_sleep(physics, world, rigidbody, sleep) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_setRigidBodyCcdEnabled( - mut env: JNIEnv, - _: JClass, - world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - ccd_enabled: jboolean, - ) { - let world = convert_ptr!(world_ptr => World); - let mut physics = convert_ptr!(mut physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return; - }; - - if let Err(e) = super::shared::set_rigidbody_ccd(&mut physics, world, rb_context, ccd_enabled != 0) { - eprintln!("Failed to set RigidBody CCD state: {}", e); - let _ = env.throw_new("java/lang/IllegalArgumentException", format!("Failed to set RigidBody CCD state: {}", e)); - return; - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "getRigidBodyCcdEnabled"), + c +)] +fn get_rigidbody_ccd_enabled( + #[dropbear_macro::define(WorldPtr)] + _world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + rigidbody: &RigidBodyContext, +) -> DropbearNativeResult<bool> { + shared::get_rigidbody_ccd(physics, rigidbody) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_getRigidBodyLinearVelocity( - mut env: JNIEnv, - _: JClass, - _world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - ) -> jobject { - let physics = convert_ptr!(physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return std::ptr::null_mut(); - }; - - match super::shared::get_rigidbody_linvel(physics, rb_context) { - Ok(v) => { - match v.to_jobject(&mut env) { - Ok(val) => val.into_raw(), - Err(e) => { - eprintln!("Failed to create Vector3d jobject: {}", e); - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to create Vector3d jobject: {}", e)); - std::ptr::null_mut() - } - } - } - Err(e) => { - eprintln!("Failed to get RigidBody linear velocity: {}", e); - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to get RigidBody linear velocity: {}", e)); - std::ptr::null_mut() - } - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "setRigidBodyCcdEnabled"), + c +)] +fn set_rigidbody_ccd_enabled( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + rigidbody: &RigidBodyContext, + ccd_enabled: bool, +) -> DropbearNativeResult<()> { + shared::set_rigidbody_ccd(physics, world, rigidbody, ccd_enabled) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_setRigidBodyLinearVelocity( - mut env: JNIEnv, - _: JClass, - world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - linear_velocity: JObject, - ) { - let world = convert_ptr!(world_ptr => World); - let mut physics = convert_ptr!(mut physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return; - }; - - let Ok(velocity) = NVector3::from_jobject(&mut env, &linear_velocity) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/math/Vector3d to rust Vector3"); - return; - }; - - if let Err(e) = super::shared::set_rigidbody_linvel(&mut physics, world, rb_context, velocity) { - eprintln!("Failed to set RigidBody linear velocity: {}", e); - let _ = env.throw_new("java/lang/IllegalArgumentException", format!("Failed to set RigidBody linear velocity: {}", e)); - return; - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "getRigidBodyLinearVelocity"), + c +)] +fn get_rigidbody_linear_velocity( + #[dropbear_macro::define(WorldPtr)] + _world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + rigidbody: &RigidBodyContext, +) -> DropbearNativeResult<NVector3> { + shared::get_rigidbody_linvel(physics, rigidbody) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_getRigidBodyAngularVelocity( - mut env: JNIEnv, - _: JClass, - _world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - ) -> jobject { - let physics = convert_ptr!(physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return std::ptr::null_mut(); - }; - - match super::shared::get_rigidbody_angvel(physics, rb_context) { - Ok(v) => { - match v.to_jobject(&mut env) { - Ok(val) => val.into_raw(), - Err(e) => { - eprintln!("Failed to create Vector3d jobject: {}", e); - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to create Vector3d jobject: {}", e)); - std::ptr::null_mut() - } - } - } - Err(e) => { - eprintln!("Failed to get RigidBody angular velocity: {}", e); - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to get RigidBody angular velocity: {}", e)); - std::ptr::null_mut() - } - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "setRigidBodyLinearVelocity"), + c +)] +fn set_rigidbody_linear_velocity( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + rigidbody: &RigidBodyContext, + linear_velocity: &NVector3, +) -> DropbearNativeResult<()> { + shared::set_rigidbody_linvel(physics, world, rigidbody, *linear_velocity) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_setRigidBodyAngularVelocity( - mut env: JNIEnv, - _: JClass, - world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - angular_velocity: JObject, - ) { - let world = convert_ptr!(world_ptr => World); - let mut physics = convert_ptr!(mut physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return; - }; - - let Ok(velocity) = NVector3::from_jobject(&mut env, &angular_velocity) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/math/Vector3d to rust Vector3"); - return; - }; - - if let Err(e) = super::shared::set_rigidbody_angvel(&mut physics, world, rb_context, velocity) { - eprintln!("Failed to set RigidBody angular velocity: {}", e); - let _ = env.throw_new("java/lang/IllegalArgumentException", format!("Failed to set RigidBody angular velocity: {}", e)); - return; - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "getRigidBodyAngularVelocity"), + c +)] +fn get_rigidbody_angular_velocity( + #[dropbear_macro::define(WorldPtr)] + _world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + rigidbody: &RigidBodyContext, +) -> DropbearNativeResult<NVector3> { + shared::get_rigidbody_angvel(physics, rigidbody) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_getRigidBodyLockTranslation( - mut env: JNIEnv, - _: JClass, - _world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - ) -> jobject { - let physics = convert_ptr!(physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return std::ptr::null_mut(); - }; - - match super::shared::get_rigidbody_lock_translation(physics, rb_context) { - Ok(v) => { - match v.to_jobject(&mut env) { - Ok(val) => val.into_raw(), - Err(e) => { - eprintln!("Failed to create AxisLock jobject: {}", e); - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to create AxisLock jobject: {}", e)); - std::ptr::null_mut() - } - } - } - Err(e) => { - eprintln!("Failed to get RigidBody translation lock: {}", e); - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to get RigidBody translation lock: {}", e)); - std::ptr::null_mut() - } - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "setRigidBodyAngularVelocity"), + c +)] +fn set_rigidbody_angular_velocity( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + rigidbody: &RigidBodyContext, + angular_velocity: &NVector3, +) -> DropbearNativeResult<()> { + shared::set_rigidbody_angvel(physics, world, rigidbody, *angular_velocity) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_setRigidBodyLockTranslation( - mut env: JNIEnv, - _: JClass, - world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - lock: JObject, - ) { - let world = convert_ptr!(world_ptr => World); - let mut physics = convert_ptr!(mut physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return; - }; - - let Ok(axis_lock) = AxisLock::from_jobject(&mut env, &lock) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/AxisLock to rust AxisLock"); - return; - }; - - if let Err(e) = super::shared::set_rigidbody_lock_translation(&mut physics, world, rb_context, axis_lock) { - eprintln!("Failed to set RigidBody translation lock: {}", e); - let _ = env.throw_new("java/lang/IllegalArgumentException", format!("Failed to set RigidBody translation lock: {}", e)); - return; - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "getRigidBodyLockTranslation"), + c +)] +fn get_rigidbody_lock_translation( + #[dropbear_macro::define(WorldPtr)] + _world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + rigidbody: &RigidBodyContext, +) -> DropbearNativeResult<AxisLock> { + shared::get_rigidbody_lock_translation(physics, rigidbody) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_getRigidBodyLockRotation( - mut env: JNIEnv, - _: JClass, - _world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - ) -> jobject { - let physics = convert_ptr!(physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return std::ptr::null_mut(); - }; - - match super::shared::get_rigidbody_lock_rotation(physics, rb_context) { - Ok(v) => { - match v.to_jobject(&mut env) { - Ok(val) => val.into_raw(), - Err(e) => { - eprintln!("Failed to create AxisLock jobject: {}", e); - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to create AxisLock jobject: {}", e)); - std::ptr::null_mut() - } - } - } - Err(e) => { - eprintln!("Failed to get RigidBody rotation lock: {}", e); - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to get RigidBody rotation lock: {}", e)); - std::ptr::null_mut() - } - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "setRigidBodyLockTranslation"), + c +)] +fn set_rigidbody_lock_translation( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + rigidbody: &RigidBodyContext, + lock_translation: &AxisLock, +) -> DropbearNativeResult<()> { + shared::set_rigidbody_lock_translation(physics, world, rigidbody, *lock_translation) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_setRigidBodyLockRotation( - mut env: JNIEnv, - _: JClass, - world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - lock: JObject, - ) { - let world = convert_ptr!(world_ptr => World); - let mut physics = convert_ptr!(mut physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return; - }; - - let Ok(axis_lock) = AxisLock::from_jobject(&mut env, &lock) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/AxisLock to rust AxisLock"); - return; - }; - - if let Err(e) = super::shared::set_rigidbody_lock_rotation(&mut physics, world, rb_context, axis_lock) { - eprintln!("Failed to set RigidBody rotation lock: {}", e); - let _ = env.throw_new("java/lang/IllegalArgumentException", format!("Failed to set RigidBody rotation lock: {}", e)); - return; - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "getRigidBodyLockRotation"), + c +)] +fn get_rigidbody_lock_rotation( + #[dropbear_macro::define(WorldPtr)] + _world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + rigidbody: &RigidBodyContext, +) -> DropbearNativeResult<AxisLock> { + shared::get_rigidbody_lock_rotation(physics, rigidbody) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_getRigidBodyChildren( - mut env: JNIEnv, - _: JClass, - _world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - ) -> jobjectArray { - let physics = convert_ptr!(physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return std::ptr::null_mut(); - }; - - match super::shared::get_rigidbody_children(physics, rb_context) { - Ok(children) => { - let mut handles: Vec<JObject> = Vec::new(); - for c in children { - match IndexNative::from(c.0).to_jobject(&mut env) { - Ok(val) => { handles.push(val); } - Err(_) => { continue; } - } - } - - let array = match env.new_object_array(handles.len() as i32, "com/dropbear/physics/Collider", JObject::null()) { - Ok(array) => array, - Err(e) => { - eprintln!("Failed to create jlong array: {}", e); - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to create jlong array: {}", e)); - return std::ptr::null_mut(); - } - }; - - for (i, h) in handles.iter().enumerate() { - if let Err(e) = env.set_object_array_element(&array, i as jsize, h) { - eprintln!("Failed to set jlong array region: {}", e); - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to set jobject array region at index {}: {}", i, e)); - return std::ptr::null_mut(); - } - } - - array.into_raw() - } - Err(e) => { - eprintln!("Failed to get RigidBody children: {}", e); - let _ = env.throw_new("java/lang/RuntimeException", format!("Failed to get RigidBody children: {}", e)); - std::ptr::null_mut() - } - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "setRigidBodyLockRotation"), + c +)] +fn set_rigidbody_lock_rotation( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + rigidbody: &RigidBodyContext, + lock_rotation: &AxisLock, +) -> DropbearNativeResult<()> { + shared::set_rigidbody_lock_rotation(physics, world, rigidbody, *lock_rotation) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_applyImpulse( - mut env: JNIEnv, - _: JClass, - world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - x: jdouble, - y: jdouble, - z: jdouble, - ) { - let world = convert_ptr!(world_ptr => World); - let mut physics = convert_ptr!(mut physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return; - }; - - let impulse = NVector3::new(x as f64, y as f64, z as f64); - if let Err(e) = super::shared::apply_impulse(&mut physics, world, rb_context, impulse) { - eprintln!("Failed to apply impulse: {}", e); - let _ = env.throw_new("java/lang/IllegalArgumentException", format!("Failed to apply impulse: {}", e)); - return; - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "getRigidBodyChildren"), + c +)] +fn get_rigidbody_children( + #[dropbear_macro::define(WorldPtr)] + _world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &PhysicsState, + rigidbody: &RigidBodyContext, +) -> DropbearNativeResult<Vec<NCollider>> { + let children = shared::get_rigidbody_children(physics, rigidbody)?; + let colliders = children + .into_iter() + .map(|handle| { + let (idx, generation) = handle.into_raw_parts(); + NCollider { + index: IndexNative { index: idx, generation }, + entity_id: rigidbody.entity_id, + id: idx, + } + }) + .collect(); + + Ok(colliders) +} - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_physics_RigidBodyNative_applyTorqueImpulse( - mut env: JNIEnv, - _: JClass, - world_ptr: jlong, - physics_ptr: jlong, - rigidbody: JObject, - x: jdouble, - y: jdouble, - z: jdouble, - ) { - let world = convert_ptr!(world_ptr => World); - let mut physics = convert_ptr!(mut physics_ptr => PhysicsState); - let Ok(rb_context) = RigidBodyContext::from_jobject(&mut env, &rigidbody) else { - let _ = env.throw_new("java/lang/RuntimeException", - "Unable to convert com/dropbear/physics/RigidBody to rust eucalyptus_core::physics::RigidBodyContext"); - return; - }; - - let torque = NVector3::new(x as f64, y as f64, z as f64); - if let Err(e) = super::shared::apply_torque_impulse(&mut physics, world, rb_context, torque) { - eprintln!("Failed to apply torque impulse: {}", e); - let _ = env.throw_new("java/lang/IllegalArgumentException", format!("Failed to apply torque impulse: {}", e)); - return; - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "applyImpulse"), + c +)] +fn apply_impulse( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + rigidbody: &RigidBodyContext, + x: f64, + y: f64, + z: f64, +) -> DropbearNativeResult<()> { + let impulse = NVector3::new(x, y, z); + shared::apply_impulse(physics, world, rigidbody, impulse) } -#[dropbear_macro::impl_c_api] -pub mod native { - +#[dropbear_macro::export( + kotlin(class = "com.dropbear.physics.RigidBodyNative", func = "applyTorqueImpulse"), + c +)] +fn apply_torque_impulse( + #[dropbear_macro::define(WorldPtr)] + world: &hecs::World, + #[dropbear_macro::define(PhysicsStatePtr)] + physics: &mut PhysicsState, + rigidbody: &RigidBodyContext, + x: f64, + y: f64, + z: f64, +) -> DropbearNativeResult<()> { + let torque = NVector3::new(x, y, z); + shared::apply_torque_impulse(physics, world, rigidbody, torque) } @@ -1,17 +1,15 @@ use std::fmt; use std::fmt::{Display, Formatter}; -use ::jni::JNIEnv; -use ::jni::objects::{JClass, JValue}; -use ::jni::sys::{jint, jobject}; use serde::{Deserialize, Serialize}; use dropbear_macro::SerializableComponent; use dropbear_traits::SerializableComponent; use egui::Ui; -use hecs::World; -use crate::physics::PhysicsState; -use crate::ptr::{PhysicsStatePtr, WorldPtr}; +use hecs::{Entity, World}; +use crate::ptr::WorldPtr; +use crate::scripting::native::DropbearNativeError; use crate::scripting::result::DropbearNativeResult; use crate::states::Property; +use crate::types::NVector3; /// Properties for an entity, typically queries with `entity.getProperty<Float>` and `entity.setProperty(21)` #[derive(Debug, Serialize, Deserialize, PartialEq, Clone, SerializableComponent)] @@ -159,671 +157,303 @@ impl Display for Value { } pub mod shared { - use std::ffi::CStr; - use std::os::raw::c_char; use hecs::World; use crate::properties::CustomProperties; - use crate::scripting::native::DropbearNativeError; - use crate::scripting::result::DropbearNativeResult; pub fn custom_properties_exists_for_entity(world: &World, entity: hecs::Entity) -> bool { world.get::<&CustomProperties>(entity).is_ok() } - - pub(crate) unsafe fn read_key(ptr: *const c_char) -> DropbearNativeResult<String> { - if ptr.is_null() { - return DropbearNativeResult::Err(DropbearNativeError::NullPointer); - } - match unsafe { CStr::from_ptr(ptr) }.to_str() { - Ok(s) => DropbearNativeResult::Ok(s.to_string()), - Err(_) => DropbearNativeResult::Err(DropbearNativeError::InvalidUTF8), - } - } } -// input: -// #[dropbear_macro::export( -// kotlin( -// class = "com.dropbear.components.CustomPropertiesNative", -// func = "getIntProperty", -// ), -// c -// )] -fn get_int_property( - #[dropbear_macro::define(crate::ptr::WorldPtr)] +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CustomPropertiesNative", func = "customPropertiesExistsForEntity"), + c +)] +fn custom_properties_exists_for_entity( + #[dropbear_macro::define(WorldPtr)] world: &World, - // #[dropbear_macro::define(crate::ptr::PhysicsStatePtr)] - // physics: &PhysicsState, - #[dropbear_macro::entity] // this proc macro defines this argument to be an entity. - entity0: hecs::Entity, - // multiple entities can also be defined - // #[dropbear_macro::entity] - // entity1: hecs::Entity, - // key: &str, // this is not valid: &str is not supported, only rust String. - key: String, // allowed -) -> DropbearNativeResult<Option<i32>> { // a nullable type is defined by an Option<T>, primitive and non-primitive included - if let Ok(props) = world.get::<&CustomProperties>(entity0) { - if let Some(Value::Int(v)) = props.get_property(key.as_str()) { - Ok(Some(*v as i32)) - } else { Ok(None) } - } else { Ok(None) } + #[dropbear_macro::entity] + entity: Entity, +) -> DropbearNativeResult<bool> { + Ok(shared::custom_properties_exists_for_entity(world, entity)) } -pub mod jni { - #![allow(non_snake_case)] - use hecs::World; - use jni::JNIEnv; - use jni::objects::{JClass, JObject, JString, JValue}; - use jni::sys::{jboolean, jdouble, jfloat, jint, jlong, jobject, jstring}; - - use crate::properties::{CustomProperties, Value}; - use crate::scripting::jni::utils::{FromJObject, ToJObject}; - use crate::types::NVector3; - - /// Returns a primitive that is boxed (long => java.lang.Long) - /// - /// ``` - /// return_boxed!(&mut env, Some(JValue::Int(21 as jint)), "(I)Ljava/lang/Integer;", "java/lang/Integer") - /// ``` - #[macro_export] - macro_rules! return_boxed { - ($env:expr, $val:expr, $sig:expr, $wrapper:expr) => { - match $val { - Some(v) => { - let result = |env: &mut jni::JNIEnv| -> jni::errors::Result<jni::sys::jobject> { - let cls = env.find_class($wrapper)?; - - let param: jni::objects::JValue = v.into(); - let ret = env.call_static_method(cls, "valueOf", $sig, &[param])?; - - Ok(ret.l()?.into_raw()) - }($env); - - match result { - Ok(ptr) => ptr, - Err(e) => { - eprintln!("return_boxed failed for {}: {:?}", $wrapper, e); - - let _ = $env.throw_new("java/lang/RuntimeException", format!("Boxing failed: {:?}", e)); - - std::ptr::null_mut() - } - } - } - None => std::ptr::null_mut(), - } - }; - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CustomPropertiesNative_customPropertiesExistsForEntity( - _env: JNIEnv, - _class: JClass, - world_handle: jlong, - entity_id: jlong, - ) -> jboolean { - let world = crate::convert_ptr!(world_handle => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - - if super::shared::custom_properties_exists_for_entity(&world, entity) { - 1 - } else { - 0 - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CustomPropertiesNative_getStringProperty( - mut env: JNIEnv, - _class: JClass, - world_handle: jlong, - entity_id: jlong, - key: JString, - ) -> jstring { - let world = crate::convert_ptr!(world_handle => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - let key_str = crate::convert_jstring!(env, key); - - if let Ok(props) = world.get::<&CustomProperties>(entity) { - if let Some(Value::String(s)) = props.get_property(&key_str) { - return env.new_string(s).map(|s| s.into_raw()).unwrap_or(std::ptr::null_mut()); - } - } - std::ptr::null_mut() - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CustomPropertiesNative_getIntProperty( - mut env: JNIEnv, - _class: JClass, - world_handle: jlong, - entity_id: jlong, - key: JString, - ) -> jobject { - let world = crate::convert_ptr!(world_handle => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - let key_str = crate::convert_jstring!(env, key); - - let val = if let Ok(props) = world.get::<&CustomProperties>(entity) { - if let Some(Value::Int(v)) = props.get_property(&key_str) { - Some(JValue::Int(*v as jint)) - } else { None } - } else { None }; - - return_boxed!(&mut env, val, "(I)Ljava/lang/Integer;", "java/lang/Integer") - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CustomPropertiesNative_getLongProperty( - mut env: JNIEnv, - _class: JClass, - world_handle: jlong, - entity_id: jlong, - key: JString, - ) -> jobject { - let world = crate::convert_ptr!(world_handle => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - let key_str = crate::convert_jstring!(env, key); - - let val = if let Ok(props) = world.get::<&CustomProperties>(entity) { - if let Some(Value::Int(v)) = props.get_property(&key_str) { - Some(JValue::Long(*v)) - } else { None } - } else { None }; - - return_boxed!(&mut env, val, "(J)Ljava/lang/Long;", "java/lang/Long") - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CustomPropertiesNative_getDoubleProperty( - mut env: JNIEnv, - _class: JClass, - world_handle: jlong, - entity_id: jlong, - key: JString, - ) -> jobject { - let world = crate::convert_ptr!(world_handle => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - let key_str = crate::convert_jstring!(env, key); - - let val = if let Ok(props) = world.get::<&CustomProperties>(entity) { - if let Some(Value::Double(v)) = props.get_property(&key_str) { - Some(JValue::Double(*v)) - } else { None } - } else { None }; - - return_boxed!(&mut env, val, "(D)Ljava/lang/Double;", "java/lang/Double") - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CustomPropertiesNative_getFloatProperty( - mut env: JNIEnv, - _class: JClass, - world_handle: jlong, - entity_id: jlong, - key: JString, - ) -> jobject { - let world = crate::convert_ptr!(world_handle => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - let key_str = crate::convert_jstring!(env, key); - - let val = if let Ok(props) = world.get::<&CustomProperties>(entity) { - if let Some(Value::Double(v)) = props.get_property(&key_str) { - Some(JValue::Float(*v as jfloat)) - } else { None } - } else { None }; - - return_boxed!(&mut env, val, "(F)Ljava/lang/Float;", "java/lang/Float") - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CustomPropertiesNative_getBoolProperty( - mut env: JNIEnv, - _class: JClass, - world_handle: jlong, - entity_id: jlong, - key: JString, - ) -> jobject { - let world = crate::convert_ptr!(world_handle => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - let key_str = crate::convert_jstring!(env, key); - - let val = if let Ok(props) = world.get::<&CustomProperties>(entity) { - if let Some(Value::Bool(v)) = props.get_property(&key_str) { - Some(JValue::Bool(if *v { 1 } else { 0 })) - } else { None } - } else { None }; - - return_boxed!(&mut env, val, "(Z)Ljava/lang/Boolean;", "java/lang/Boolean") - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CustomPropertiesNative_getVec3Property( - mut env: JNIEnv, - _class: JClass, - world_handle: jlong, - entity_id: jlong, - key: JString, - ) -> jobject { - let world = crate::convert_ptr!(world_handle => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - let key_str = crate::convert_jstring!(env, key); - - if let Ok(props) = world.get::<&CustomProperties>(entity) { - if let Some(Value::Vec3(v)) = props.get_property(&key_str) { - return match NVector3::from(*v).to_jobject(&mut env) { - Ok(obj) => obj.into_raw(), - Err(_) => std::ptr::null_mut() - }; - } - } - std::ptr::null_mut() - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CustomPropertiesNative_setStringProperty( - mut env: JNIEnv, - _class: JClass, - world_handle: jlong, - entity_id: jlong, - key: JString, - value: JString, - ) { - let world = crate::convert_ptr!(world_handle => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - let key_str = crate::convert_jstring!(env, key); - let val_str = crate::convert_jstring!(env, value); - - if let Ok(mut props) = world.get::<&mut CustomProperties>(entity) { - props.set_property(key_str, Value::String(val_str)); - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CustomPropertiesNative_setIntProperty( - mut env: JNIEnv, - _class: JClass, - world_handle: jlong, - entity_id: jlong, - key: JString, - value: jint, - ) { - let world = crate::convert_ptr!(world_handle => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - let key_str = crate::convert_jstring!(env, key); - - if let Ok(mut props) = world.get::<&mut CustomProperties>(entity) { - props.set_property(key_str, Value::Int(value as i64)); - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CustomPropertiesNative_setLongProperty( - mut env: JNIEnv, - _class: JClass, - world_handle: jlong, - entity_id: jlong, - key: JString, - value: jlong, - ) { - let world = crate::convert_ptr!(world_handle => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - let key_str = crate::convert_jstring!(env, key); - - if let Ok(mut props) = world.get::<&mut CustomProperties>(entity) { - props.set_property(key_str, Value::Int(value)); - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CustomPropertiesNative_setFloatProperty( - mut env: JNIEnv, - _class: JClass, - world_handle: jlong, - entity_id: jlong, - key: JString, - value: jfloat, - ) { - let world = crate::convert_ptr!(world_handle => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - let key_str = crate::convert_jstring!(env, key); - - if let Ok(mut props) = world.get::<&mut CustomProperties>(entity) { - props.set_property(key_str, Value::Double(value as f64)); - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CustomPropertiesNative_setDoubleProperty( - mut env: JNIEnv, - _class: JClass, - world_handle: jlong, - entity_id: jlong, - key: JString, - value: jdouble, - ) { - let world = crate::convert_ptr!(world_handle => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - let key_str = crate::convert_jstring!(env, key); - - if let Ok(mut props) = world.get::<&mut CustomProperties>(entity) { - props.set_property(key_str, Value::Double(value)); - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CustomPropertiesNative_setBoolProperty( - mut env: JNIEnv, - _class: JClass, - world_handle: jlong, - entity_id: jlong, - key: JString, - value: jboolean, - ) { - let world = crate::convert_ptr!(world_handle => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - let key_str = crate::convert_jstring!(env, key); - - if let Ok(mut props) = world.get::<&mut CustomProperties>(entity) { - props.set_property(key_str, Value::Bool(value != 0)); - } - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_components_CustomPropertiesNative_setVec3Property( - mut env: JNIEnv, - _class: JClass, - world_handle: jlong, - entity_id: jlong, - key: JString, - value: JObject, - ) { - let world = crate::convert_ptr!(world_handle => World); - let entity = crate::convert_jlong_to_entity!(entity_id); - let key_str = crate::convert_jstring!(env, key); - - let vec_val = match NVector3::from_jobject(&mut env, &value) { - Ok(v) => v, - Err(_) => return, - }; - - if let Ok(mut props) = world.get::<&mut CustomProperties>(entity) { - props.set_property(key_str, Value::Vec3(vec_val.to_array())); - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CustomPropertiesNative", func = "getStringProperty"), + c +)] +fn get_string_property( + #[dropbear_macro::define(WorldPtr)] + world: &World, + #[dropbear_macro::entity] + entity: Entity, + key: String, +) -> DropbearNativeResult<Option<String>> { + let props = world + .get::<&CustomProperties>(entity) + .map_err(|_| DropbearNativeError::NoSuchComponent)?; + + Ok(props.get_property(&key).and_then(|value| match value { + Value::String(s) => Some(s.clone()), + _ => None, + })) } -#[dropbear_macro::impl_c_api] -pub mod native { - use hecs::{Entity, World}; - use std::ffi::CString; - use std::os::raw::c_char; - - use crate::convert_ptr; - use crate::properties::shared::read_key; - use crate::properties::{CustomProperties, Value}; - use crate::ptr::WorldPtr; - use crate::scripting::native::DropbearNativeError; - use crate::scripting::result::DropbearNativeResult; - use crate::types::NVector3; - - pub fn dropbear_custom_properties_exists_for_entity( - world_ptr: WorldPtr, - entity_id: u64, - ) -> DropbearNativeResult<bool> { - let world = convert_ptr!(world_ptr => World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - - DropbearNativeResult::Ok(super::shared::custom_properties_exists_for_entity(world, entity)) - } - - - pub fn dropbear_get_string_property( - world_ptr: WorldPtr, - entity_id: u64, - key: *const c_char - ) -> DropbearNativeResult<*mut c_char> { - let world = convert_ptr!(world_ptr => World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - let key_str = unsafe { read_key(key)? }; - - if let Ok(props) = world.get::<&CustomProperties>(entity) { - if let Some(Value::String(s)) = props.get_property(&key_str) { - return match CString::new(s.clone()) { - Ok(c) => DropbearNativeResult::Ok(c.into_raw()), - Err(_) => DropbearNativeResult::Err(DropbearNativeError::CStringError), - }; - } - } - DropbearNativeResult::Err(DropbearNativeError::InvalidArgument) - } - - pub fn dropbear_get_int_property( - world_ptr: WorldPtr, - entity_id: u64, - key: *const c_char - ) -> DropbearNativeResult<i32> { - let world = convert_ptr!(world_ptr => World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - let key_str = unsafe { read_key(key)? }; - - if let Ok(props) = world.get::<&CustomProperties>(entity) { - if let Some(Value::Int(v)) = props.get_property(&key_str) { - return DropbearNativeResult::Ok(*v as i32); - } - } - DropbearNativeResult::Err(DropbearNativeError::InvalidArgument) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CustomPropertiesNative", func = "getIntProperty"), + c +)] +fn get_int_property( + #[dropbear_macro::define(WorldPtr)] + world: &World, + #[dropbear_macro::entity] + entity: Entity, + key: String, +) -> DropbearNativeResult<Option<i32>> { + let props = world + .get::<&CustomProperties>(entity) + .map_err(|_| DropbearNativeError::NoSuchComponent)?; + + Ok(props.get_property(&key).and_then(|value| match value { + Value::Int(v) => Some(*v as i32), + _ => None, + })) +} - pub fn dropbear_get_long_property( - world_ptr: WorldPtr, - entity_id: u64, - key: *const c_char - ) -> DropbearNativeResult<i64> { - let world = convert_ptr!(world_ptr => World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - let key_str = unsafe { read_key(key)? }; - - if let Ok(props) = world.get::<&CustomProperties>(entity) { - if let Some(Value::Int(v)) = props.get_property(&key_str) { - return DropbearNativeResult::Ok(*v); - } - } - DropbearNativeResult::Err(DropbearNativeError::InvalidArgument) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CustomPropertiesNative", func = "getLongProperty"), + c +)] +fn get_long_property( + #[dropbear_macro::define(WorldPtr)] + world: &World, + #[dropbear_macro::entity] + entity: Entity, + key: String, +) -> DropbearNativeResult<Option<i64>> { + let props = world + .get::<&CustomProperties>(entity) + .map_err(|_| DropbearNativeError::NoSuchComponent)?; + + Ok(props.get_property(&key).and_then(|value| match value { + Value::Int(v) => Some(*v), + _ => None, + })) +} - pub fn dropbear_get_double_property( - world_ptr: WorldPtr, - entity_id: u64, - key: *const c_char - ) -> DropbearNativeResult<f64> { - let world = convert_ptr!(world_ptr => World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - let key_str = unsafe { read_key(key)? }; - - if let Ok(props) = world.get::<&CustomProperties>(entity) { - if let Some(Value::Double(v)) = props.get_property(&key_str) { - return DropbearNativeResult::Ok(*v); - } - } - DropbearNativeResult::Err(DropbearNativeError::InvalidArgument) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CustomPropertiesNative", func = "getDoubleProperty"), + c +)] +fn get_double_property( + #[dropbear_macro::define(WorldPtr)] + world: &World, + #[dropbear_macro::entity] + entity: Entity, + key: String, +) -> DropbearNativeResult<Option<f64>> { + let props = world + .get::<&CustomProperties>(entity) + .map_err(|_| DropbearNativeError::NoSuchComponent)?; + + Ok(props.get_property(&key).and_then(|value| match value { + Value::Double(v) => Some(*v), + _ => None, + })) +} - pub fn dropbear_get_float_property( - world_ptr: WorldPtr, - entity_id: u64, - key: *const c_char - ) -> DropbearNativeResult<f32> { - let world = convert_ptr!(world_ptr => World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - let key_str = unsafe { read_key(key)? }; - - if let Ok(props) = world.get::<&CustomProperties>(entity) { - if let Some(Value::Double(v)) = props.get_property(&key_str) { - return DropbearNativeResult::Ok(*v as f32); - } - } - DropbearNativeResult::Err(DropbearNativeError::InvalidArgument) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CustomPropertiesNative", func = "getFloatProperty"), + c +)] +fn get_float_property( + #[dropbear_macro::define(WorldPtr)] + world: &World, + #[dropbear_macro::entity] + entity: Entity, + key: String, +) -> DropbearNativeResult<Option<f32>> { + let props = world + .get::<&CustomProperties>(entity) + .map_err(|_| DropbearNativeError::NoSuchComponent)?; + + Ok(props.get_property(&key).and_then(|value| match value { + Value::Double(v) => Some(*v as f32), + _ => None, + })) +} - pub fn dropbear_get_bool_property( - world_ptr: WorldPtr, - entity_id: u64, - key: *const c_char - ) -> DropbearNativeResult<bool> { - let world = convert_ptr!(world_ptr => World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - let key_str = unsafe { read_key(key)? }; - - if let Ok(props) = world.get::<&CustomProperties>(entity) { - if let Some(Value::Bool(v)) = props.get_property(&key_str) { - return DropbearNativeResult::Ok(*v); - } - } - DropbearNativeResult::Err(DropbearNativeError::InvalidArgument) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CustomPropertiesNative", func = "getBoolProperty"), + c +)] +fn get_bool_property( + #[dropbear_macro::define(WorldPtr)] + world: &World, + #[dropbear_macro::entity] + entity: Entity, + key: String, +) -> DropbearNativeResult<Option<bool>> { + let props = world + .get::<&CustomProperties>(entity) + .map_err(|_| DropbearNativeError::NoSuchComponent)?; + + Ok(props.get_property(&key).and_then(|value| match value { + Value::Bool(v) => Some(*v), + _ => None, + })) +} - pub fn dropbear_get_vec3_property( - world_ptr: WorldPtr, - entity_id: u64, - key: *const c_char - ) -> DropbearNativeResult<NVector3> { - let world = convert_ptr!(world_ptr => World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - let key_str = unsafe { read_key(key)? }; - - if let Ok(props) = world.get::<&CustomProperties>(entity) { - if let Some(Value::Vec3(v)) = props.get_property(&key_str) { - return DropbearNativeResult::Ok(NVector3::from(*v)); - } - } - DropbearNativeResult::Err(DropbearNativeError::InvalidArgument) - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CustomPropertiesNative", func = "getVec3Property"), + c +)] +fn get_vec3_property( + #[dropbear_macro::define(WorldPtr)] + world: &World, + #[dropbear_macro::entity] + entity: Entity, + key: String, +) -> DropbearNativeResult<Option<NVector3>> { + let props = world + .get::<&CustomProperties>(entity) + .map_err(|_| DropbearNativeError::NoSuchComponent)?; + + Ok(props.get_property(&key).and_then(|value| match value { + Value::Vec3(v) => Some(NVector3::from(*v)), + _ => None, + })) +} - pub fn dropbear_set_string_property( - world_ptr: WorldPtr, - entity_id: u64, - key: *const c_char, - value: *const c_char - ) -> DropbearNativeResult<()> { - let world = convert_ptr!(world_ptr => World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - let key_str = unsafe { read_key(key)? }; - let val_str = unsafe { read_key(value)? }; - - if let Ok(mut props) = world.get::<&mut CustomProperties>(entity) { - props.set_property(key_str, Value::String(val_str)); - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CustomPropertiesNative", func = "setStringProperty"), + c +)] +fn set_string_property( + #[dropbear_macro::define(WorldPtr)] + world: &mut World, + #[dropbear_macro::entity] + entity: Entity, + key: String, + value: String, +) -> DropbearNativeResult<()> { + let mut props = world + .get::<&mut CustomProperties>(entity) + .map_err(|_| DropbearNativeError::NoSuchComponent)?; + props.set_property(key, Value::String(value)); + Ok(()) +} - pub fn dropbear_set_int_property( - world_ptr: WorldPtr, - entity_id: u64, - key: *const c_char, - value: i32 - ) -> DropbearNativeResult<()> { - let world = convert_ptr!(world_ptr => World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - let key_str = unsafe { read_key(key)? }; - - if let Ok(mut props) = world.get::<&mut CustomProperties>(entity) { - props.set_property(key_str, Value::Int(value as i64)); - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CustomPropertiesNative", func = "setIntProperty"), + c +)] +fn set_int_property( + #[dropbear_macro::define(WorldPtr)] + world: &mut World, + #[dropbear_macro::entity] + entity: Entity, + key: String, + value: i32, +) -> DropbearNativeResult<()> { + let mut props = world + .get::<&mut CustomProperties>(entity) + .map_err(|_| DropbearNativeError::NoSuchComponent)?; + props.set_property(key, Value::Int(value as i64)); + Ok(()) +} - pub fn dropbear_set_long_property( - world_ptr: WorldPtr, - entity_id: u64, - key: *const c_char, - value: i64 - ) -> DropbearNativeResult<()> { - let world = convert_ptr!(world_ptr => World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - let key_str = unsafe { read_key(key)? }; - - if let Ok(mut props) = world.get::<&mut CustomProperties>(entity) { - props.set_property(key_str, Value::Int(value)); - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CustomPropertiesNative", func = "setLongProperty"), + c +)] +fn set_long_property( + #[dropbear_macro::define(WorldPtr)] + world: &mut World, + #[dropbear_macro::entity] + entity: Entity, + key: String, + value: i64, +) -> DropbearNativeResult<()> { + let mut props = world + .get::<&mut CustomProperties>(entity) + .map_err(|_| DropbearNativeError::NoSuchComponent)?; + props.set_property(key, Value::Int(value)); + Ok(()) +} - pub fn dropbear_set_double_property( - world_ptr: WorldPtr, - entity_id: u64, - key: *const c_char, - value: f64 - ) -> DropbearNativeResult<()> { - let world = convert_ptr!(world_ptr => World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - let key_str = unsafe { read_key(key)? }; - - if let Ok(mut props) = world.get::<&mut CustomProperties>(entity) { - props.set_property(key_str, Value::Double(value)); - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CustomPropertiesNative", func = "setDoubleProperty"), + c +)] +fn set_double_property( + #[dropbear_macro::define(WorldPtr)] + world: &mut World, + #[dropbear_macro::entity] + entity: Entity, + key: String, + value: f64, +) -> DropbearNativeResult<()> { + let mut props = world + .get::<&mut CustomProperties>(entity) + .map_err(|_| DropbearNativeError::NoSuchComponent)?; + props.set_property(key, Value::Double(value)); + Ok(()) +} - pub fn dropbear_set_float_property( - world_ptr: WorldPtr, - entity_id: u64, - key: *const c_char, - value: f32 - ) -> DropbearNativeResult<()> { - let world = convert_ptr!(world_ptr => World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - let key_str = unsafe { read_key(key)? }; - - if let Ok(mut props) = world.get::<&mut CustomProperties>(entity) { - props.set_property(key_str, Value::Double(value as f64)); - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CustomPropertiesNative", func = "setFloatProperty"), + c +)] +fn set_float_property( + #[dropbear_macro::define(WorldPtr)] + world: &mut World, + #[dropbear_macro::entity] + entity: Entity, + key: String, + value: f64, +) -> DropbearNativeResult<()> { + let mut props = world + .get::<&mut CustomProperties>(entity) + .map_err(|_| DropbearNativeError::NoSuchComponent)?; + props.set_property(key, Value::Double(value)); + Ok(()) +} - pub fn dropbear_set_bool_property( - world_ptr: WorldPtr, - entity_id: u64, - key: *const c_char, - value: bool - ) -> DropbearNativeResult<()> { - let world = convert_ptr!(world_ptr => World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - let key_str = unsafe { read_key(key)? }; - - if let Ok(mut props) = world.get::<&mut CustomProperties>(entity) { - props.set_property(key_str, Value::Bool(value)); - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CustomPropertiesNative", func = "setBoolProperty"), + c +)] +fn set_bool_property( + #[dropbear_macro::define(WorldPtr)] + world: &mut World, + #[dropbear_macro::entity] + entity: Entity, + key: String, + value: bool, +) -> DropbearNativeResult<()> { + let mut props = world + .get::<&mut CustomProperties>(entity) + .map_err(|_| DropbearNativeError::NoSuchComponent)?; + props.set_property(key, Value::Bool(value)); + Ok(()) +} - pub fn dropbear_set_vec3_property( - world_ptr: WorldPtr, - entity_id: u64, - key: *const c_char, - value: NVector3 - ) -> DropbearNativeResult<()> { - let world = convert_ptr!(world_ptr => World); - let entity = Entity::from_bits(entity_id).ok_or(DropbearNativeError::InvalidEntity)?; - let key_str = unsafe { read_key(key)? }; - - if let Ok(mut props) = world.get::<&mut CustomProperties>(entity) { - props.set_property(key_str, Value::Vec3(value.to_array())); - DropbearNativeResult::Ok(()) - } else { - DropbearNativeResult::Err(DropbearNativeError::NoSuchComponent) - } - } +#[dropbear_macro::export( + kotlin(class = "com.dropbear.components.CustomPropertiesNative", func = "setVec3Property"), + c +)] +fn set_vec3_property( + #[dropbear_macro::define(WorldPtr)] + world: &mut World, + #[dropbear_macro::entity] + entity: Entity, + key: String, + value: &NVector3, +) -> DropbearNativeResult<()> { + let mut props = world + .get::<&mut CustomProperties>(entity) + .map_err(|_| DropbearNativeError::NoSuchComponent)?; + props.set_property(key, Value::Vec3(value.to_array())); + Ok(()) } @@ -5,11 +5,11 @@ use crate::input::InputState; use crate::command::CommandBuffer; use crossbeam_channel::Sender; use dropbear_engine::asset::AssetRegistry; +use dropbear_engine::graphics::SharedGraphicsContext; use hecs::World; use parking_lot::{Mutex, RwLock}; use crate::physics::PhysicsState; use crate::scene::loading::SceneLoader; -use crate::ui::{UiContext}; /// A mutable pointer to a [`World`]. /// @@ -26,6 +26,12 @@ pub type InputStatePtr = *mut InputState; /// /// Defined in `dropbear_common.h` as `CommandBuffer` pub type CommandBufferPtr = *const Sender<CommandBuffer>; +pub type CommandBufferUnwrapped = Sender<CommandBuffer>; + +/// A non-mutable pointer to the shared graphics context. +/// +/// Defined in `dropbear_common.h` as `GraphicsContext`. +pub type GraphicsContextPtr = *const SharedGraphicsContext; /// A non-mutable pointer to the [`AssetRegistry`]. /// @@ -46,10 +52,4 @@ pub type SceneLoaderUnwrapped = Mutex<SceneLoader>; /// A mutable pointer to a [`PhysicsState`]. /// /// Defined in `dropbear_common.h` as `PhysicsEngine` -pub type PhysicsStatePtr = *mut PhysicsState; - -/// A mutable pointer to a [`UiContext`], used for queueing UI components -/// in the scripting module. -/// -/// Defined in `dropbear_common.h` as `UiBufferPtr`. -pub type UiBufferPtr = *const UiContext; +pub type PhysicsStatePtr = *mut PhysicsState; @@ -1,83 +0,0 @@ -//! Deprecated and dead. I don't know why it even exists :shrug: - -use jni::objects::{JClass, JObject, JString}; -use std::ptr; - -/// Trait used by the `jni` crate for easier error matching. -#[allow(dead_code)] -pub trait ResultToNull { - type Output; - - /// If the output is of a type [`jni::Error`](jni::errors::Error), - /// it will return a null pointer. Pretty useful for when you don't want to have - /// to deal with error matching. - /// - /// Specifically: converts result to the inner value on [`Ok`], or a null pointer on [`Err`] - fn or_null(self) -> Self::Output; -} - -impl ResultToNull for Result<JObject<'_>, jni::errors::Error> { - type Output = JObject<'static>; - - fn or_null(self) -> Self::Output { - match self { - Ok(val) => unsafe { JObject::from_raw(val.into_raw()) }, - Err(_) => JObject::null(), - } - } -} - -impl ResultToNull for anyhow::Result<JObject<'_>> { - type Output = JObject<'static>; - - fn or_null(self) -> Self::Output { - match self { - Ok(val) => unsafe { JObject::from_raw(val.into_raw()) }, - Err(_) => JObject::null(), - } - } -} - -impl ResultToNull for Result<JClass<'_>, jni::errors::Error> { - type Output = JClass<'static>; - - fn or_null(self) -> Self::Output { - match self { - Ok(val) => unsafe { JClass::from_raw(val.into_raw()) }, - Err(_) => unsafe { JClass::from_raw(ptr::null_mut()) }, - } - } -} - -impl ResultToNull for anyhow::Result<JClass<'_>> { - type Output = JClass<'static>; - - fn or_null(self) -> Self::Output { - match self { - Ok(val) => unsafe { JClass::from_raw(val.into_raw()) }, - Err(_) => unsafe { JClass::from_raw(ptr::null_mut()) }, - } - } -} - -impl ResultToNull for Result<JString<'_>, jni::errors::Error> { - type Output = JString<'static>; - - fn or_null(self) -> Self::Output { - match self { - Ok(val) => unsafe { JString::from_raw(val.into_raw()) }, - Err(_) => unsafe { JString::from_raw(ptr::null_mut()) }, - } - } -} - -impl ResultToNull for anyhow::Result<JString<'_>> { - type Output = JString<'static>; - - fn or_null(self) -> Self::Output { - match self { - Ok(val) => unsafe { JString::from_raw(val.into_raw()) }, - Err(_) => unsafe { JString::from_raw(ptr::null_mut()) }, - } - } -} @@ -13,8 +13,7 @@ use dropbear_engine::entity::{EntityTransform, MeshRenderer, Transform}; use dropbear_engine::texture::Texture; use dropbear_engine::graphics::SharedGraphicsContext; use dropbear_engine::lighting::{Light as EngineLight, LightComponent}; -use dropbear_engine::model::{LoadedModel, Material, Model, ModelId}; -use dropbear_engine::model::MODEL_CACHE; +use dropbear_engine::model::{Material, Model}; use dropbear_engine::utils::{ResourceReference, ResourceReferenceType}; use dropbear_traits::SerializableComponent; use dropbear_traits::registry::ComponentRegistry; @@ -12,7 +12,7 @@ pub static JVM_ARGS: OnceLock<String> = OnceLock::new(); pub static AWAIT_JDB: OnceLock<bool> = OnceLock::new(); use std::sync::OnceLock; -use crate::ptr::{AssetRegistryPtr, CommandBufferPtr, InputStatePtr, PhysicsStatePtr, SceneLoaderPtr, UiBufferPtr, WorldPtr}; +use crate::ptr::{AssetRegistryPtr, CommandBufferPtr, GraphicsContextPtr, InputStatePtr, PhysicsStatePtr, SceneLoaderPtr, WorldPtr}; use crate::scripting::jni::JavaContext; use crate::scripting::native::NativeLibrary; use crate::states::{Script}; @@ -24,12 +24,9 @@ use std::collections::{HashMap, HashSet}; use std::path::{Path, PathBuf}; use tokio::io::{AsyncBufReadExt, BufReader}; use tokio::process::Command; -use dropbear_engine::asset::PointerKind::Const; -use dropbear_engine::model::MODEL_CACHE; use magna_carta::Target; use crate::scene::loading::SCENE_LOADER; use crate::types::{CollisionEvent, ContactForceEvent}; -use crate::ui::UI_CONTEXT; /// The target of the script. This can be either a JVM or a native library. #[derive(Default, Clone, Debug)] @@ -222,31 +219,26 @@ impl ScriptManager { world: WorldPtr, input: InputStatePtr, graphics: CommandBufferPtr, + graphics_context: GraphicsContextPtr, physics_state: PhysicsStatePtr, ) -> anyhow::Result<()> { let assets = &raw const *ASSET_REGISTRY; let scene_loader = &raw const *SCENE_LOADER; - - let model_cache_ptr = &raw const *MODEL_CACHE; - ASSET_REGISTRY.add_pointer(Const("model_cache"), model_cache_ptr as usize); - - let ui_buf = UI_CONTEXT.with(|v| { - v.as_ptr() - }); let context = DropbearContext { world, input, - graphics, + command_buffer: graphics, + graphics_context, assets, scene_loader, physics_state, - ui_buf, }; if world.is_null() { log::error!("World pointer is null"); } if input.is_null() { log::error!("InputState pointer is null"); } if graphics.is_null() { log::error!("CommandBuffer pointer is null"); } + if graphics_context.is_null() { log::error!("SharedGraphicsContext pointer is null"); } if assets.is_null() { log::error!("AssetRegistry pointer is null"); } if scene_loader.is_null() { log::error!("SceneLoader pointer is null"); } if physics_state.is_null() { log::error!("PhysicsState pointer is null"); } @@ -971,9 +963,9 @@ pub async fn build_native( pub struct DropbearContext { pub world: WorldPtr, pub input: InputStatePtr, - pub graphics: CommandBufferPtr, + pub command_buffer: CommandBufferPtr, + pub graphics_context: GraphicsContextPtr, pub assets: AssetRegistryPtr, pub scene_loader: SceneLoaderPtr, pub physics_state: PhysicsStatePtr, - pub ui_buf: UiBufferPtr, } @@ -2,6 +2,7 @@ //! Deals with the Java Native Interface (JNI) with the help of the [`jni`] crate pub mod utils; +pub mod primitives; use crate::APP_INFO; use crate::logging::LOG_LEVEL; @@ -281,20 +282,20 @@ impl JavaContext { let result = (|| -> anyhow::Result<()> { let world_handle = context.world as jlong; let input_handle = context.input as jlong; - let graphics_handle = context.graphics as jlong; + let graphics_handle = context.command_buffer as jlong; + let graphics_context_handle = context.graphics_context as jlong; let asset_handle = context.assets as jlong; let scene_loader_handle = context.scene_loader as jlong; let physics_handle = context.physics_state as jlong; - let ui_handle = context.ui_buf as jlong; let args = [ JValue::Long(world_handle), JValue::Long(input_handle), JValue::Long(graphics_handle), + JValue::Long(graphics_context_handle), JValue::Long(asset_handle), JValue::Long(scene_loader_handle), JValue::Long(physics_handle), - JValue::Long(ui_handle), ]; let mut sig = String::from("("); @@ -0,0 +1,138 @@ +use jni::JNIEnv; +use jni::objects::{JObject, JValue}; +use jni::sys::{jdouble, jint, jlong}; +use crate::scripting::jni::utils::ToJObject; +use crate::scripting::native::DropbearNativeError; +use crate::scripting::result::DropbearNativeResult; + +impl ToJObject for Option<i32> { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + match self { + Some(value) => { + let class = env.find_class("java/lang/Integer") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; + + env.new_object(&class, "(I)V", &[JValue::Int(*value)]) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject) + }, + None => Ok(JObject::null()), + } + } +} + +impl ToJObject for Vec<i32> { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + self.as_slice().to_jobject(env) + } +} + +impl ToJObject for &[i32] { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + let array = env + .new_int_array(self.len() as i32) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; + let buf: Vec<jint> = self.iter().map(|v| *v as jint).collect(); + env.set_int_array_region(&array, 0, &buf) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; + Ok(JObject::from(array)) + } +} + +impl ToJObject for &[Vec<i32>] { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + let list = new_array_list(env)?; + for value in self.iter() { + let boxed = value.as_slice().to_jobject(env)?; + array_list_add(env, &list, &boxed)?; + } + Ok(list) + } +} + +impl ToJObject for Option<f32> { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + match self { + Some(value) => { + let class = env.find_class("java/lang/Float") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; + + env.new_object(&class, "(F)V", &[JValue::Float(*value)]) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject) + } + None => Ok(JObject::null()), + } + } +} + +impl ToJObject for Option<f64> { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + match self { + Some(value) => { + let class = env.find_class("java/lang/Double") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; + + env.new_object(&class, "(D)V", &[JValue::Double(*value)]) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject) + } + None => Ok(JObject::null()), + } + } +} + +impl ToJObject for Vec<f64> { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + self.as_slice().to_jobject(env) + } +} + +impl ToJObject for &[f64] { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + let array = env + .new_double_array(self.len() as i32) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; + let buf: Vec<jdouble> = self.iter().map(|v| *v as jdouble).collect(); + env.set_double_array_region(&array, 0, &buf) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject)?; + Ok(JObject::from(array)) + } +} + +impl ToJObject for &[Vec<f64>] { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + let list = new_array_list(env)?; + for value in self.iter() { + let array = value.as_slice().to_jobject(env)?; + array_list_add(env, &list, &array)?; + } + Ok(list) + } +} + +fn new_array_list<'a>(env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + let class = env.find_class("java/util/ArrayList") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; + env.new_object(&class, "()V", &[]) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject) +} + +fn array_list_add(env: &mut JNIEnv, list: &JObject, item: &JObject) -> DropbearNativeResult<()> { + env.call_method(list, "add", "(Ljava/lang/Object;)Z", &[JValue::Object(item)]) + .map_err(|_| DropbearNativeError::JNIMethodNotFound)?; + Ok(()) +} + +impl ToJObject for Vec<u64> { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + self.as_slice().to_jobject(env) + } +} + +impl ToJObject for &[u64] { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + let array = env + .new_long_array(self.len() as i32)?; + let buf: Vec<jlong> = self.iter().map(|v| *v as jlong).collect(); + env.set_long_array_region(&array, 0, &buf)?; + Ok(JObject::from(array)) + } +} @@ -12,13 +12,13 @@ use libloading::{Library, Symbol}; use std::ffi::CString; // use std::fmt::{Display, Formatter}; // Display derived by thiserror use std::path::Path; +use hecs::ComponentError; use crate::scripting::DropbearContext; use crate::types::{CollisionEvent as CollisionEventFFI, ContactForceEvent as ContactForceEventFFI}; use thiserror::Error; use jni::signature::TypeSignature; use jni::errors::JniError; - pub struct NativeLibrary { #[allow(dead_code)] /// The libloading library that is currently loaded @@ -526,6 +526,12 @@ pub enum DropbearNativeError { /// When a physics object is not found #[error("Physics object not found")] PhysicsObjectNotFound, + /// When parsing through the JObject, the enum ordinal provided was invalid. + #[error("Invalid enum ordinal")] + InvalidEnumOrdinal, + /// The entity did not have a requested component + #[error("Missing component")] + MissingComponent, /// The entity provided was invalid. #[error("Invalid entity")] InvalidEntity, @@ -598,6 +604,8 @@ impl DropbearNativeError { DropbearNativeError::AssetNotFound => -21, DropbearNativeError::InvalidHandle => -22, DropbearNativeError::PhysicsObjectNotFound => -23, + DropbearNativeError::InvalidEnumOrdinal => -24, + DropbearNativeError::MissingComponent => -25, DropbearNativeError::InvalidEntity => -100, DropbearNativeError::InvalidUTF8 => -108, DropbearNativeError::UnknownError => -1274, @@ -642,3 +650,12 @@ impl From<jni::errors::Error> for DropbearNativeError { } } } + +impl From<hecs::ComponentError> for DropbearNativeError { + fn from(e: hecs::ComponentError) -> Self { + match e { + ComponentError::NoSuchEntity => DropbearNativeError::NoSuchEntity, + ComponentError::MissingComponent(_) => DropbearNativeError::MissingComponent + } + } +} @@ -7,10 +7,10 @@ use crate::config::{ProjectConfig, ResourceConfig, SourceConfig}; use crate::scene::SceneConfig; use crate::traits::SerializableComponent; use dropbear_engine::camera::Camera; -use dropbear_engine::entity::{MaterialOverride, MeshRenderer, Transform}; +use dropbear_engine::entity::{MeshRenderer, Transform}; use dropbear_engine::lighting::LightComponent; -use dropbear_engine::texture::TextureWrapMode; -use dropbear_engine::utils::{ResourceReference}; +use dropbear_engine::asset::ASSET_REGISTRY; +use dropbear_engine::utils::{ResourceReference, ResourceReferenceType, EUCA_SCHEME}; use dropbear_macro::SerializableComponent; use once_cell::sync::Lazy; use parking_lot::RwLock; @@ -370,106 +370,49 @@ impl DerefMut for Label { } /// A [MeshRenderer] that is serialized into a file to be stored as a value for config. -#[derive(Default, Debug, Clone, Serialize, Deserialize)] +#[derive(Default, Debug, Clone, Serialize, Deserialize, SerializableComponent)] pub struct SerializedMeshRenderer { pub handle: ResourceReference, - pub material_override: Vec<MaterialOverride>, - - #[serde(default)] - pub material_customisation: Vec<SerializedMaterialcustomisation>, - - #[serde(default)] - #[serde(alias = "custom_import_scale")] - #[serde(alias = "editor_import_scale")] - #[serde(alias = "baked_import_scale")] pub import_scale: Option<f32>, -} - -#[derive(Default, Debug, Clone, Serialize, Deserialize)] -pub struct SerializedMaterialcustomisation { - #[serde(default)] - pub material_index: Option<usize>, - pub target_material: String, - pub tint: [f32; 4], - - #[serde(default)] - pub diffuse_texture: Option<ResourceReference>, - - #[serde(default)] - pub wrap_mode: TextureWrapMode, - - #[serde(default = "default_uv_tiling")] - pub uv_tiling: [f32; 2], -} - -fn default_uv_tiling() -> [f32; 2] { - [1.0, 1.0] -} - -#[typetag::serde] -impl SerializableComponent for SerializedMeshRenderer { - fn as_any(&self) -> &dyn std::any::Any { - self - } - - fn as_any_mut(&mut self) -> &mut dyn std::any::Any { - self - } - - fn type_name(&self) -> &'static str { - "SerializedMeshRenderer" - } - - fn clone_boxed(&self) -> Box<dyn SerializableComponent> { - Box::new(self.clone()) - } - - fn display_name(&self) -> String { - "MeshRenderer".to_string() - } + pub texture_override: Option<ResourceReference>, } impl SerializedMeshRenderer { /// Creates a new [SerializedMeshRenderer] from an existing [MeshRenderer] by cloning data. pub fn from_renderer(renderer: &MeshRenderer) -> Self { - fn is_probably_texture_uri(uri: &str) -> bool { - let uri = uri.to_ascii_lowercase(); - uri.ends_with(".png") - || uri.ends_with(".jpg") - || uri.ends_with(".jpeg") - || uri.ends_with(".tga") - || uri.ends_with(".bmp") - } + let handle = renderer.model(); + let handle_ref = if handle.is_null() { + ResourceReference::from_reference(ResourceReferenceType::Unassigned { id: handle.id }) + } else { + let registry = ASSET_REGISTRY.read(); + registry + .get_model(handle) + .map(|model| model.path.clone()) + .unwrap_or_else(|| { + ResourceReference::from_reference(ResourceReferenceType::Unassigned { id: handle.id }) + }) + }; - let handle = renderer.handle(); - let model = renderer.model(); - let material_customisation = model - .materials - .iter() - .enumerate() - .map(|(index, mat)| { - let diffuse_texture = mat - .texture_tag - .as_deref() - .filter(|tag| is_probably_texture_uri(tag)) - .and_then(|tag| ResourceReference::from_euca_uri(tag).ok()); - - SerializedMaterialcustomisation { - material_index: Some(index), - target_material: mat.name.clone(), - tint: mat.tint, - diffuse_texture, - wrap_mode: mat.wrap_mode, - uv_tiling: mat.uv_tiling, + let texture_override = renderer.texture_override().map(|handle| { + let registry = ASSET_REGISTRY.read(); + let label = registry.get_label_from_texture_handle(handle); + let reference = label.and_then(|value| { + if value.starts_with(EUCA_SCHEME) { + Some(ResourceReference::from_reference(ResourceReferenceType::File(value))) + } else { + None } + }); + + reference.unwrap_or_else(|| { + ResourceReference::from_reference(ResourceReferenceType::Unassigned { id: handle.id }) }) - .collect(); + }); Self { - handle: handle.path.clone(), - material_override: renderer.material_overrides.clone(), - material_customisation, + handle: handle_ref, import_scale: Some(renderer.import_scale()), + texture_override, } } } @@ -5,6 +5,7 @@ use jni::JNIEnv; use jni::objects::{JObject, JValue}; use jni::sys::jdouble; use rapier3d::data::Index; +use rapier3d::parry::query::{ShapeCastOptions, ShapeCastStatus}; use rapier3d::prelude::ColliderHandle; use dropbear_engine::entity::Transform; use crate::physics::PhysicsState; @@ -93,6 +94,18 @@ impl From<glam::DVec3> for NVector3 { } } +impl From<&glam::DVec3> for NVector3 { + fn from(v: &glam::DVec3) -> Self { + Self { x: v.x, y: v.y, z: v.z } + } +} + +impl From<&NVector3> for glam::DVec3 { + fn from(v: &NVector3) -> Self { + Self { x: v.x, y: v.y, z: v.z } + } +} + impl From<[f64; 3]> for NVector3 { fn from(value: [f64; 3]) -> Self { NVector3 { @@ -376,12 +389,67 @@ impl From<NVector4> for NQuaternion { } } +impl ToJObject for NQuaternion { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + let class = env.find_class("com/dropbear/math/Quaterniond") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; + + let args = [ + JValue::Double(self.x), + JValue::Double(self.y), + JValue::Double(self.z), + JValue::Double(self.w), + ]; + + env.new_object(&class, "(DDDD)V", &args) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject) + } +} + +impl FromJObject for NQuaternion { + fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> + where + Self: Sized + { + let class = env.find_class("com/dropbear/math/Quaterniond") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; + + if !env.is_instance_of(obj, &class) + .map_err(|_| DropbearNativeError::JNIUnwrapFailed)? + { + return Err(DropbearNativeError::InvalidArgument); + } + + let x = env.get_field(obj, "x", "D") + .map_err(|_| DropbearNativeError::JNIFailedToGetField)? + .d() + .map_err(|_| DropbearNativeError::JNIUnwrapFailed)?; + + let y = env.get_field(obj, "y", "D") + .map_err(|_| DropbearNativeError::JNIFailedToGetField)? + .d() + .map_err(|_| DropbearNativeError::JNIUnwrapFailed)?; + + let z = env.get_field(obj, "z", "D") + .map_err(|_| DropbearNativeError::JNIFailedToGetField)? + .d() + .map_err(|_| DropbearNativeError::JNIUnwrapFailed)?; + + let w = env.get_field(obj, "w", "D") + .map_err(|_| DropbearNativeError::JNIFailedToGetField)? + .d() + .map_err(|_| DropbearNativeError::JNIUnwrapFailed)?; + + Ok(NQuaternion { x, y, z, w }) + } +} + #[repr(C)] #[derive(Clone, Copy)] pub struct NTransform { - position: NVector3, - rotation: NQuaternion, - scale: NVector3, + pub position: NVector3, + pub rotation: NQuaternion, + pub scale: NVector3, } impl From<Transform> for NTransform { @@ -404,6 +472,30 @@ impl From<NTransform> for Transform { } } +impl ToJObject for NTransform { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + let class = env + .find_class("com/dropbear/math/Transform") + .map_err(|_| DropbearNativeError::JNIClassNotFound)?; + + let args = [ + JValue::Double(self.position.x), + JValue::Double(self.position.y), + JValue::Double(self.position.z), + JValue::Double(self.rotation.x), + JValue::Double(self.rotation.y), + JValue::Double(self.rotation.z), + JValue::Double(self.rotation.w), + JValue::Double(self.scale.x), + JValue::Double(self.scale.y), + JValue::Double(self.scale.z), + ]; + + env.new_object(&class, "(DDDDDDDDDD)V", &args) + .map_err(|_| DropbearNativeError::JNIFailedToCreateObject) + } +} + #[repr(C)] #[derive(Clone, Copy)] pub struct NCollider { @@ -521,25 +613,59 @@ impl From<IndexNative> for Index { } } -#[repr(C)] -#[derive(Clone, Copy)] -pub enum ColliderShapeType { - Box = 0, - Sphere = 1, - Capsule = 2, - Cylinder = 3, - Cone = 4, +impl ToJObject for IndexNative { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + let cls = env.find_class("com/dropbear/physics/Index") + .map_err(|e| { + eprintln!("[JNI Error] Could not find Index class: {:?}", e); + DropbearNativeError::GenericError + })?; + + let obj = env.new_object( + cls, + "(II)V", + &[ + JValue::Int(self.index as i32), + JValue::Int(self.generation as i32) + ] + ).map_err(|e| { + eprintln!("[JNI Error] Failed to create Index object: {:?}", e); + DropbearNativeError::GenericError + })?; + + Ok(obj) + } } -#[repr(C)] -#[derive(Clone, Copy)] -pub struct NColliderShape { - pub shape_type: ColliderShapeType, - pub radius: f32, - pub half_height: f32, - pub half_extents_x: f32, - pub half_extents_y: f32, - pub half_extents_z: f32, +impl ToJObject for Option<IndexNative> { + fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { + match self { + Some(value) => value.to_jobject(env), + None => Ok(JObject::null()), + } + } +} + +impl FromJObject for IndexNative { + fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> + where + Self: Sized + { + let idx_val = env.get_field(obj, "index", "I") + .map_err(|_| DropbearNativeError::JNIFailedToGetField)? + .i() + .map_err(|_| DropbearNativeError::JNIUnwrapFailed)?; + + let gen_val = env.get_field(obj, "generation", "I") + .map_err(|_| DropbearNativeError::JNIFailedToGetField)? + .i() + .map_err(|_| DropbearNativeError::JNIUnwrapFailed)?; + + Ok(IndexNative { + index: idx_val as u32, + generation: gen_val as u32, + }) + } } #[repr(C)] @@ -680,18 +806,50 @@ impl ToJObject for RayHit { } #[repr(C)] +#[dropbear_macro::repr_c_enum] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum NShapeCastStatus { + OutOfIterations, + Converged, + Failed, + PenetratingOrWithinTargetDist, +} + +impl Into<ShapeCastStatus> for NShapeCastStatus { + fn into(self) -> ShapeCastStatus { + match self { + NShapeCastStatus::OutOfIterations => ShapeCastStatus::OutOfIterations, + NShapeCastStatus::Converged => ShapeCastStatus::Converged, + NShapeCastStatus::Failed => ShapeCastStatus::Failed, + NShapeCastStatus::PenetratingOrWithinTargetDist => ShapeCastStatus::PenetratingOrWithinTargetDist, + } + } +} + +impl Into<NShapeCastStatus> for ShapeCastStatus { + fn into(self) -> NShapeCastStatus { + match self { + ShapeCastStatus::OutOfIterations => NShapeCastStatus::OutOfIterations, + ShapeCastStatus::Converged => NShapeCastStatus::Converged, + ShapeCastStatus::Failed => NShapeCastStatus::Failed, + ShapeCastStatus::PenetratingOrWithinTargetDist => NShapeCastStatus::PenetratingOrWithinTargetDist, + } + } +} + +#[repr(C)] #[derive(Clone, Copy)] -pub struct ShapeCastHitFFI { +pub struct NShapeCastHit { pub collider: NCollider, pub distance: f64, pub witness1: NVector3, pub witness2: NVector3, pub normal1: NVector3, pub normal2: NVector3, - pub status: rapier3d::parry::query::ShapeCastStatus, + pub status: NShapeCastStatus, } -impl ToJObject for ShapeCastHitFFI { +impl ToJObject for NShapeCastHit { fn to_jobject<'a>(&self, env: &mut JNIEnv<'a>) -> DropbearNativeResult<JObject<'a>> { use jni::sys::jdouble; @@ -1,192 +0,0 @@ -// mod button; -// mod utils; -// mod text; -// mod align; -// mod checkbox; - -use std::any::Any; -use std::cell::RefCell; -use std::collections::HashMap; -use std::fmt::Debug; -use ::jni::JNIEnv; -use ::jni::objects::JObject; -use parking_lot::Mutex; -use serde::{Deserialize, Serialize}; -// use yakui::{Alignment, MainAxisSize, Yakui}; -use dropbear_engine::utils::ResourceReference; -use dropbear_macro::SerializableComponent; -use dropbear_traits::SerializableComponent; -use crate::scripting::jni::utils::{FromJObject}; -use crate::scripting::result::DropbearNativeResult; -// use crate::ui::align::{AlignParser}; -// use crate::ui::button::ButtonParser; -// use crate::ui::checkbox::CheckboxParser; -// use crate::ui::text::TextParser; - -thread_local! { - pub static UI_CONTEXT: RefCell<UiContext> = RefCell::new(UiContext::new()); -} - -/// A component that can be attached to an entity that renders UI for the entire scene. -/// -/// This UI is used in tandem with a `.kts` (Kotlin Script file) with the dropbear-engine scripting -/// ui DSL. -#[derive(Debug, Serialize, Deserialize, Clone, SerializableComponent, Default)] -pub struct UIComponent { - /// Does not render the UI file. - pub disabled: bool, - /// The reference to the script file. - pub ui_file: ResourceReference, -} - -#[derive(Clone, Copy, Debug, Default)] -pub struct WidgetState { - pub clicked: bool, - pub hovering: bool, - pub checked: bool, -} - -pub trait WidgetParser: Send + Sync { - fn parse(&self, env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Option<UiInstructionType>>; - fn name(&self) -> String; -} - -pub struct UiContext { - // pub yakui_state: Mutex<Yakui>, - pub instruction_set: Mutex<Vec<UiInstructionType>>, - pub widget_states: Mutex<HashMap<i64, WidgetState>>, - pub parsers: Mutex<Vec<Box<dyn WidgetParser>>>, -} - -pub fn poll() { - UI_CONTEXT.with(|v| { - let ctx = v.borrow(); - // let mut instructions = ctx.instruction_set.lock(); - let mut widget_states = ctx.widget_states.lock(); - - widget_states.clear(); - - // let current_instructions = instructions.drain(..).collect::<Vec<UiInstructionType>>(); - - // let tree = build_tree(current_instructions); - - // yakui::widgets::Align::new(Alignment::TOP_LEFT).show(|| { - // yakui::widgets::List::column() - // .main_axis_size(MainAxisSize::Max) - // .show(|| { - // render_tree(tree, &mut widget_states); - // }); - // }); - }); -} - -#[derive(Debug)] -pub enum UiInstructionType { - Containered(ContaineredWidgetType), - Widget(Box<dyn NativeWidget>), -} - -#[derive(Debug)] -pub enum ContaineredWidgetType { - Start { - id: i64, - widget: Box<dyn ContaineredWidget>, - }, - End { - id: i64, - } -} - -pub trait NativeWidget: Send + Sync + Debug { - fn render(self: Box<Self>, state: &mut HashMap<i64, WidgetState>); - fn id(&self) -> i64; - fn as_any(&self) -> &dyn Any; -} - -pub trait ContaineredWidget: Send + Sync + Debug { - fn render(self: Box<Self>, children: Vec<UiNode>, state: &mut HashMap<i64, WidgetState>); - fn as_any(&self) -> &dyn Any; -} - -pub struct UiNode { - pub instruction: UiInstructionType, - pub children: Vec<UiNode>, -} - -impl UiContext { - pub fn new() -> Self { - let mut parsers: Vec<Box<dyn WidgetParser>> = Vec::new(); - - // parsers.push(Box::new(ButtonParser)); - // parsers.push(Box::new(TextParser)); - // parsers.push(Box::new(AlignParser)); - // parsers.push(Box::new(CheckboxParser)); - - // let yakui = Yakui::new(); - - Self { - // yakui_state: Mutex::new(yakui), - instruction_set: Default::default(), - widget_states: Default::default(), - parsers: Mutex::new(parsers), - } - } -} - -pub trait UiWidgetType: FromJObject { - type UIWidgetType; - - fn as_id(&self) -> u32; - fn from_id(id: u32) -> Self::UIWidgetType; -} - -pub mod jni { - #![allow(non_snake_case)] - - use jni::sys::{jlong}; - use jni::objects::{JClass, JObjectArray}; - use jni::JNIEnv; - use crate::convert_ptr; - use crate::ui::{UiContext}; - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_ui_UINative_renderUI( - mut env: JNIEnv, - _class: JClass, - ui_buf_ptr: jlong, - instructions: JObjectArray, - ) { - // println!("[Java_com_dropbear_ui_UINative_renderUI] received new renderUI request"); - let ui = convert_ptr!(ui_buf_ptr => UiContext); - let mut rust_instructions = Vec::new(); - - let count = env.get_array_length(&instructions).unwrap_or(0); - let parsers_guard = ui.parsers.lock(); - - for i in 0..count { - let obj = match env.get_object_array_element(&instructions, i) { - Ok(o) => o, - Err(_) => continue, - }; - if obj.is_null() { println!("[Java_com_dropbear_ui_UINative_renderUI] obj is null at index {}", i); continue; } - - for parser in parsers_guard.iter() { - match parser.parse(&mut env, &obj) { - Ok(Some(widget)) => { - // println!("Received widget: {:?}", widget); - rust_instructions.push(widget); - break; - }, - Ok(None) => continue, - Err(e) => { - eprintln!("[Java_com_dropbear_ui_UINative_renderUI] Error converting UI instruction: {:?}", e); - } - } - } - } - - let mut instruction_set = ui.instruction_set.lock(); - instruction_set.clear(); - instruction_set.extend(rust_instructions); - } -} @@ -1,81 +0,0 @@ -use std::any::Any; -use std::collections::HashMap; -use jni::JNIEnv; -use jni::objects::JObject; -use yakui::Alignment; -use crate::scripting::jni::utils::FromJObject; -use crate::scripting::result::DropbearNativeResult; -use crate::ui::{ContaineredWidget, ContaineredWidgetType, UiInstructionType, UiNode, WidgetParser, WidgetState}; - -pub(crate) struct AlignParser; - -#[derive(Debug, Clone)] -pub(crate) struct AlignWidget { - pub alignment: Alignment, -} - -impl WidgetParser for AlignParser { - fn parse(&self, env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Option<UiInstructionType>> { - let class = env.get_object_class(obj)?; - let name_str_obj = env.call_method(class, "getName", "()Ljava/lang/String;", &[])?.l()?; - let name_string: String = env.get_string(&name_str_obj.into())?.into(); - - if name_string.contains("AlignmentInstruction$StartAlignmentBlock") { - let align_obj = env.get_field(obj, "align", "Lcom/dropbear/ui/widgets/Align;")?.l()?; - let align = yakui::widgets::Align::from_jobject(env, &align_obj)?; - - let id_obj = env.get_field(obj, "id", "Lcom/dropbear/ui/WidgetId;")?.l()?; - let id = env.get_field(id_obj, "id", "J")?.j()?; - - return Ok(Some(UiInstructionType::Containered( - ContaineredWidgetType::Start { - id, - widget: Box::new(AlignWidget { - alignment: align.alignment, - }), - } - ))); - } - - if name_string.contains("AlignmentInstruction$EndAlignmentBlock") { - let id_obj = env.get_field(obj, "id", "Lcom/dropbear/ui/WidgetId;")?.l()?; - let id = env.get_field(id_obj, "id", "J")?.j()?; - - return Ok(Some(UiInstructionType::Containered( - ContaineredWidgetType::End { id } - ))); - } - - Ok(None) - } - - fn name(&self) -> String { - String::from("AlignParser") - } -} - -impl ContaineredWidget for AlignWidget { - fn render(self: Box<Self>, children: Vec<UiNode>, state: &mut HashMap<i64, WidgetState>) { - yakui::widgets::Align::new(self.alignment).show(|| { - super::render_tree(children, state); - }); - } - - fn as_any(&self) -> &dyn Any { - self - } -} - -impl FromJObject for yakui::widgets::Align { - fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> - where - Self: Sized - { - let align_obj = env.get_field(obj, "align", "Lcom/dropbear/ui/styling/Alignment;")?.l()?; - let alignment = Alignment::from_jobject(env, &align_obj)?; - - Ok(Self { - alignment, - }) - } -} @@ -1,134 +0,0 @@ -use std::any::Any; -use std::collections::HashMap; -use yakui::{Alignment, BorderRadius}; -use yakui::widgets::{Button, Pad, DynamicButtonStyle}; -use crate::scripting::jni::utils::FromJObject; -use crate::scripting::result::DropbearNativeResult; -use std::borrow::Cow; -use ::jni::JNIEnv; -use ::jni::objects::JObject; -use crate::ui::{NativeWidget, UiInstructionType, WidgetParser, WidgetState}; - -pub(crate) struct ButtonParser; - -#[derive(Debug)] -pub(crate) struct ButtonWidget { - pub id: i64, - pub button: yakui::widgets::Button, -} - -impl WidgetParser for ButtonParser { - fn parse(&self, env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Option<UiInstructionType>> { - let class = env.get_object_class(obj)?; - let name_str_obj = env.call_method(class, "getName", "()Ljava/lang/String;", &[])?.l()?; - let name_string: String = env.get_string(&name_str_obj.into())?.into(); - - if name_string.contains("ButtonInstruction$Button") { - let button_obj = env.get_field(obj, "button", "Lcom/dropbear/ui/widgets/Button;")?.l()?; - let button = yakui::widgets::Button::from_jobject(env, &button_obj)?; - - let id_obj = env.get_field(obj, "id", "Lcom/dropbear/ui/WidgetId;")?.l()?; - let id = env.get_field(id_obj, "id", "J")?.j()?; - - return Ok(Some(UiInstructionType::Widget(Box::new(ButtonWidget { - id, - button, - })))); - } - - Ok(None) - } - - fn name(&self) -> String { - String::from("ButtonParser") - } -} - -impl NativeWidget for ButtonWidget { - fn render(self: Box<Self>, states: &mut HashMap<i64, WidgetState>) { - let res = self.button.show(); - states.insert(self.id, WidgetState { - clicked: res.clicked, - hovering: res.hovering, - checked: false, // always be false because it is not a checkbox, obv - }); - } - - fn id(&self) -> i64 { - self.id - } - - fn as_any(&self) -> &dyn Any { - self - } -} - -impl FromJObject for Button { - fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { - let text_field = env.get_field(obj, "text", "Ljava/lang/String;")?; - let text_jstring = text_field.l()?.into(); - let text: String = env.get_string(&text_jstring)?.into(); - - let f = env.get_field(obj, "alignment", "Lcom/dropbear/ui/styling/Alignment;")?.l()?; - let alignment = Alignment::from_jobject(env, &f)?; - - let f = env.get_field(obj, "padding", "Lcom/dropbear/ui/styling/Padding;")?.l()?; - let padding = Pad::from_jobject(env, &f)?; - - let f = env.get_field(obj, "borderRadius", "Lcom/dropbear/ui/styling/BorderRadius;")?.l()?; - let border_radius = BorderRadius::from_jobject(env, &f)?; - - let f = env.get_field(obj, "style", "Lcom/dropbear/ui/styling/DynamicButtonStyle;")?.l()?; - let style = DynamicButtonStyle::from_jobject(env, &f)?; - - let f = env.get_field(obj, "hoverStyle", "Lcom/dropbear/ui/styling/DynamicButtonStyle;")?.l()?; - let hover_style = DynamicButtonStyle::from_jobject(env, &f)?; - - let f = env.get_field(obj, "downStyle", "Lcom/dropbear/ui/styling/DynamicButtonStyle;")?.l()?; - let down_style = DynamicButtonStyle::from_jobject(env, &f)?; - - Ok(Self { - text: Cow::Owned(text), - alignment, - padding, - border_radius, - style, - hover_style, - down_style, - }) - } -} - -pub mod jni { - #![allow(non_snake_case)] - - use jni::JNIEnv; - use jni::objects::JClass; - use jni::sys::{jboolean, jlong}; - use crate::convert_ptr; - use crate::ui::UiContext; - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_ui_widgets_ButtonNative_getClicked( - _env: JNIEnv, - _class: JClass, - ui_buf_ptr: jlong, - id: jlong, - ) -> jboolean { - let ui = convert_ptr!(ui_buf_ptr => UiContext); - let states = ui.widget_states.lock(); - states.get(&id).map(|s| s.clicked).unwrap_or(false).into() - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_ui_widgets_ButtonNative_getHovering( - _env: JNIEnv, - _class: JClass, - ui_buf_ptr: jlong, - id: jlong, - ) -> jboolean { - let ui = convert_ptr!(ui_buf_ptr => UiContext); - let states = ui.widget_states.lock(); - states.get(&id).map(|s| s.hovering).unwrap_or(false).into() - } -} @@ -1,99 +0,0 @@ -use std::any::Any; -use std::collections::HashMap; -use ::jni::JNIEnv; -use ::jni::objects::JObject; -use yakui::widgets::Checkbox; -use crate::scripting::result::DropbearNativeResult; -use crate::ui::{NativeWidget, UiInstructionType, WidgetParser, WidgetState}; - -pub(crate) struct CheckboxParser; - -#[derive(Debug)] -pub(crate) struct CheckboxWidget { - pub id: i64, - pub checkbox: Checkbox, -} - -impl WidgetParser for CheckboxParser { - fn parse(&self, env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Option<UiInstructionType>> { - let class = env.get_object_class(obj)?; - let name_str_obj = env.call_method(class, "getName", "()Ljava/lang/String;", &[])?.l()?; - let name_string: String = env.get_string(&name_str_obj.into())?.into(); - - if name_string.contains("CheckboxInstruction$Checkbox") { - let checked = env.get_field(obj, "checked", "Z")?.z()?; - let checkbox = Checkbox::new(checked); - - let id_obj = env.get_field(obj, "id", "Lcom/dropbear/ui/WidgetId;")?.l()?; - let id = env.get_field(id_obj, "id", "J")?.j()?; - - return Ok(Some(UiInstructionType::Widget(Box::new(CheckboxWidget { - id, - checkbox, - })))); - } - - Ok(None) - } - - fn name(&self) -> String { - String::from("CheckboxParser") - } -} - -impl NativeWidget for CheckboxWidget { - fn render(self: Box<Self>, state: &mut HashMap<i64, WidgetState>) { - let resp = self.checkbox.show(); - state.insert(self.id, WidgetState { - clicked: false, - hovering: false, - checked: resp.checked, - }); - - } - - fn id(&self) -> i64 { - self.id - } - - fn as_any(&self) -> &dyn Any { - self - } -} - -pub mod jni { - #![allow(non_snake_case)] - - use jni::JNIEnv; - use jni::objects::JClass; - use jni::sys::{jboolean, jlong}; - use crate::convert_ptr; - use crate::ui::UiContext; - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_ui_widgets_CheckboxNative_getChecked( - _env: JNIEnv, - _: JClass, - ui_buf_ptr: jlong, - id: jlong, - ) -> jboolean { - let ui = convert_ptr!(ui_buf_ptr => UiContext); - - if let Some(v) = ui.widget_states.lock().get(&(id as i64)) { - return v.checked.into(); - } - false.into() - } - - #[unsafe(no_mangle)] - pub extern "system" fn Java_com_dropbear_ui_widgets_CheckboxNative_hasCheckedState( - _env: JNIEnv, - _: JClass, - ui_buf_ptr: jlong, - id: jlong, - ) -> jboolean { - let ui = convert_ptr!(ui_buf_ptr => UiContext); - - ui.widget_states.lock().contains_key(&(id as i64)).into() - } -} @@ -1,86 +0,0 @@ -use std::any::Any; -use std::borrow::Cow; -use std::collections::HashMap; -use jni::JNIEnv; -use jni::objects::JObject; -use yakui::style::TextStyle; -use yakui::widgets::Pad; -use crate::scripting::jni::utils::FromJObject; -use crate::scripting::result::DropbearNativeResult; -use crate::ui::{NativeWidget, UiInstructionType, WidgetParser, WidgetState}; - -pub(crate) struct TextParser; - -#[derive(Debug)] -pub(crate) struct TextWidget { - pub id: i64, - pub text: yakui::widgets::Text, -} - -impl WidgetParser for TextParser { - fn parse(&self, env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Option<UiInstructionType>> { - let class = env.get_object_class(obj)?; - let name_str_obj = env.call_method(class, "getName", "()Ljava/lang/String;", &[])?.l()?; - let name_string: String = env.get_string(&name_str_obj.into())?.into(); - // println!("TextParser obj get_string result: {}", name_string); - - if name_string.contains("TextInstruction$Text") { - let text_obj = env.get_field(obj, "text", "Lcom/dropbear/ui/widgets/Text;")?.l()?; - let text = yakui::widgets::Text::from_jobject(env, &text_obj)?; - - let id_obj = env.get_field(obj, "id", "Lcom/dropbear/ui/WidgetId;")?.l()?; - let id = env.get_field(id_obj, "id", "J")?.j()?; - - return Ok(Some(UiInstructionType::Widget(Box::new(TextWidget { - id, - text, - })))) - } - - Ok(None) - } - - fn name(&self) -> String { - String::from("TextParser") - } -} - -impl NativeWidget for TextWidget { - fn render(self: Box<Self>, _state: &mut HashMap<i64, WidgetState>) { - let _ = self.text.show(); // no response - } - - fn id(&self) -> i64 { - self.id - } - - fn as_any(&self) -> &dyn Any { - self - } -} - -impl FromJObject for yakui::widgets::Text { - fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> - where - Self: Sized - { - let text_field = env.get_field(obj, "text", "Ljava/lang/String;")?; - let text_jstring = text_field.l()?.into(); - let text: String = env.get_string(&text_jstring)?.into(); - - let style_obj = env.get_field(obj, "style", "Lcom/dropbear/ui/styling/TextStyle;")?.l()?; - let style = TextStyle::from_jobject(env, &style_obj)?; - - let f = env.get_field(obj, "padding", "Lcom/dropbear/ui/styling/Padding;")?.l()?; - let padding = Pad::from_jobject( - env, - &f - )?; - - Ok(Self { - text: Cow::Owned(text), - style, - padding, - }) - } -} @@ -1,323 +0,0 @@ -use jni::JNIEnv; -use jni::objects::{JObject, JByteArray}; -use crate::scripting::jni::utils::FromJObject; -use crate::scripting::result::DropbearNativeResult; -use yakui::{Border, Color}; -use yakui::widgets::{Pad, DynamicButtonStyle}; -use yakui::{Alignment, BorderRadius}; -use yakui::style::{TextStyle, TextAlignment}; -use yakui::cosmic_text::{Attrs, AttrsOwned, FamilyOwned, Weight, Style, Stretch, CacheKeyFlags, FontFeatures, Feature, FeatureTag, Metrics, CacheMetrics}; - -impl FromJObject for FeatureTag { - fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { - let tag_obj = env.call_method(obj, "asBytes", "()[B", &[])?.l()?; - let tag_bytes = env.convert_byte_array(JByteArray::from(tag_obj))?; - - let mut fixed_tag = [0u8; 4]; - let len = tag_bytes.len().min(4); - fixed_tag[..len].copy_from_slice(&tag_bytes[..len]); - - Ok(FeatureTag::new(&fixed_tag)) - } -} - -impl FromJObject for Feature { - fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { - let tag_obj = env.get_field(obj, "tag", "Lcom/dropbear/ui/styling/fonts/FeatureTag;")?.l()?; - let tag = FeatureTag::from_jobject(env, &tag_obj)?; - - let value_obj = env.get_field(obj, "value", "Lcom/dropbear/ui/styling/fonts/UInt;")?.l()?; - let value = env.get_field(&value_obj, "value", "I")?.i()? as u32; - - Ok(Feature { - tag, - value, - }) - } -} - -impl FromJObject for FontFeatures { - fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { - let features_list_obj = env.get_field(obj, "features", "Ljava/util/List;")?.l()?; - - let size = env.call_method(&features_list_obj, "size", "()I", &[])?.i()?; - let mut features = Vec::with_capacity(size as usize); - - for i in 0..size { - let item = env.call_method(&features_list_obj, "get", "(I)Ljava/lang/Object;", &[i.into()])?.l()?; - if !item.is_null() { - features.push(Feature::from_jobject(env, &item)?); - } - } - - Ok(FontFeatures { features }) - } -} - -impl FromJObject for CacheMetrics { - fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { - let font_size = env.get_field(obj, "fontSize", "D")?.d()? as f32; - let line_height = env.get_field(obj, "lineHeight", "D")?.d()? as f32; - - Ok(CacheMetrics::from(Metrics { - font_size, - line_height, - })) - } -} - -impl FromJObject for Border { - fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { - let color_obj = env.get_field(obj, "colour", "Lcom/dropbear/utils/Colour;")?.l()?; - let color = Color::from_jobject(env, &color_obj)?; - let width = env.get_field(obj, "width", "D")?.d()? as f32; - Ok(Border { - color, - width, - }) - } -} - -impl FromJObject for Color { - fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { - let r = env.get_field(obj, "r", "B")?.b()? as u8; - let g = env.get_field(obj, "g", "B")?.b()? as u8; - let b = env.get_field(obj, "b", "B")?.b()? as u8; - let a = env.get_field(obj, "a", "B")?.b()? as u8; - Ok(Color::rgba(r, g, b, a)) - } -} - -impl FromJObject for Pad { - fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { - let left = env.get_field(obj, "left", "D")?.d()? as f32; - let right = env.get_field(obj, "right", "D")?.d()? as f32; - let top = env.get_field(obj, "top", "D")?.d()? as f32; - let bottom = env.get_field(obj, "bottom", "D")?.d()? as f32; - Ok(Pad { - left, - right, - top, - bottom, - }) - } -} - -impl FromJObject for BorderRadius { - fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { - let top_left = env.get_field(obj, "topLeft", "D")?.d()? as f32; - let top_right = env.get_field(obj, "topRight", "D")?.d()? as f32; - let bottom_left = env.get_field(obj, "bottomLeft", "D")?.d()? as f32; - let bottom_right = env.get_field(obj, "bottomRight", "D")?.d()? as f32; - Ok(BorderRadius { - top_left, - top_right, - bottom_left, - bottom_right, - }) - } -} - -impl FromJObject for Alignment { - fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { - let x = env.get_field(obj, "x", "D")?.d()? as f32; - let y = env.get_field(obj, "y", "D")?.d()? as f32; - Ok(Alignment::new(x, y)) - } -} - -impl FromJObject for TextAlignment { - fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { - let name_obj = env.call_method(obj, "name", "()Ljava/lang/String;", &[])?.l()?; - let name: String = env.get_string(&name_obj.into())?.into(); - match name.as_str() { - "Start" => Ok(TextAlignment::Start), - "Center" => Ok(TextAlignment::Center), - "End" => Ok(TextAlignment::End), - _ => Ok(TextAlignment::Start), - } - } -} - -impl FromJObject for Weight { - fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { - let val = env.get_field(obj, "value", "I")?.i()? as u16; - Ok(Weight(val)) - } -} - -impl FromJObject for Style { - fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { - let name_obj = env.call_method(obj, "name", "()Ljava/lang/String;", &[])?.l()?; - let name: String = env.get_string(&name_obj.into())?.into(); - match name.as_str() { - "Normal" => Ok(Style::Normal), - "Italic" => Ok(Style::Italic), - "Oblique" => Ok(Style::Oblique), - _ => Ok(Style::Normal), - } - } -} - -impl FromJObject for Stretch { - fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { - let name_obj = env.call_method(obj, "name", "()Ljava/lang/String;", &[])?.l()?; - let name: String = env.get_string(&name_obj.into())?.into(); - match name.as_str() { - "UltraCondensed" => Ok(Stretch::UltraCondensed), - "ExtraCondensed" => Ok(Stretch::ExtraCondensed), - "Condensed" => Ok(Stretch::Condensed), - "SemiCondensed" => Ok(Stretch::SemiCondensed), - "Normal" => Ok(Stretch::Normal), - "SemiExpanded" => Ok(Stretch::SemiExpanded), - "Expanded" => Ok(Stretch::Expanded), - "ExtraExpanded" => Ok(Stretch::ExtraExpanded), - "UltraExpanded" => Ok(Stretch::UltraExpanded), - _ => Ok(Stretch::Normal), - } - } -} - -impl FromJObject for FamilyOwned { - fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { - if env.is_instance_of(obj, "com/dropbear/ui/styling/fonts/Family$Name")? { - let value_obj = env.call_method(obj, "getValue", "()Ljava/lang/String;", &[])?.l()?; - let val: String = env.get_string(&value_obj.into())?.into(); - return Ok(FamilyOwned::Name(val.parse().unwrap())); - } - if env.is_instance_of(obj, "com/dropbear/ui/styling/fonts/Family$Serif")? { return Ok(FamilyOwned::Serif); } - if env.is_instance_of(obj, "com/dropbear/ui/styling/fonts/Family$SansSerif")? { return Ok(FamilyOwned::SansSerif); } - if env.is_instance_of(obj, "com/dropbear/ui/styling/fonts/Family$Cursive")? { return Ok(FamilyOwned::Cursive); } - if env.is_instance_of(obj, "com/dropbear/ui/styling/fonts/Family$Fantasy")? { return Ok(FamilyOwned::Fantasy); } - if env.is_instance_of(obj, "com/dropbear/ui/styling/fonts/Family$Monospace")? { return Ok(FamilyOwned::Monospace); } - - Ok(FamilyOwned::SansSerif) - } -} - -impl FromJObject for AttrsOwned { - fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { - let family_obj = env.get_field(obj, "family", "Lcom/dropbear/ui/styling/fonts/Family;")?.l()?; - let family_owned = FamilyOwned::from_jobject(env, &family_obj)?; - let family = family_owned.as_family(); - - let color_obj = env.get_field(obj, "colourOptions", "Lcom/dropbear/utils/Colour;")?.l()?; - let color_opt = if !color_obj.is_null() { - let colour = Color::from_jobject(env, &color_obj)?; - Some(yakui::cosmic_text::Color::rgba(colour.r, colour.g, colour.b, colour.a)) - } else { - None - }; - - let stretch_obj = env.get_field(obj, "stretch", "Lcom/dropbear/ui/styling/fonts/Stretch;")?.l()?; - let stretch = Stretch::from_jobject(env, &stretch_obj)?; - - let style_obj = env.get_field(obj, "style", "Lcom/dropbear/ui/styling/fonts/FontStyle;")?.l()?; - let style = Style::from_jobject(env, &style_obj)?; - - let weight_obj = env.get_field(obj, "weight", "Lcom/dropbear/ui/styling/fonts/FontWeight;")?.l()?; - let weight = Weight::from_jobject(env, &weight_obj)?; - - let metadata = match env.get_field(obj, "metadata", "I") { - Ok(val) => val.i()? as usize, - Err(_) => 0, - }; - - let letter_spacing_obj = env.get_field(obj, "letterSpacingOptions", "Ljava/lang/Double;")?.l()?; - let letter_spacing_opt = if !letter_spacing_obj.is_null() { - let val = env.call_method(&letter_spacing_obj, "doubleValue", "()D", &[])?.d()?; - Some(yakui::cosmic_text::LetterSpacing(val as f32)) - } else { - None - }; - - let font_features_obj = env.get_field(obj, "fontFeatures", "Lcom/dropbear/ui/styling/fonts/FontFeatures;")?.l()?; - let font_features = if !font_features_obj.is_null() { - FontFeatures::from_jobject(env, &font_features_obj)? - } else { - FontFeatures::default() - }; - - let cache_key_flags_val = env.get_field(obj, "cacheKeyFlags", "I")?.i()? as u32; - let cache_key_flags = CacheKeyFlags::from_bits_truncate(cache_key_flags_val); - - let metrics_obj = env.get_field(obj, "metricsOptions", "Lcom/dropbear/ui/styling/fonts/CacheMetrics;")?.l()?; - let metrics_opt = if !metrics_obj.is_null() { - Some(CacheMetrics::from_jobject(env, &metrics_obj)?) - } else { - None - }; - - Ok(AttrsOwned::new(&Attrs { - family, - stretch, - style, - weight, - metadata, - color_opt, - cache_key_flags, - metrics_opt, - letter_spacing_opt, - font_features, - })) - } -} - -impl FromJObject for TextStyle { - fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { - let align_obj = env.get_field(obj, "align", "Lcom/dropbear/ui/styling/fonts/TextAlignment;")?.l()?; - let align = TextAlignment::from_jobject(env, &align_obj)?; - - let font_size = env.get_field(obj, "fontSize", "D")?.d()? as f32; - - let color_obj = env.get_field(obj, "colour", "Lcom/dropbear/utils/Colour;")?.l()?; - let color = if !color_obj.is_null() { - Color::from_jobject(env, &color_obj)? - } else { - Color::WHITE - }; - - let attrs_obj = env.get_field(obj, "attrs", "Lcom/dropbear/ui/styling/fonts/FontAttributes;")?.l()?; - let attrs = AttrsOwned::from_jobject(env, &attrs_obj)?; - - Ok(TextStyle { - align, - font_size, - line_height_override: None, - color, - attrs, - }) - } -} - -impl FromJObject for DynamicButtonStyle { - fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> { - let text_obj = env.get_field(obj, "text", "Lcom/dropbear/ui/styling/TextStyle;")?.l()?; - let text = if !text_obj.is_null() { - TextStyle::from_jobject(env, &text_obj)? - } else { - println!("Text is null, setting to default"); - TextStyle::default() - }; - - let fill_obj = env.get_field(obj, "fill", "Lcom/dropbear/utils/Colour;")?.l()?; - let fill = if !fill_obj.is_null() { - Color::from_jobject(env, &fill_obj)? - } else { - Color::GRAY - }; - - let border_obj = env.get_field(obj, "border", "Lcom/dropbear/ui/styling/Border;")?.l()?; - let border = if !border_obj.is_null() { - Some(Border::from_jobject(env, &border_obj)?) - } else { - None - }; - - Ok(DynamicButtonStyle { - text, - fill, - border, - }) - } -} @@ -0,0 +1,12 @@ +[package] +name = "goanna-gen" +version.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +authors.workspace = true + +[dependencies] +cbindgen.workspace = true +syn = { workspace = true, features = ["full"] } +anyhow.workspace = true @@ -0,0 +1,5 @@ +# goanna-gen + +A c header compile-time generator that sits in build.rs. + +When paired with `dropbear_macro`, you can generate c headers and JNI headers easily for interop. @@ -0,0 +1,844 @@ +pub fn generate_c_header() -> anyhow::Result<()> { + let manifest_dir = std::path::PathBuf::from(std::env::var("CARGO_MANIFEST_DIR")?); + let workspace_root = manifest_dir + .parent() + .and_then(|p| p.parent()) + .ok_or_else(|| anyhow::anyhow!("Failed to locate workspace root"))?; + + let output_path = workspace_root.join("include").join("dropbear.h"); + if let Some(parent) = output_path.parent() { + std::fs::create_dir_all(parent)?; + } + + let src_dir = manifest_dir.join("src"); + let mut functions = Vec::new(); + let mut structs = std::collections::HashMap::new(); + let mut enums = Vec::new(); + collect_exported_functions(&src_dir, &mut functions, &mut structs, &mut enums)?; + + let header = render_header(&functions, &structs, &enums); + std::fs::write(&output_path, header)?; + + Ok(()) +} + +#[derive(Debug)] +struct ExportedFunction { + name: String, + params: Vec<ExportParam>, + out_type: Option<String>, +} + +#[derive(Debug, Clone)] +struct ExportParam { + name: String, + ty: String, +} + +fn collect_exported_functions( + dir: &std::path::Path, + out: &mut Vec<ExportedFunction>, + structs: &mut std::collections::HashMap<String, StructDef>, + enums: &mut Vec<EnumDef>, +) -> anyhow::Result<()> { + if dir.is_dir() { + for entry in std::fs::read_dir(dir)? { + let entry = entry?; + let path = entry.path(); + if path.is_dir() { + collect_exported_functions(&path, out, structs, enums)?; + } else if path.extension().and_then(|s| s.to_str()) == Some("rs") { + let content = std::fs::read_to_string(&path)?; + let file = syn::parse_file(&content)?; + extract_exports_from_file(&file, &path, dir, out, structs)?; + extract_structs_from_file(&file, structs)?; + extract_repr_c_enums_from_file(&file, enums)?; + } + } + } + Ok(()) +} + +fn extract_exports_from_file( + file: &syn::File, + file_path: &std::path::Path, + src_root: &std::path::Path, + out: &mut Vec<ExportedFunction>, + _structs: &mut std::collections::HashMap<String, StructDef>, +) -> anyhow::Result<()> { + let module_path = module_path_from_file(file_path, src_root); + for item in &file.items { + if let syn::Item::Fn(func) = item { + if let Some(export) = parse_export_attr(&func.attrs)? { + if export.c.is_none() { + continue; + } + + let c_name = export.c.and_then(|c| c.name).unwrap_or_else(|| { + if let Some(path) = module_path.as_deref() { + if !path.is_empty() { + return format!("dropbear_{}_{}", path, func.sig.ident); + } + } + format!("dropbear_{}", func.sig.ident) + }); + + let (out_type, out_is_optional) = extract_result_type(&func.sig.output)?; + let mut params = Vec::new(); + for input in &func.sig.inputs { + if let syn::FnArg::Typed(pat_ty) = input { + let (define_ty, is_entity) = extract_arg_markers(&pat_ty.attrs); + let name = match &*pat_ty.pat { + syn::Pat::Ident(ident) => ident.ident.to_string(), + _ => continue, + }; + + let ty = if is_entity { + "uint64_t".to_string() + } else if let Some(define_ty) = define_ty { + type_to_c(&define_ty, true) + } else if is_object_input(&pat_ty.ty) { + object_input_to_c(&pat_ty.ty) + } else { + type_to_c(&pat_ty.ty, false) + }; + + params.push(ExportParam { name, ty }); + } + } + + if out_type.is_some() { + let out_ty = out_type.clone().unwrap(); + params.push(ExportParam { name: "out0".to_string(), ty: format!("{}*", out_ty) }); + if out_is_optional { + params.push(ExportParam { name: "out0_present".to_string(), ty: "bool*".to_string() }); + } + } + + out.push(ExportedFunction { + name: c_name, + params, + out_type, + }); + } + } + } + Ok(()) +} + +fn module_path_from_file( + file_path: &std::path::Path, + src_root: &std::path::Path, +) -> Option<String> { + let rel = file_path.strip_prefix(src_root).ok()?; + let mut parts: Vec<String> = rel + .components() + .map(|c| c.as_os_str().to_string_lossy().to_string()) + .collect(); + + let file = parts.pop()?; + let stem = file.strip_suffix(".rs").unwrap_or(&file); + + if stem != "mod" && stem != "lib" && stem != "main" { + parts.push(stem.to_string()); + } + + if parts.is_empty() { + return None; + } + + let joined = parts.join("_"); + Some(joined.replace('-', "_")) +} + +#[derive(Debug, Clone)] +struct StructDef { + name: String, + fields: Vec<ExportParam>, + is_repr_c: bool, +} + +#[derive(Debug)] +struct EnumDef { + name: String, + variants: Vec<EnumVariantDef>, +} + +#[derive(Debug)] +struct EnumVariantDef { + name: String, + fields: Vec<ExportParam>, +} + +fn extract_repr_c_enums_from_file( + file: &syn::File, + enums: &mut Vec<EnumDef>, +) -> anyhow::Result<()> { + for item in &file.items { + if let syn::Item::Enum(enm) = item { + if !has_repr_c_enum_attr(&enm.attrs) { + continue; + } + let mut variants = Vec::new(); + for variant in &enm.variants { + let mut fields = Vec::new(); + match &variant.fields { + syn::Fields::Named(named) => { + for field in &named.named { + let name = field + .ident + .as_ref() + .map(|i| i.to_string()) + .unwrap_or_else(|| "field".to_string()); + let ty = type_to_c(&field.ty, false); + fields.push(ExportParam { name, ty }); + } + } + syn::Fields::Unnamed(unnamed) => { + for (idx, field) in unnamed.unnamed.iter().enumerate() { + let name = format!("_{}", idx); + let ty = type_to_c(&field.ty, false); + fields.push(ExportParam { name, ty }); + } + } + syn::Fields::Unit => {} + } + variants.push(EnumVariantDef { name: variant.ident.to_string(), fields }); + } + enums.push(EnumDef { name: enm.ident.to_string(), variants }); + } + } + Ok(()) +} + +fn extract_structs_from_file( + file: &syn::File, + structs: &mut std::collections::HashMap<String, StructDef>, +) -> anyhow::Result<()> { + for item in &file.items { + if let syn::Item::Struct(strct) = item { + let name = strct.ident.to_string(); + let is_repr_c = has_repr_c(&strct.attrs); + let mut fields = Vec::new(); + + if let syn::Fields::Named(named) = &strct.fields { + for field in &named.named { + let field_name = field.ident.as_ref().map(|i| i.to_string()).unwrap_or_else(|| "field".to_string()); + let ty = type_to_c(&field.ty, false); + fields.push(ExportParam { name: field_name, ty }); + } + } + + structs.insert(name.clone(), StructDef { name, fields, is_repr_c }); + } + } + + Ok(()) +} + +#[derive(Default)] +struct ExportAttr { + c: Option<CArgs>, +} + +#[derive(Default)] +struct CArgs { + name: Option<String>, +} + +fn parse_export_attr(attrs: &[syn::Attribute]) -> anyhow::Result<Option<ExportAttr>> { + for attr in attrs { + let path = attr.path(); + let is_export = path.segments.last().map(|s| s.ident == "export").unwrap_or(false) + || (path.segments.iter().any(|s| s.ident == "dropbear_macro") + && path.segments.last().map(|s| s.ident == "export").unwrap_or(false)); + if !is_export { + continue; + } + + let meta = &attr.meta; + if let syn::Meta::List(list) = meta { + let args = syn::parse2::<ExportArgs>(list.tokens.clone())?; + return Ok(Some(ExportAttr { c: args.c })); + } + } + + Ok(None) +} + +struct ExportArgs { + c: Option<CArgs>, +} + +impl syn::parse::Parse for ExportArgs { + fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { + let items = syn::punctuated::Punctuated::<ExportItem, syn::Token![,]>::parse_terminated(input)?; + let mut args = ExportArgs { c: None }; + + for item in items { + if let ExportItem::C(c) = item { + args.c = Some(c); + } + } + + Ok(args) + } +} + +enum ExportItem { + C(CArgs), + Kotlin, +} + +impl syn::parse::Parse for ExportItem { + fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { + let ident: syn::Ident = input.parse()?; + if ident == "c" { + let args = if input.peek(syn::token::Paren) { + let content; + syn::parenthesized!(content in input); + let mut c_args = CArgs::default(); + while !content.is_empty() { + let key: syn::Ident = content.parse()?; + content.parse::<syn::Token![=]>()?; + let value: syn::LitStr = content.parse()?; + if key == "name" { + c_args.name = Some(value.value()); + } + if content.peek(syn::Token![,]) { + content.parse::<syn::Token![,]>()?; + } + } + c_args + } else { + CArgs::default() + }; + return Ok(ExportItem::C(args)); + } + + if ident == "kotlin" { + if input.peek(syn::token::Paren) { + let content; + syn::parenthesized!(content in input); + while !content.is_empty() { + let _key: syn::Ident = content.parse()?; + content.parse::<syn::Token![=]>()?; + let _value: syn::LitStr = content.parse()?; + if content.peek(syn::Token![,]) { + content.parse::<syn::Token![,]>()?; + } + } + } + return Ok(ExportItem::Kotlin); + } + + Err(syn::Error::new(ident.span(), "Expected c or kotlin")) + } +} + +fn extract_arg_markers(attrs: &[syn::Attribute]) -> (Option<syn::Type>, bool) { + let mut define_ty: Option<syn::Type> = None; + let mut is_entity = false; + for attr in attrs { + let path = attr.path(); + let ident = path.segments.last().map(|s| s.ident.to_string()).unwrap_or_default(); + if ident == "define" { + if let Ok(ty) = attr.parse_args::<syn::Type>() { + define_ty = Some(ty); + } + } + if ident == "entity" { + is_entity = true; + } + } + (define_ty, is_entity) +} + +fn extract_result_type(output: &syn::ReturnType) -> anyhow::Result<(Option<String>, bool)> { + let ty = match output { + syn::ReturnType::Type(_, ty) => ty, + syn::ReturnType::Default => return Ok((None, false)), + }; + + let inner = match &**ty { + syn::Type::Path(path) => { + let last = path.path.segments.last().ok_or_else(|| anyhow::anyhow!("Invalid return type"))?; + if last.ident != "DropbearNativeResult" { + return Ok((None, false)); + } + match &last.arguments { + syn::PathArguments::AngleBracketed(args) => args.args.first().and_then(|a| match a { + syn::GenericArgument::Type(t) => Some(t.clone()), + _ => None, + }).ok_or_else(|| anyhow::anyhow!("DropbearNativeResult missing type"))?, + _ => return Ok((None, false)), + } + } + _ => return Ok((None, false)), + }; + + if is_unit_type(&inner) { + return Ok((None, false)); + } + + if let Some(opt_inner) = extract_option_inner(&inner) { + return Ok((Some(type_to_c(&opt_inner, true)), true)); + } + + Ok((Some(type_to_c(&inner, true)), false)) +} + +fn extract_option_inner(ty: &syn::Type) -> Option<syn::Type> { + if let syn::Type::Path(path) = ty { + let last = path.path.segments.last()?; + if last.ident != "Option" { + return None; + } + if let syn::PathArguments::AngleBracketed(args) = &last.arguments { + if let Some(syn::GenericArgument::Type(inner)) = args.args.first() { + return Some(inner.clone()); + } + } + } + None +} + +fn is_unit_type(ty: &syn::Type) -> bool { + matches!(ty, syn::Type::Tuple(tuple) if tuple.elems.is_empty()) +} + +fn type_to_c(ty: &syn::Type, for_output: bool) -> String { + if let syn::Type::Reference(reference) = ty { + let inner = type_to_c(&reference.elem, for_output); + let mutability = if reference.mutability.is_some() { "" } else { "const " }; + return format!("{}{}*", mutability, inner); + } + if let Some(inner) = extract_option_inner(ty) { + let inner_c = type_to_c(&inner, true); + let mutability = if for_output { "" } else { "const " }; + return format!("{}{}*", mutability, inner_c); + } + if let Some(inner) = vec_inner_type(ty) { + return array_struct_name_from_type(&inner); + } + + if let syn::Type::Path(path) = ty { + let ident = path.path.segments.last().map(|s| s.ident.to_string()).unwrap_or_else(|| "void".to_string()); + return match ident.as_str() { + "i8" => "int8_t".to_string(), + "u8" => "uint8_t".to_string(), + "i16" => "int16_t".to_string(), + "u16" => "uint16_t".to_string(), + "i32" => "int32_t".to_string(), + "u32" => "uint32_t".to_string(), + "i64" => "int64_t".to_string(), + "u64" => "uint64_t".to_string(), + "isize" => "intptr_t".to_string(), + "usize" => "size_t".to_string(), + "f32" => "float".to_string(), + "f64" => "double".to_string(), + "bool" => "bool".to_string(), + "String" => { + if for_output { + "char*".to_string() + } else { + "const char*".to_string() + } + } + _ => ident, + }; + } + + "void".to_string() +} + +fn vec_inner_type(ty: &syn::Type) -> Option<syn::Type> { + if let syn::Type::Path(path) = ty { + let last = path.path.segments.last()?; + if last.ident != "Vec" { + return None; + } + if let syn::PathArguments::AngleBracketed(args) = &last.arguments { + if let Some(syn::GenericArgument::Type(inner)) = args.args.first() { + return Some(inner.clone()); + } + } + } + None +} + +fn type_name_from_type(ty: &syn::Type) -> Option<String> { + if let syn::Type::Path(path) = ty { + return path.path.segments.last().map(|s| s.ident.to_string()); + } + None +} + +fn array_struct_name_from_type(ty: &syn::Type) -> String { + if let Some(inner) = vec_inner_type(ty) { + let inner_name = array_struct_name_from_type(&inner); + return format!("{}Array", inner_name); + } + + let name = type_name_from_type(ty).unwrap_or_else(|| "Unknown".to_string()); + format!("{}Array", name) +} + +fn render_header( + funcs: &[ExportedFunction], + structs: &std::collections::HashMap<String, StructDef>, + enums: &[EnumDef], +) -> String { + let mut out = String::new(); + out.push_str("// Machine generated header bindings by goanna-gen.\n"); + out.push_str("// DO NOT EDIT UNLESS YOU KNOW WHAT YOU ARE DOING (it will get regenerated anyways with a modification to eucalyptus-core/src).\n"); + out.push_str("// Licensed under MIT or Apache 2.0 depending on your mood.\n"); + out.push_str("// part of the dropbear project, by tirbofish\n\n"); + out.push_str("#ifndef DROPBEAR_H\n"); + out.push_str("#define DROPBEAR_H\n\n"); + out.push_str("#include <stdbool.h>\n"); + out.push_str("#include <stdint.h>\n\n"); + out.push_str("#include <stddef.h>\n\n"); + + let mut needed = std::collections::HashSet::new(); + for func in funcs { + if let Some(out_ty) = &func.out_type { + if is_custom_type(out_ty) { + needed.insert(out_ty.clone()); + } else if is_opaque_ptr_name(out_ty) { + needed.insert(out_ty.clone()); + } + } + for param in &func.params { + if is_opaque_ptr_name(¶m.ty) { + needed.insert(param.ty.clone()); + } + if let Some(base) = base_type_name(¶m.ty) { + if is_custom_type(&base) { + needed.insert(base); + } else if is_opaque_ptr_name(&base) { + needed.insert(base); + } + } + } + } + + let mut emitted = std::collections::HashSet::new(); + + if needed.contains("AssetKind") { + out.push_str("typedef enum AssetKind {\n"); + out.push_str(" AssetKind_Texture = 0,\n"); + out.push_str(" AssetKind_Model = 1,\n"); + out.push_str("} AssetKind;\n\n"); + emitted.insert("AssetKind".to_string()); + } + + for enm in enums { + emit_repr_c_enum(enm, structs, &mut emitted, &mut out); + } + for ty in needed { + emit_structs_recursive(&ty, structs, &mut emitted, &mut out); + } + + for func in funcs { + let params = if func.params.is_empty() { + "void".to_string() + } else { + func.params.iter() + .map(|p| format!("{} {}", p.ty, p.name)) + .collect::<Vec<_>>() + .join(", ") + }; + out.push_str(&format!("int32_t {}({});\n", func.name, params)); + } + + out.push_str("\n#endif /* DROPBEAR_H */\n"); + out +} + +fn emit_repr_c_enum( + enm: &EnumDef, + structs: &std::collections::HashMap<String, StructDef>, + emitted: &mut std::collections::HashSet<String>, + out: &mut String, +) { + if emitted.contains(&enm.name) { + return; + } + + let tag_name = format!("{}Tag", enm.name); + let data_name = format!("{}Data", enm.name); + let ffi_name = format!("{}Ffi", enm.name); + + for var in &enm.variants { + for field in &var.fields { + if is_array_type(&field.ty) { + emit_array_struct(&field.ty, structs, emitted, out); + } + } + } + + out.push_str(&format!("typedef enum {} {{\n", tag_name)); + for (idx, var) in enm.variants.iter().enumerate() { + out.push_str(&format!(" {}_{} = {},\n", tag_name, var.name, idx)); + } + out.push_str(&format!("}} {};\n\n", tag_name)); + + for var in &enm.variants { + let struct_name = format!("{}{}", enm.name, var.name); + out.push_str(&format!("typedef struct {} {{\n", struct_name)); + for field in &var.fields { + out.push_str(&format!(" {} {};\n", field.ty, field.name)); + } + out.push_str(&format!("}} {};\n\n", struct_name)); + } + + out.push_str(&format!("typedef union {} {{\n", data_name)); + for var in &enm.variants { + let struct_name = format!("{}{}", enm.name, var.name); + out.push_str(&format!(" {} {};\n", struct_name, var.name)); + } + out.push_str(&format!("}} {};\n\n", data_name)); + + out.push_str(&format!("typedef struct {} {{\n", ffi_name)); + out.push_str(&format!(" {} tag;\n", tag_name)); + out.push_str(&format!(" {} data;\n", data_name)); + out.push_str(&format!("}} {};\n\n", ffi_name)); + + out.push_str(&format!("typedef {} {};\n\n", ffi_name, enm.name)); + emitted.insert(ffi_name); + emitted.insert(enm.name.clone()); +} + +fn has_repr_c_enum_attr(attrs: &[syn::Attribute]) -> bool { + for attr in attrs { + let path = attr.path(); + if path.segments.last().map(|s| s.ident == "repr_c_enum").unwrap_or(false) { + return true; + } + if path.segments.iter().any(|s| s.ident == "dropbear_macro") + && path.segments.last().map(|s| s.ident == "repr_c_enum").unwrap_or(false) + { + return true; + } + } + false +} + +fn has_repr_c(attrs: &[syn::Attribute]) -> bool { + for attr in attrs { + if !attr.path().is_ident("repr") { + continue; + } + if let syn::Meta::List(list) = &attr.meta { + let tokens = list.tokens.to_string(); + if tokens.contains("C") || tokens.contains("transparent") { + return true; + } + } + } + false +} + +fn is_custom_type(ty: &str) -> bool { + if ty.ends_with('*') { + return false; + } + if is_opaque_ptr_name(ty) { + return false; + } + !is_builtin_c_type(ty) +} + +fn base_type_name(ty: &str) -> Option<String> { + let mut t = ty.trim().to_string(); + if t.starts_with("const ") { + t = t.trim_start_matches("const ").trim().to_string(); + } + if t.ends_with('*') { + t = t.trim_end_matches('*').trim().to_string(); + return Some(t); + } + None +} + +fn is_object_input(ty: &syn::Type) -> bool { + let inner = peel_reference(ty); + if is_string_type(inner) || is_primitive_type(inner) { + return false; + } + !is_define_or_entity_like(inner) +} + +fn object_input_to_c(ty: &syn::Type) -> String { + match ty { + syn::Type::Reference(reference) => { + let inner = type_to_c(&reference.elem, false); + let mutability = if reference.mutability.is_some() { "" } else { "const " }; + format!("{}{}*", mutability, inner) + } + _ => type_to_c(ty, false), + } +} + +fn is_define_or_entity_like(_ty: &syn::Type) -> bool { + false +} + +fn is_string_type(ty: &syn::Type) -> bool { + matches!(ty, syn::Type::Path(path) if path.path.segments.last().map(|s| s.ident == "String").unwrap_or(false)) +} + +fn is_primitive_type(ty: &syn::Type) -> bool { + matches!(ty, syn::Type::Path(path) if { + let ident = path.path.segments.last().map(|s| s.ident.to_string()).unwrap_or_default(); + matches!( + ident.as_str(), + "i8" | "u8" | "i16" | "u16" | "i32" | "u32" | "i64" | "u64" | + "isize" | "usize" | "f32" | "f64" | "bool" + ) + }) +} + +fn peel_reference<'a>(ty: &'a syn::Type) -> &'a syn::Type { + if let syn::Type::Reference(reference) = ty { + &reference.elem + } else { + ty + } +} + +fn is_builtin_c_type(ty: &str) -> bool { + matches!( + ty, + "int8_t" | "uint8_t" | "int16_t" | "uint16_t" | "int32_t" | "uint32_t" | + "int64_t" | "uint64_t" | "intptr_t" | "uintptr_t" | "bool" | "float" | + "double" | "char" | "char*" | "const char*" | "void*" | "size_t" + ) +} + +fn is_opaque_ptr_name(name: &str) -> bool { + name.ends_with("Ptr") +} + +fn emit_structs_recursive( + name: &str, + structs: &std::collections::HashMap<String, StructDef>, + emitted: &mut std::collections::HashSet<String>, + out: &mut String, +) { + if emitted.contains(name) { + return; + } + + if is_opaque_ptr_name(name) { + out.push_str(&format!("typedef void* {};\n\n", name)); + emitted.insert(name.to_string()); + return; + } + + if let Some(def) = structs.get(name) { + for field in &def.fields { + if is_array_type(&field.ty) { + emit_array_struct(&field.ty, structs, emitted, out); + continue; + } + if is_custom_type(&field.ty) { + emit_structs_recursive(&field.ty, structs, emitted, out); + } + } + + if !def.is_repr_c { + out.push_str("// NOTE: type is not #[repr(C)] in Rust; ensure C ABI safety.\n"); + } + + out.push_str(&format!("typedef struct {} {{\n", def.name)); + for field in &def.fields { + out.push_str(&format!(" {} {};\n", field.ty, field.name)); + } + out.push_str(&format!("}} {};\n\n", def.name)); + emitted.insert(def.name.clone()); + } else if is_array_type(name) { + emit_array_struct(name, structs, emitted, out); + } else { + out.push_str(&format!("typedef struct {} {};// opaque\n\n", name, name)); + emitted.insert(name.to_string()); + } +} + +fn is_array_type(ty: &str) -> bool { + ty.ends_with("Array") +} + +fn emit_array_struct( + name: &str, + structs: &std::collections::HashMap<String, StructDef>, + emitted: &mut std::collections::HashSet<String>, + out: &mut String, +) { + if emitted.contains(name) { + return; + } + let elem = name.trim_end_matches("Array"); + + if is_array_type(elem) { + emit_array_struct(elem, structs, emitted, out); + } + + if is_builtin_rust_primitive(elem) { + let c_elem = map_primitive_name(elem); + if !emitted.contains(elem) { + emitted.insert(elem.to_string()); + } + out.push_str(&format!("typedef struct {} {{\n", name)); + out.push_str(&format!(" {}* values;\n", c_elem)); + out.push_str(" size_t length;\n"); + out.push_str(" size_t capacity;\n"); + out.push_str(&format!("}} {};\n\n", name)); + emitted.insert(name.to_string()); + return; + } + + if !emitted.contains(elem) { + if structs.contains_key(elem) { + emit_structs_recursive(elem, structs, emitted, out); + } else { + out.push_str(&format!("typedef struct {} {};// opaque\n\n", elem, elem)); + emitted.insert(elem.to_string()); + } + } + + out.push_str(&format!("typedef struct {} {{\n", name)); + out.push_str(&format!(" {}* values;\n", elem)); + out.push_str(" size_t length;\n"); + out.push_str(" size_t capacity;\n"); + out.push_str(&format!("}} {};\n\n", name)); + emitted.insert(name.to_string()); +} + +fn is_builtin_rust_primitive(name: &str) -> bool { + matches!( + name, + "i8" | "u8" | "i16" | "u16" | "i32" | "u32" | "i64" | "u64" | + "isize" | "usize" | "f32" | "f64" | "bool" + ) +} + +fn map_primitive_name(name: &str) -> &'static str { + match name { + "i8" => "int8_t", + "u8" => "uint8_t", + "i16" => "int16_t", + "u16" => "uint16_t", + "i32" => "int32_t", + "u32" => "uint32_t", + "i64" => "int64_t", + "u64" => "uint64_t", + "isize" => "intptr_t", + "usize" => "size_t", + "f32" => "float", + "f64" => "double", + "bool" => "bool", + _ => "void", + } +} @@ -20,7 +20,7 @@ use eucalyptus_core::scripting::{ScriptManager, ScriptTarget}; use eucalyptus_core::states::{WorldLoadingStatus, SCENES, Script}; use eucalyptus_core::scene::loading::{SceneLoadResult, SCENE_LOADER}; use eucalyptus_core::traits::registry::ComponentRegistry; -use eucalyptus_core::ptr::{CommandBufferPtr, InputStatePtr, PhysicsStatePtr, WorldPtr}; +use eucalyptus_core::ptr::{CommandBufferPtr, GraphicsContextPtr, InputStatePtr, PhysicsStatePtr, WorldPtr}; use eucalyptus_core::command::COMMAND_BUFFER; use eucalyptus_core::scene::loading::IsSceneLoaded; use std::collections::HashMap; @@ -255,7 +255,7 @@ impl PlayMode { } } - fn reload_scripts_for_current_world(&mut self) { + fn reload_scripts_for_current_world(&mut self, graphics: Arc<SharedGraphicsContext>) { let mut entity_tag_map: HashMap<String, Vec<Entity>> = HashMap::new(); for (entity_id, script) in self.world.query::<(Entity, &Script)>().iter() { for tag in &script.tags { @@ -281,11 +281,12 @@ impl PlayMode { let world_ptr = self.world.as_mut() as WorldPtr; let input_ptr = &mut self.input_state as InputStatePtr; let graphics_ptr = COMMAND_BUFFER.0.as_ref() as CommandBufferPtr; + let graphics_context_ptr = Arc::as_ptr(&graphics) as GraphicsContextPtr; let physics_ptr = self.physics_state.as_mut() as PhysicsStatePtr; if let Err(e) = self .script_manager - .load_script(world_ptr, input_ptr, graphics_ptr, physics_ptr) + .load_script(world_ptr, input_ptr, graphics_ptr, graphics_context_ptr, physics_ptr) { panic!("Failed to load scripts: {}", e); } else { @@ -439,7 +440,7 @@ impl PlayMode { self.load_wgpu_nerdy_stuff(graphics); - self.reload_scripts_for_current_world(); + self.reload_scripts_for_current_world(graphics.clone()); log::debug!("Scene '{}' loaded", scene_name); } @@ -461,7 +462,7 @@ impl PlayMode { } self.load_wgpu_nerdy_stuff(graphics); - self.reload_scripts_for_current_world(); + self.reload_scripts_for_current_world(graphics.clone()); self.current_scene = Some(scene_progress.requested_scene.clone()); } @@ -1,2613 +0,0 @@ -pub mod model { - use crate::types::{NQuaternion, NVector2, NVector3, NVector4}; - use dropbear_engine::model::{ - Animation, AnimationChannel, AnimationInterpolation, ChannelValues, Material, - Mesh, ModelVertex, Node, NodeTransform, Skin, - }; - use dropbear_engine::texture::Texture; - pub use ffi::*; - use ffi_impl::{ - NMaterialInner, NMeshInner, NModelVertexInner, NNodeInner, NNodeTransformInner, - NSkinInner, - }; - #[allow(dead_code)] - #[allow(unused_imports)] - mod ffi_impl { - use super::*; - use super::ffi::*; - use dropbear_engine::asset::Handle; - use crate::asset::model::{ - map_animation, map_material, map_mesh, map_node, map_skin, - }; - use crate::ptr::AssetRegistryUnwrapped; - pub struct NModelVertexInner { - pub position: crate::types::NVector3, - pub normal: crate::types::NVector3, - pub tangent: crate::types::NVector4, - pub tex_coords0: crate::types::NVector2, - pub tex_coords1: crate::types::NVector2, - pub colour0: crate::types::NVector4, - pub joints0: Vec<i32>, - pub weights0: crate::types::NVector4, - } - #[automatically_derived] - impl ::core::clone::Clone for NModelVertexInner { - #[inline] - fn clone(&self) -> NModelVertexInner { - NModelVertexInner { - position: ::core::clone::Clone::clone(&self.position), - normal: ::core::clone::Clone::clone(&self.normal), - tangent: ::core::clone::Clone::clone(&self.tangent), - tex_coords0: ::core::clone::Clone::clone(&self.tex_coords0), - tex_coords1: ::core::clone::Clone::clone(&self.tex_coords1), - colour0: ::core::clone::Clone::clone(&self.colour0), - joints0: ::core::clone::Clone::clone(&self.joints0), - weights0: ::core::clone::Clone::clone(&self.weights0), - } - } - } - #[automatically_derived] - impl ::core::fmt::Debug for NModelVertexInner { - #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - let names: &'static _ = &[ - "position", - "normal", - "tangent", - "tex_coords0", - "tex_coords1", - "colour0", - "joints0", - "weights0", - ]; - let values: &[&dyn ::core::fmt::Debug] = &[ - &self.position, - &self.normal, - &self.tangent, - &self.tex_coords0, - &self.tex_coords1, - &self.colour0, - &self.joints0, - &&self.weights0, - ]; - ::core::fmt::Formatter::debug_struct_fields_finish( - f, - "NModelVertexInner", - names, - values, - ) - } - } - pub struct NMeshInner { - pub name: String, - pub num_elements: i32, - pub material_index: i32, - pub vertices: Vec<NModelVertex>, - } - #[automatically_derived] - impl ::core::clone::Clone for NMeshInner { - #[inline] - fn clone(&self) -> NMeshInner { - NMeshInner { - name: ::core::clone::Clone::clone(&self.name), - num_elements: ::core::clone::Clone::clone(&self.num_elements), - material_index: ::core::clone::Clone::clone(&self.material_index), - vertices: ::core::clone::Clone::clone(&self.vertices), - } - } - } - #[automatically_derived] - impl ::core::fmt::Debug for NMeshInner { - #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_struct_field4_finish( - f, - "NMeshInner", - "name", - &self.name, - "num_elements", - &self.num_elements, - "material_index", - &self.material_index, - "vertices", - &&self.vertices, - ) - } - } - pub struct NMaterialInner { - pub name: String, - pub diffuse_texture: u64, - pub normal_texture: u64, - pub tint: crate::types::NVector4, - pub emissive_factor: crate::types::NVector3, - pub metallic_factor: f32, - pub roughness_factor: f32, - pub alpha_cutoff: Option<f32>, - pub double_sided: bool, - pub occlusion_strength: f32, - pub normal_scale: f32, - pub uv_tiling: crate::types::NVector2, - pub emissive_texture: Option<u64>, - pub metallic_roughness_texture: Option<u64>, - pub occlusion_texture: Option<u64>, - } - #[automatically_derived] - impl ::core::clone::Clone for NMaterialInner { - #[inline] - fn clone(&self) -> NMaterialInner { - NMaterialInner { - name: ::core::clone::Clone::clone(&self.name), - diffuse_texture: ::core::clone::Clone::clone(&self.diffuse_texture), - normal_texture: ::core::clone::Clone::clone(&self.normal_texture), - tint: ::core::clone::Clone::clone(&self.tint), - emissive_factor: ::core::clone::Clone::clone(&self.emissive_factor), - metallic_factor: ::core::clone::Clone::clone(&self.metallic_factor), - roughness_factor: ::core::clone::Clone::clone( - &self.roughness_factor, - ), - alpha_cutoff: ::core::clone::Clone::clone(&self.alpha_cutoff), - double_sided: ::core::clone::Clone::clone(&self.double_sided), - occlusion_strength: ::core::clone::Clone::clone( - &self.occlusion_strength, - ), - normal_scale: ::core::clone::Clone::clone(&self.normal_scale), - uv_tiling: ::core::clone::Clone::clone(&self.uv_tiling), - emissive_texture: ::core::clone::Clone::clone( - &self.emissive_texture, - ), - metallic_roughness_texture: ::core::clone::Clone::clone( - &self.metallic_roughness_texture, - ), - occlusion_texture: ::core::clone::Clone::clone( - &self.occlusion_texture, - ), - } - } - } - #[automatically_derived] - impl ::core::fmt::Debug for NMaterialInner { - #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - let names: &'static _ = &[ - "name", - "diffuse_texture", - "normal_texture", - "tint", - "emissive_factor", - "metallic_factor", - "roughness_factor", - "alpha_cutoff", - "double_sided", - "occlusion_strength", - "normal_scale", - "uv_tiling", - "emissive_texture", - "metallic_roughness_texture", - "occlusion_texture", - ]; - let values: &[&dyn ::core::fmt::Debug] = &[ - &self.name, - &self.diffuse_texture, - &self.normal_texture, - &self.tint, - &self.emissive_factor, - &self.metallic_factor, - &self.roughness_factor, - &self.alpha_cutoff, - &self.double_sided, - &self.occlusion_strength, - &self.normal_scale, - &self.uv_tiling, - &self.emissive_texture, - &self.metallic_roughness_texture, - &&self.occlusion_texture, - ]; - ::core::fmt::Formatter::debug_struct_fields_finish( - f, - "NMaterialInner", - names, - values, - ) - } - } - pub struct NNodeTransformInner { - pub translation: crate::types::NVector3, - pub rotation: crate::types::NQuaternion, - pub scale: crate::types::NVector3, - } - #[automatically_derived] - impl ::core::clone::Clone for NNodeTransformInner { - #[inline] - fn clone(&self) -> NNodeTransformInner { - NNodeTransformInner { - translation: ::core::clone::Clone::clone(&self.translation), - rotation: ::core::clone::Clone::clone(&self.rotation), - scale: ::core::clone::Clone::clone(&self.scale), - } - } - } - #[automatically_derived] - impl ::core::fmt::Debug for NNodeTransformInner { - #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_struct_field3_finish( - f, - "NNodeTransformInner", - "translation", - &self.translation, - "rotation", - &self.rotation, - "scale", - &&self.scale, - ) - } - } - pub struct NNodeInner { - pub name: String, - pub parent: Option<i32>, - pub children: Vec<i32>, - pub transform: NNodeTransform, - } - #[automatically_derived] - impl ::core::clone::Clone for NNodeInner { - #[inline] - fn clone(&self) -> NNodeInner { - NNodeInner { - name: ::core::clone::Clone::clone(&self.name), - parent: ::core::clone::Clone::clone(&self.parent), - children: ::core::clone::Clone::clone(&self.children), - transform: ::core::clone::Clone::clone(&self.transform), - } - } - } - #[automatically_derived] - impl ::core::fmt::Debug for NNodeInner { - #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_struct_field4_finish( - f, - "NNodeInner", - "name", - &self.name, - "parent", - &self.parent, - "children", - &self.children, - "transform", - &&self.transform, - ) - } - } - pub struct NSkinInner { - pub name: String, - pub joints: Vec<i32>, - pub inverse_bind_matrices: Vec<Vec<f64>>, - pub skeleton_root: Option<i32>, - } - #[automatically_derived] - impl ::core::clone::Clone for NSkinInner { - #[inline] - fn clone(&self) -> NSkinInner { - NSkinInner { - name: ::core::clone::Clone::clone(&self.name), - joints: ::core::clone::Clone::clone(&self.joints), - inverse_bind_matrices: ::core::clone::Clone::clone( - &self.inverse_bind_matrices, - ), - skeleton_root: ::core::clone::Clone::clone(&self.skeleton_root), - } - } - } - #[automatically_derived] - impl ::core::fmt::Debug for NSkinInner { - #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_struct_field4_finish( - f, - "NSkinInner", - "name", - &self.name, - "joints", - &self.joints, - "inverse_bind_matrices", - &self.inverse_bind_matrices, - "skeleton_root", - &&self.skeleton_root, - ) - } - } - pub struct NAnimationInner { - pub name: String, - pub channels: Vec<Box<NAnimationChannel>>, - pub duration: f32, - } - #[automatically_derived] - impl ::core::clone::Clone for NAnimationInner { - #[inline] - fn clone(&self) -> NAnimationInner { - NAnimationInner { - name: ::core::clone::Clone::clone(&self.name), - channels: ::core::clone::Clone::clone(&self.channels), - duration: ::core::clone::Clone::clone(&self.duration), - } - } - } - #[automatically_derived] - impl ::core::fmt::Debug for NAnimationInner { - #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_struct_field3_finish( - f, - "NAnimationInner", - "name", - &self.name, - "channels", - &self.channels, - "duration", - &&self.duration, - ) - } - } - pub struct NAnimationChannelInner { - pub target_node: i32, - pub times: Vec<f64>, - pub values: Box<NChannelValues>, - pub interpolation: Box<NAnimationInterpolation>, - } - #[automatically_derived] - impl ::core::clone::Clone for NAnimationChannelInner { - #[inline] - fn clone(&self) -> NAnimationChannelInner { - NAnimationChannelInner { - target_node: ::core::clone::Clone::clone(&self.target_node), - times: ::core::clone::Clone::clone(&self.times), - values: ::core::clone::Clone::clone(&self.values), - interpolation: ::core::clone::Clone::clone(&self.interpolation), - } - } - } - #[automatically_derived] - impl ::core::fmt::Debug for NAnimationChannelInner { - #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_struct_field4_finish( - f, - "NAnimationChannelInner", - "target_node", - &self.target_node, - "times", - &self.times, - "values", - &self.values, - "interpolation", - &&self.interpolation, - ) - } - } - #[allow(non_camel_case_types)] - pub enum NAnimationInterpolationInner { - Linear, - Step, - CubicSpline, - } - #[automatically_derived] - #[allow(non_camel_case_types)] - impl ::core::clone::Clone for NAnimationInterpolationInner { - #[inline] - fn clone(&self) -> NAnimationInterpolationInner { - match self { - NAnimationInterpolationInner::Linear => { - NAnimationInterpolationInner::Linear - } - NAnimationInterpolationInner::Step => { - NAnimationInterpolationInner::Step - } - NAnimationInterpolationInner::CubicSpline => { - NAnimationInterpolationInner::CubicSpline - } - } - } - } - #[automatically_derived] - #[allow(non_camel_case_types)] - impl ::core::fmt::Debug for NAnimationInterpolationInner { - #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::write_str( - f, - match self { - NAnimationInterpolationInner::Linear => "Linear", - NAnimationInterpolationInner::Step => "Step", - NAnimationInterpolationInner::CubicSpline => "CubicSpline", - }, - ) - } - } - #[allow(non_camel_case_types)] - pub enum NChannelValuesInner { - Translations { values: Vec<crate::types::NVector3> }, - Rotations { values: Vec<crate::types::NQuaternion> }, - Scales { values: Vec<crate::types::NVector3> }, - } - #[automatically_derived] - #[allow(non_camel_case_types)] - impl ::core::clone::Clone for NChannelValuesInner { - #[inline] - fn clone(&self) -> NChannelValuesInner { - match self { - NChannelValuesInner::Translations { values: __self_0 } => { - NChannelValuesInner::Translations { - values: ::core::clone::Clone::clone(__self_0), - } - } - NChannelValuesInner::Rotations { values: __self_0 } => { - NChannelValuesInner::Rotations { - values: ::core::clone::Clone::clone(__self_0), - } - } - NChannelValuesInner::Scales { values: __self_0 } => { - NChannelValuesInner::Scales { - values: ::core::clone::Clone::clone(__self_0), - } - } - } - } - } - #[automatically_derived] - #[allow(non_camel_case_types)] - impl ::core::fmt::Debug for NChannelValuesInner { - #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - match self { - NChannelValuesInner::Translations { values: __self_0 } => { - ::core::fmt::Formatter::debug_struct_field1_finish( - f, - "Translations", - "values", - &__self_0, - ) - } - NChannelValuesInner::Rotations { values: __self_0 } => { - ::core::fmt::Formatter::debug_struct_field1_finish( - f, - "Rotations", - "values", - &__self_0, - ) - } - NChannelValuesInner::Scales { values: __self_0 } => { - ::core::fmt::Formatter::debug_struct_field1_finish( - f, - "Scales", - "values", - &__self_0, - ) - } - } - } - } - } - pub mod ffi { - use super::ffi_impl::{ - NModelVertexInner, NMeshInner, NMaterialInner, NNodeTransformInner, - NNodeInner, NSkinInner, NAnimationInner, NAnimationChannelInner, - NAnimationInterpolationInner, NChannelValuesInner, - }; - use crate::scripting::native::DropbearNativeError; - use crate::pointer_convert; - use dropbear_engine::asset::Handle; - use crate::asset::model::{ - map_animation, map_material, map_mesh, map_node, map_skin, - }; - use crate::ptr::AssetRegistryUnwrapped; - pub struct NModelVertex(pub NModelVertexInner); - #[automatically_derived] - impl ::core::clone::Clone for NModelVertex { - #[inline] - fn clone(&self) -> NModelVertex { - NModelVertex(::core::clone::Clone::clone(&self.0)) - } - } - #[automatically_derived] - impl ::core::fmt::Debug for NModelVertex { - #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_tuple_field1_finish( - f, - "NModelVertex", - &&self.0, - ) - } - } - impl NModelVertex { - pub fn new( - position: crate::types::NVector3, - normal: crate::types::NVector3, - tangent: crate::types::NVector4, - tex_coords0: crate::types::NVector2, - tex_coords1: crate::types::NVector2, - colour0: crate::types::NVector4, - joints0: &[i32], - weights0: crate::types::NVector4, - ) -> Box<Self> { - Box::new( - Self(NModelVertexInner { - position, - normal, - tangent, - tex_coords0, - tex_coords1, - colour0, - joints0: joints0.to_vec(), - weights0, - }), - ) - } - pub fn get_position(&self) -> crate::types::NVector3 { - self.0.position.clone() - } - pub fn set_position(&mut self, value: crate::types::NVector3) { - self.0.position = value; - } - pub fn get_normal(&self) -> crate::types::NVector3 { - self.0.normal.clone() - } - pub fn set_normal(&mut self, value: crate::types::NVector3) { - self.0.normal = value; - } - pub fn get_tangent(&self) -> crate::types::NVector4 { - self.0.tangent.clone() - } - pub fn set_tangent(&mut self, value: crate::types::NVector4) { - self.0.tangent = value; - } - pub fn get_tex_coords0(&self) -> crate::types::NVector2 { - self.0.tex_coords0.clone() - } - pub fn set_tex_coords0(&mut self, value: crate::types::NVector2) { - self.0.tex_coords0 = value; - } - pub fn get_tex_coords1(&self) -> crate::types::NVector2 { - self.0.tex_coords1.clone() - } - pub fn set_tex_coords1(&mut self, value: crate::types::NVector2) { - self.0.tex_coords1 = value; - } - pub fn get_colour0(&self) -> crate::types::NVector4 { - self.0.colour0.clone() - } - pub fn set_colour0(&mut self, value: crate::types::NVector4) { - self.0.colour0 = value; - } - pub fn joints0_len(&self) -> usize { - self.0.joints0.len() - } - pub fn joints0_get(&self, index: usize) -> Option<i32> { - self.0.joints0.get(index).cloned() - } - pub fn joints0_push(&mut self, value: i32) { - self.0.joints0.push(value); - } - pub fn get_weights0(&self) -> crate::types::NVector4 { - self.0.weights0.clone() - } - pub fn set_weights0(&mut self, value: crate::types::NVector4) { - self.0.weights0 = value; - } - } - pub struct NMesh(pub NMeshInner); - #[automatically_derived] - impl ::core::clone::Clone for NMesh { - #[inline] - fn clone(&self) -> NMesh { - NMesh(::core::clone::Clone::clone(&self.0)) - } - } - #[automatically_derived] - impl ::core::fmt::Debug for NMesh { - #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_tuple_field1_finish(f, "NMesh", &&self.0) - } - } - impl NMesh { - pub fn new( - name: String, - num_elements: i32, - material_index: i32, - vertices: &[NModelVertex], - ) -> Box<Self> { - Box::new( - Self(NMeshInner { - name, - num_elements, - material_index, - vertices: vertices.to_vec(), - }), - ) - } - pub fn get_name(&self) -> String { - self.0.name.clone() - } - pub fn set_name(&mut self, value: String) { - self.0.name = value; - } - pub fn get_num_elements(&self) -> i32 { - self.0.num_elements.clone() - } - pub fn set_num_elements(&mut self, value: i32) { - self.0.num_elements = value; - } - pub fn get_material_index(&self) -> i32 { - self.0.material_index.clone() - } - pub fn set_material_index(&mut self, value: i32) { - self.0.material_index = value; - } - pub fn vertices_len(&self) -> usize { - self.0.vertices.len() - } - pub fn vertices_get(&self, index: usize) -> Option<NModelVertex> { - self.0.vertices.get(index).cloned() - } - pub fn vertices_push(&mut self, value: NModelVertex) { - self.0.vertices.push(value); - } - } - pub struct NMaterial(pub NMaterialInner); - #[automatically_derived] - impl ::core::clone::Clone for NMaterial { - #[inline] - fn clone(&self) -> NMaterial { - NMaterial(::core::clone::Clone::clone(&self.0)) - } - } - #[automatically_derived] - impl ::core::fmt::Debug for NMaterial { - #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_tuple_field1_finish( - f, - "NMaterial", - &&self.0, - ) - } - } - impl NMaterial { - pub fn new( - name: String, - diffuse_texture: u64, - normal_texture: u64, - tint: crate::types::NVector4, - emissive_factor: crate::types::NVector3, - metallic_factor: f32, - roughness_factor: f32, - alpha_cutoff: Option<f32>, - double_sided: bool, - occlusion_strength: f32, - normal_scale: f32, - uv_tiling: crate::types::NVector2, - emissive_texture: Option<u64>, - metallic_roughness_texture: Option<u64>, - occlusion_texture: Option<u64>, - ) -> Box<Self> { - Box::new( - Self(NMaterialInner { - name, - diffuse_texture, - normal_texture, - tint, - emissive_factor, - metallic_factor, - roughness_factor, - alpha_cutoff, - double_sided, - occlusion_strength, - normal_scale, - uv_tiling, - emissive_texture, - metallic_roughness_texture, - occlusion_texture, - }), - ) - } - pub fn get_name(&self) -> String { - self.0.name.clone() - } - pub fn set_name(&mut self, value: String) { - self.0.name = value; - } - pub fn get_diffuse_texture(&self) -> u64 { - self.0.diffuse_texture.clone() - } - pub fn set_diffuse_texture(&mut self, value: u64) { - self.0.diffuse_texture = value; - } - pub fn get_normal_texture(&self) -> u64 { - self.0.normal_texture.clone() - } - pub fn set_normal_texture(&mut self, value: u64) { - self.0.normal_texture = value; - } - pub fn get_tint(&self) -> crate::types::NVector4 { - self.0.tint.clone() - } - pub fn set_tint(&mut self, value: crate::types::NVector4) { - self.0.tint = value; - } - pub fn get_emissive_factor(&self) -> crate::types::NVector3 { - self.0.emissive_factor.clone() - } - pub fn set_emissive_factor(&mut self, value: crate::types::NVector3) { - self.0.emissive_factor = value; - } - pub fn get_metallic_factor(&self) -> f32 { - self.0.metallic_factor.clone() - } - pub fn set_metallic_factor(&mut self, value: f32) { - self.0.metallic_factor = value; - } - pub fn get_roughness_factor(&self) -> f32 { - self.0.roughness_factor.clone() - } - pub fn set_roughness_factor(&mut self, value: f32) { - self.0.roughness_factor = value; - } - pub fn get_alpha_cutoff(&self) -> Option<f32> { - self.0.alpha_cutoff.clone() - } - pub fn set_alpha_cutoff(&mut self, value: Option<f32>) { - self.0.alpha_cutoff = value; - } - pub fn get_double_sided(&self) -> bool { - self.0.double_sided.clone() - } - pub fn set_double_sided(&mut self, value: bool) { - self.0.double_sided = value; - } - pub fn get_occlusion_strength(&self) -> f32 { - self.0.occlusion_strength.clone() - } - pub fn set_occlusion_strength(&mut self, value: f32) { - self.0.occlusion_strength = value; - } - pub fn get_normal_scale(&self) -> f32 { - self.0.normal_scale.clone() - } - pub fn set_normal_scale(&mut self, value: f32) { - self.0.normal_scale = value; - } - pub fn get_uv_tiling(&self) -> crate::types::NVector2 { - self.0.uv_tiling.clone() - } - pub fn set_uv_tiling(&mut self, value: crate::types::NVector2) { - self.0.uv_tiling = value; - } - pub fn get_emissive_texture(&self) -> Option<u64> { - self.0.emissive_texture.clone() - } - pub fn set_emissive_texture(&mut self, value: Option<u64>) { - self.0.emissive_texture = value; - } - pub fn get_metallic_roughness_texture(&self) -> Option<u64> { - self.0.metallic_roughness_texture.clone() - } - pub fn set_metallic_roughness_texture(&mut self, value: Option<u64>) { - self.0.metallic_roughness_texture = value; - } - pub fn get_occlusion_texture(&self) -> Option<u64> { - self.0.occlusion_texture.clone() - } - pub fn set_occlusion_texture(&mut self, value: Option<u64>) { - self.0.occlusion_texture = value; - } - } - pub struct NNodeTransform(pub NNodeTransformInner); - #[automatically_derived] - impl ::core::clone::Clone for NNodeTransform { - #[inline] - fn clone(&self) -> NNodeTransform { - NNodeTransform(::core::clone::Clone::clone(&self.0)) - } - } - #[automatically_derived] - impl ::core::fmt::Debug for NNodeTransform { - #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_tuple_field1_finish( - f, - "NNodeTransform", - &&self.0, - ) - } - } - impl NNodeTransform { - pub fn new( - translation: crate::types::NVector3, - rotation: crate::types::NQuaternion, - scale: crate::types::NVector3, - ) -> Box<Self> { - Box::new( - Self(NNodeTransformInner { - translation, - rotation, - scale, - }), - ) - } - pub fn get_translation(&self) -> crate::types::NVector3 { - self.0.translation.clone() - } - pub fn set_translation(&mut self, value: crate::types::NVector3) { - self.0.translation = value; - } - pub fn get_rotation(&self) -> crate::types::NQuaternion { - self.0.rotation.clone() - } - pub fn set_rotation(&mut self, value: crate::types::NQuaternion) { - self.0.rotation = value; - } - pub fn get_scale(&self) -> crate::types::NVector3 { - self.0.scale.clone() - } - pub fn set_scale(&mut self, value: crate::types::NVector3) { - self.0.scale = value; - } - } - pub struct NNode(pub NNodeInner); - #[automatically_derived] - impl ::core::clone::Clone for NNode { - #[inline] - fn clone(&self) -> NNode { - NNode(::core::clone::Clone::clone(&self.0)) - } - } - #[automatically_derived] - impl ::core::fmt::Debug for NNode { - #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_tuple_field1_finish(f, "NNode", &&self.0) - } - } - impl NNode { - pub fn new( - name: String, - parent: Option<i32>, - children: &[i32], - transform: NNodeTransform, - ) -> Box<Self> { - Box::new( - Self(NNodeInner { - name, - parent, - children: children.to_vec(), - transform, - }), - ) - } - pub fn get_name(&self) -> String { - self.0.name.clone() - } - pub fn set_name(&mut self, value: String) { - self.0.name = value; - } - pub fn get_parent(&self) -> Option<i32> { - self.0.parent.clone() - } - pub fn set_parent(&mut self, value: Option<i32>) { - self.0.parent = value; - } - pub fn children_len(&self) -> usize { - self.0.children.len() - } - pub fn children_get(&self, index: usize) -> Option<i32> { - self.0.children.get(index).cloned() - } - pub fn children_push(&mut self, value: i32) { - self.0.children.push(value); - } - pub fn get_transform(&self) -> NNodeTransform { - self.0.transform.clone() - } - pub fn set_transform(&mut self, value: NNodeTransform) { - self.0.transform = value; - } - } - pub struct NSkin(pub NSkinInner); - #[automatically_derived] - impl ::core::clone::Clone for NSkin { - #[inline] - fn clone(&self) -> NSkin { - NSkin(::core::clone::Clone::clone(&self.0)) - } - } - #[automatically_derived] - impl ::core::fmt::Debug for NSkin { - #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_tuple_field1_finish(f, "NSkin", &&self.0) - } - } - impl NSkin { - pub fn get_name(&self) -> String { - self.0.name.clone() - } - pub fn set_name(&mut self, value: String) { - self.0.name = value; - } - pub fn joints_len(&self) -> usize { - self.0.joints.len() - } - pub fn joints_get(&self, index: usize) -> Option<i32> { - self.0.joints.get(index).cloned() - } - pub fn joints_push(&mut self, value: i32) { - self.0.joints.push(value); - } - pub fn get_skeleton_root(&self) -> Option<i32> { - self.0.skeleton_root.clone() - } - pub fn set_skeleton_root(&mut self, value: Option<i32>) { - self.0.skeleton_root = value; - } - } - pub struct NAnimation(pub NAnimationInner); - #[automatically_derived] - impl ::core::clone::Clone for NAnimation { - #[inline] - fn clone(&self) -> NAnimation { - NAnimation(::core::clone::Clone::clone(&self.0)) - } - } - #[automatically_derived] - impl ::core::fmt::Debug for NAnimation { - #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_tuple_field1_finish( - f, - "NAnimation", - &&self.0, - ) - } - } - impl NAnimation { - pub fn new( - name: String, - channels: &[Box<NAnimationChannel>], - duration: f32, - ) -> Box<Self> { - Box::new( - Self(NAnimationInner { - name, - channels: channels.to_vec(), - duration, - }), - ) - } - pub fn get_name(&self) -> String { - self.0.name.clone() - } - pub fn set_name(&mut self, value: String) { - self.0.name = value; - } - pub fn channels_len(&self) -> usize { - self.0.channels.len() - } - pub fn channels_get(&self, index: usize) -> Option<Box<NAnimationChannel>> { - self.0.channels.get(index).cloned() - } - pub fn channels_push(&mut self, value: Box<NAnimationChannel>) { - self.0.channels.push(value); - } - pub fn get_duration(&self) -> f32 { - self.0.duration.clone() - } - pub fn set_duration(&mut self, value: f32) { - self.0.duration = value; - } - } - pub struct NAnimationChannel(pub NAnimationChannelInner); - #[automatically_derived] - impl ::core::clone::Clone for NAnimationChannel { - #[inline] - fn clone(&self) -> NAnimationChannel { - NAnimationChannel(::core::clone::Clone::clone(&self.0)) - } - } - #[automatically_derived] - impl ::core::fmt::Debug for NAnimationChannel { - #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_tuple_field1_finish( - f, - "NAnimationChannel", - &&self.0, - ) - } - } - impl NAnimationChannel { - pub fn new( - target_node: i32, - times: &[f64], - values: Box<NChannelValues>, - interpolation: Box<NAnimationInterpolation>, - ) -> Box<Self> { - Box::new( - Self(NAnimationChannelInner { - target_node, - times: times.to_vec(), - values, - interpolation, - }), - ) - } - pub fn get_target_node(&self) -> i32 { - self.0.target_node.clone() - } - pub fn set_target_node(&mut self, value: i32) { - self.0.target_node = value; - } - pub fn times_len(&self) -> usize { - self.0.times.len() - } - pub fn times_get(&self, index: usize) -> Option<f64> { - self.0.times.get(index).cloned() - } - pub fn times_push(&mut self, value: f64) { - self.0.times.push(value); - } - pub fn get_values(&self) -> Box<NChannelValues> { - self.0.values.clone() - } - pub fn set_values(&mut self, value: Box<NChannelValues>) { - self.0.values = value; - } - pub fn get_interpolation(&self) -> Box<NAnimationInterpolation> { - self.0.interpolation.clone() - } - pub fn set_interpolation(&mut self, value: Box<NAnimationInterpolation>) { - self.0.interpolation = value; - } - } - pub struct NAnimationInterpolation(NAnimationInterpolationInner); - #[automatically_derived] - impl ::core::clone::Clone for NAnimationInterpolation { - #[inline] - fn clone(&self) -> NAnimationInterpolation { - NAnimationInterpolation(::core::clone::Clone::clone(&self.0)) - } - } - #[automatically_derived] - impl ::core::fmt::Debug for NAnimationInterpolation { - #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_tuple_field1_finish( - f, - "NAnimationInterpolation", - &&self.0, - ) - } - } - impl NAnimationInterpolation { - pub fn new_linear() -> Box<NAnimationInterpolation> { - Box::new(NAnimationInterpolation(NAnimationInterpolationInner::Linear)) - } - pub fn new_step() -> Box<NAnimationInterpolation> { - Box::new(NAnimationInterpolation(NAnimationInterpolationInner::Step)) - } - pub fn new_cubicspline() -> Box<NAnimationInterpolation> { - Box::new( - NAnimationInterpolation(NAnimationInterpolationInner::CubicSpline), - ) - } - } - pub struct NChannelValues(NChannelValuesInner); - #[automatically_derived] - impl ::core::clone::Clone for NChannelValues { - #[inline] - fn clone(&self) -> NChannelValues { - NChannelValues(::core::clone::Clone::clone(&self.0)) - } - } - #[automatically_derived] - impl ::core::fmt::Debug for NChannelValues { - #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_tuple_field1_finish( - f, - "NChannelValues", - &&self.0, - ) - } - } - impl NChannelValues { - pub fn new_translations( - values: &[crate::types::NVector3], - ) -> Box<NChannelValues> { - Box::new( - NChannelValues(NChannelValuesInner::Translations { - values: values.to_vec(), - }), - ) - } - pub fn new_rotations( - values: &[crate::types::NQuaternion], - ) -> Box<NChannelValues> { - Box::new( - NChannelValues(NChannelValuesInner::Rotations { - values: values.to_vec(), - }), - ) - } - pub fn new_scales(values: &[crate::types::NVector3]) -> Box<NChannelValues> { - Box::new( - NChannelValues(NChannelValuesInner::Scales { - values: values.to_vec(), - }), - ) - } - pub fn translations_values_len(&self) -> usize { - if let NChannelValuesInner::Translations { values, .. } = &self.0 { - values.len() - } else { - 0 - } - } - pub fn translations_values_get( - &self, - index: usize, - ) -> Option<crate::types::NVector3> { - if let NChannelValuesInner::Translations { values, .. } = &self.0 { - values.get(index).cloned() - } else { - None - } - } - pub fn translations_values_push(&mut self, value: crate::types::NVector3) { - if let NChannelValuesInner::Translations { values, .. } = &mut self.0 { - values.push(value); - } - } - pub fn rotations_values_len(&self) -> usize { - if let NChannelValuesInner::Rotations { values, .. } = &self.0 { - values.len() - } else { - 0 - } - } - pub fn rotations_values_get( - &self, - index: usize, - ) -> Option<crate::types::NQuaternion> { - if let NChannelValuesInner::Rotations { values, .. } = &self.0 { - values.get(index).cloned() - } else { - None - } - } - pub fn rotations_values_push(&mut self, value: crate::types::NQuaternion) { - if let NChannelValuesInner::Rotations { values, .. } = &mut self.0 { - values.push(value); - } - } - pub fn scales_values_len(&self) -> usize { - if let NChannelValuesInner::Scales { values, .. } = &self.0 { - values.len() - } else { - 0 - } - } - pub fn scales_values_get( - &self, - index: usize, - ) -> Option<crate::types::NVector3> { - if let NChannelValuesInner::Scales { values, .. } = &self.0 { - values.get(index).cloned() - } else { - None - } - } - pub fn scales_values_push(&mut self, value: crate::types::NVector3) { - if let NChannelValuesInner::Scales { values, .. } = &mut self.0 { - values.push(value); - } - } - } - pub fn dropbear_asset_model_get_label( - asset_registry: u64, - model_handle: u64, - ) -> Result<String, crate::scripting::native::DropbearNativeError> { - let asset = { - let ptr = asset_registry as *const AssetRegistryUnwrapped; - if ptr.is_null() { - return Err( - crate::scripting::native::DropbearNativeError::NullPointer, - ); - } - let addr = ptr as usize; - let align = std::mem::align_of::<AssetRegistryUnwrapped>(); - if addr % align != 0 { - return Err( - crate::scripting::native::DropbearNativeError::InvalidArgument, - ); - } - unsafe { &*ptr } - }; - let label = asset - .read() - .get_label_from_model_handle(Handle::new(model_handle)) - .ok_or_else(|| DropbearNativeError::InvalidHandle)?; - Ok(label) - } - pub struct NMeshList(pub Vec<NMesh>); - impl NMeshList { - pub fn len(&self) -> usize { - self.0.len() - } - pub fn get(&self, i: usize) -> Option<&NMesh> { - self.0.get(i) - } - } - pub fn dropbear_asset_model_get_meshes( - asset_registry: u64, - model_handle: u64, - ) -> Result<Box<NMeshList>, crate::scripting::native::DropbearNativeError> { - let logic = || -> Result<Vec<NMesh>, _> { - { - let asset = { - let ptr = asset_registry as *const AssetRegistryUnwrapped; - if ptr.is_null() { - return Err( - crate::scripting::native::DropbearNativeError::NullPointer, - ); - } - let addr = ptr as usize; - let align = std::mem::align_of::<AssetRegistryUnwrapped>(); - if addr % align != 0 { - return Err( - crate::scripting::native::DropbearNativeError::InvalidArgument, - ); - } - unsafe { &*ptr } - }; - let reader = asset.read(); - let model = reader - .get_model(Handle::new(model_handle)) - .ok_or(DropbearNativeError::InvalidHandle)?; - Ok(model.meshes.iter().map(map_mesh).collect()) - } - }; - logic().map(|v| Box::new(NMeshList(v))) - } - pub struct NMaterialList(pub Vec<NMaterial>); - impl NMaterialList { - pub fn len(&self) -> usize { - self.0.len() - } - pub fn get(&self, i: usize) -> Option<&NMaterial> { - self.0.get(i) - } - } - pub fn dropbear_asset_model_get_materials( - asset_registry: u64, - model_handle: u64, - ) -> Result<Box<NMaterialList>, crate::scripting::native::DropbearNativeError> { - let logic = || -> Result<Vec<NMaterial>, _> { - { - let asset = { - let ptr = asset_registry as *const AssetRegistryUnwrapped; - if ptr.is_null() { - return Err( - crate::scripting::native::DropbearNativeError::NullPointer, - ); - } - let addr = ptr as usize; - let align = std::mem::align_of::<AssetRegistryUnwrapped>(); - if addr % align != 0 { - return Err( - crate::scripting::native::DropbearNativeError::InvalidArgument, - ); - } - unsafe { &*ptr } - }; - let reader = asset.read(); - let model = reader - .get_model(Handle::new(model_handle)) - .ok_or(DropbearNativeError::InvalidHandle)?; - Ok( - model - .materials - .iter() - .map(|mat| map_material(&reader, mat)) - .collect(), - ) - } - }; - logic().map(|v| Box::new(NMaterialList(v))) - } - pub struct NSkinList(pub Vec<NSkin>); - impl NSkinList { - pub fn len(&self) -> usize { - self.0.len() - } - pub fn get(&self, i: usize) -> Option<&NSkin> { - self.0.get(i) - } - } - pub fn dropbear_asset_model_get_skins( - asset_registry: u64, - model_handle: u64, - ) -> Result<Box<NSkinList>, crate::scripting::native::DropbearNativeError> { - let logic = || -> Result<Vec<NSkin>, _> { - { - let asset = { - let ptr = asset_registry as *const AssetRegistryUnwrapped; - if ptr.is_null() { - return Err( - crate::scripting::native::DropbearNativeError::NullPointer, - ); - } - let addr = ptr as usize; - let align = std::mem::align_of::<AssetRegistryUnwrapped>(); - if addr % align != 0 { - return Err( - crate::scripting::native::DropbearNativeError::InvalidArgument, - ); - } - unsafe { &*ptr } - }; - let reader = asset.read(); - let model = reader - .get_model(Handle::new(model_handle)) - .ok_or(DropbearNativeError::InvalidHandle)?; - Ok(model.skins.iter().map(map_skin).collect()) - } - }; - logic().map(|v| Box::new(NSkinList(v))) - } - pub struct NAnimationList(pub Vec<Box<NAnimation>>); - impl NAnimationList { - pub fn len(&self) -> usize { - self.0.len() - } - pub fn get(&self, i: usize) -> Option<&Box<NAnimation>> { - self.0.get(i) - } - } - pub fn dropbear_asset_model_get_animations( - asset_registry: u64, - model_handle: u64, - ) -> Result<Box<NAnimationList>, crate::scripting::native::DropbearNativeError> { - let logic = || -> Result<Vec<Box<NAnimation>>, _> { - { - let asset = { - let ptr = asset_registry as *const AssetRegistryUnwrapped; - if ptr.is_null() { - return Err( - crate::scripting::native::DropbearNativeError::NullPointer, - ); - } - let addr = ptr as usize; - let align = std::mem::align_of::<AssetRegistryUnwrapped>(); - if addr % align != 0 { - return Err( - crate::scripting::native::DropbearNativeError::InvalidArgument, - ); - } - unsafe { &*ptr } - }; - let reader = asset.read(); - let model = reader - .get_model(Handle::new(model_handle)) - .ok_or(DropbearNativeError::InvalidHandle)?; - Ok(model.animations.iter().map(map_animation).collect()) - } - }; - logic().map(|v| Box::new(NAnimationList(v))) - } - pub struct NNodeList(pub Vec<NNode>); - impl NNodeList { - pub fn len(&self) -> usize { - self.0.len() - } - pub fn get(&self, i: usize) -> Option<&NNode> { - self.0.get(i) - } - } - pub fn dropbear_asset_model_get_nodes( - asset_registry: u64, - model_handle: u64, - ) -> Result<Box<NNodeList>, crate::scripting::native::DropbearNativeError> { - let logic = || -> Result<Vec<NNode>, _> { - { - let asset = { - let ptr = asset_registry as *const AssetRegistryUnwrapped; - if ptr.is_null() { - return Err( - crate::scripting::native::DropbearNativeError::NullPointer, - ); - } - let addr = ptr as usize; - let align = std::mem::align_of::<AssetRegistryUnwrapped>(); - if addr % align != 0 { - return Err( - crate::scripting::native::DropbearNativeError::InvalidArgument, - ); - } - unsafe { &*ptr } - }; - let reader = asset.read(); - let model = reader - .get_model(Handle::new(model_handle)) - .ok_or(DropbearNativeError::InvalidHandle)?; - Ok(model.nodes.iter().map(map_node).collect()) - } - }; - logic().map(|v| Box::new(NNodeList(v))) - } - use diplomat_runtime::*; - use core::ffi::c_void; - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimation_new( - name: String, - channels: &[Box<NAnimationChannel>], - duration: f32, - ) -> Box<NAnimation> { - NAnimation::new(name, channels, duration) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimation_get_name(this: &NAnimation) -> String { - this.get_name() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimation_set_name(this: &mut NAnimation, value: String) { - this.set_name(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimation_channels_len(this: &NAnimation) -> usize { - this.channels_len() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimation_channels_get( - this: &NAnimation, - index: usize, - ) -> Option<Box<NAnimationChannel>> { - this.channels_get(index) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimation_channels_push( - this: &mut NAnimation, - value: Box<NAnimationChannel>, - ) { - this.channels_push(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimation_get_duration(this: &NAnimation) -> f32 { - this.get_duration() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimation_set_duration(this: &mut NAnimation, value: f32) { - this.set_duration(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimation_destroy(this: Box<NAnimation>) {} - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimationChannel_new( - target_node: i32, - times: diplomat_runtime::DiplomatSlice<f64>, - values: Box<NChannelValues>, - interpolation: Box<NAnimationInterpolation>, - ) -> Box<NAnimationChannel> { - let times = times.into(); - NAnimationChannel::new(target_node, times, values, interpolation) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimationChannel_get_target_node( - this: &NAnimationChannel, - ) -> i32 { - this.get_target_node() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimationChannel_set_target_node( - this: &mut NAnimationChannel, - value: i32, - ) { - this.set_target_node(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimationChannel_times_len(this: &NAnimationChannel) -> usize { - this.times_len() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimationChannel_times_get( - this: &NAnimationChannel, - index: usize, - ) -> diplomat_runtime::DiplomatResult<f64, ()> { - this.times_get(index).ok_or(()).into() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimationChannel_times_push( - this: &mut NAnimationChannel, - value: f64, - ) { - this.times_push(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimationChannel_get_values( - this: &NAnimationChannel, - ) -> Box<NChannelValues> { - this.get_values() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimationChannel_set_values( - this: &mut NAnimationChannel, - value: Box<NChannelValues>, - ) { - this.set_values(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimationChannel_get_interpolation( - this: &NAnimationChannel, - ) -> Box<NAnimationInterpolation> { - this.get_interpolation() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimationChannel_set_interpolation( - this: &mut NAnimationChannel, - value: Box<NAnimationInterpolation>, - ) { - this.set_interpolation(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimationChannel_destroy(this: Box<NAnimationChannel>) {} - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimationInterpolation_new_linear() -> Box< - NAnimationInterpolation, - > { - NAnimationInterpolation::new_linear() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimationInterpolation_new_step() -> Box< - NAnimationInterpolation, - > { - NAnimationInterpolation::new_step() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimationInterpolation_new_cubicspline() -> Box< - NAnimationInterpolation, - > { - NAnimationInterpolation::new_cubicspline() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimationInterpolation_destroy( - this: Box<NAnimationInterpolation>, - ) {} - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimationList_len(this: &NAnimationList) -> usize { - this.len() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimationList_get( - this: &NAnimationList, - i: usize, - ) -> Option<&Box<NAnimation>> { - this.get(i) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NAnimationList_destroy(this: Box<NAnimationList>) {} - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NChannelValues_new_translations( - values: &[crate::types::NVector3], - ) -> Box<NChannelValues> { - NChannelValues::new_translations(values) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NChannelValues_new_rotations( - values: &[crate::types::NQuaternion], - ) -> Box<NChannelValues> { - NChannelValues::new_rotations(values) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NChannelValues_new_scales( - values: &[crate::types::NVector3], - ) -> Box<NChannelValues> { - NChannelValues::new_scales(values) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NChannelValues_translations_values_len( - this: &NChannelValues, - ) -> usize { - this.translations_values_len() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NChannelValues_translations_values_get( - this: &NChannelValues, - index: usize, - ) -> diplomat_runtime::DiplomatResult<crate::types::NVector3, ()> { - this.translations_values_get(index).ok_or(()).into() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NChannelValues_translations_values_push( - this: &mut NChannelValues, - value: crate::types::NVector3, - ) { - this.translations_values_push(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NChannelValues_rotations_values_len( - this: &NChannelValues, - ) -> usize { - this.rotations_values_len() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NChannelValues_rotations_values_get( - this: &NChannelValues, - index: usize, - ) -> diplomat_runtime::DiplomatResult<crate::types::NQuaternion, ()> { - this.rotations_values_get(index).ok_or(()).into() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NChannelValues_rotations_values_push( - this: &mut NChannelValues, - value: crate::types::NQuaternion, - ) { - this.rotations_values_push(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NChannelValues_scales_values_len(this: &NChannelValues) -> usize { - this.scales_values_len() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NChannelValues_scales_values_get( - this: &NChannelValues, - index: usize, - ) -> diplomat_runtime::DiplomatResult<crate::types::NVector3, ()> { - this.scales_values_get(index).ok_or(()).into() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NChannelValues_scales_values_push( - this: &mut NChannelValues, - value: crate::types::NVector3, - ) { - this.scales_values_push(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NChannelValues_destroy(this: Box<NChannelValues>) {} - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_new( - name: String, - diffuse_texture: u64, - normal_texture: u64, - tint: crate::types::NVector4, - emissive_factor: crate::types::NVector3, - metallic_factor: f32, - roughness_factor: f32, - alpha_cutoff: diplomat_runtime::DiplomatOption<f32>, - double_sided: bool, - occlusion_strength: f32, - normal_scale: f32, - uv_tiling: crate::types::NVector2, - emissive_texture: diplomat_runtime::DiplomatOption<u64>, - metallic_roughness_texture: diplomat_runtime::DiplomatOption<u64>, - occlusion_texture: diplomat_runtime::DiplomatOption<u64>, - ) -> Box<NMaterial> { - let alpha_cutoff: Option<f32> = alpha_cutoff.into(); - let emissive_texture: Option<u64> = emissive_texture.into(); - let metallic_roughness_texture: Option<u64> = metallic_roughness_texture - .into(); - let occlusion_texture: Option<u64> = occlusion_texture.into(); - NMaterial::new( - name, - diffuse_texture, - normal_texture, - tint, - emissive_factor, - metallic_factor, - roughness_factor, - alpha_cutoff, - double_sided, - occlusion_strength, - normal_scale, - uv_tiling, - emissive_texture, - metallic_roughness_texture, - occlusion_texture, - ) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_get_name(this: &NMaterial) -> String { - this.get_name() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_set_name(this: &mut NMaterial, value: String) { - this.set_name(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_get_diffuse_texture(this: &NMaterial) -> u64 { - this.get_diffuse_texture() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_set_diffuse_texture(this: &mut NMaterial, value: u64) { - this.set_diffuse_texture(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_get_normal_texture(this: &NMaterial) -> u64 { - this.get_normal_texture() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_set_normal_texture(this: &mut NMaterial, value: u64) { - this.set_normal_texture(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_get_tint(this: &NMaterial) -> crate::types::NVector4 { - this.get_tint() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_set_tint( - this: &mut NMaterial, - value: crate::types::NVector4, - ) { - this.set_tint(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_get_emissive_factor( - this: &NMaterial, - ) -> crate::types::NVector3 { - this.get_emissive_factor() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_set_emissive_factor( - this: &mut NMaterial, - value: crate::types::NVector3, - ) { - this.set_emissive_factor(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_get_metallic_factor(this: &NMaterial) -> f32 { - this.get_metallic_factor() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_set_metallic_factor(this: &mut NMaterial, value: f32) { - this.set_metallic_factor(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_get_roughness_factor(this: &NMaterial) -> f32 { - this.get_roughness_factor() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_set_roughness_factor(this: &mut NMaterial, value: f32) { - this.set_roughness_factor(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_get_alpha_cutoff( - this: &NMaterial, - ) -> diplomat_runtime::DiplomatResult<f32, ()> { - this.get_alpha_cutoff().ok_or(()).into() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_set_alpha_cutoff( - this: &mut NMaterial, - value: diplomat_runtime::DiplomatOption<f32>, - ) { - let value: Option<f32> = value.into(); - this.set_alpha_cutoff(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_get_double_sided(this: &NMaterial) -> bool { - this.get_double_sided() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_set_double_sided(this: &mut NMaterial, value: bool) { - this.set_double_sided(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_get_occlusion_strength(this: &NMaterial) -> f32 { - this.get_occlusion_strength() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_set_occlusion_strength( - this: &mut NMaterial, - value: f32, - ) { - this.set_occlusion_strength(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_get_normal_scale(this: &NMaterial) -> f32 { - this.get_normal_scale() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_set_normal_scale(this: &mut NMaterial, value: f32) { - this.set_normal_scale(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_get_uv_tiling( - this: &NMaterial, - ) -> crate::types::NVector2 { - this.get_uv_tiling() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_set_uv_tiling( - this: &mut NMaterial, - value: crate::types::NVector2, - ) { - this.set_uv_tiling(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_get_emissive_texture( - this: &NMaterial, - ) -> diplomat_runtime::DiplomatResult<u64, ()> { - this.get_emissive_texture().ok_or(()).into() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_set_emissive_texture( - this: &mut NMaterial, - value: diplomat_runtime::DiplomatOption<u64>, - ) { - let value: Option<u64> = value.into(); - this.set_emissive_texture(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_get_metallic_roughness_texture( - this: &NMaterial, - ) -> diplomat_runtime::DiplomatResult<u64, ()> { - this.get_metallic_roughness_texture().ok_or(()).into() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_set_metallic_roughness_texture( - this: &mut NMaterial, - value: diplomat_runtime::DiplomatOption<u64>, - ) { - let value: Option<u64> = value.into(); - this.set_metallic_roughness_texture(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_get_occlusion_texture( - this: &NMaterial, - ) -> diplomat_runtime::DiplomatResult<u64, ()> { - this.get_occlusion_texture().ok_or(()).into() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_set_occlusion_texture( - this: &mut NMaterial, - value: diplomat_runtime::DiplomatOption<u64>, - ) { - let value: Option<u64> = value.into(); - this.set_occlusion_texture(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterial_destroy(this: Box<NMaterial>) {} - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterialList_len(this: &NMaterialList) -> usize { - this.len() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterialList_get( - this: &NMaterialList, - i: usize, - ) -> Option<&NMaterial> { - this.get(i) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMaterialList_destroy(this: Box<NMaterialList>) {} - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMesh_new( - name: String, - num_elements: i32, - material_index: i32, - vertices: &[NModelVertex], - ) -> Box<NMesh> { - NMesh::new(name, num_elements, material_index, vertices) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMesh_get_name(this: &NMesh) -> String { - this.get_name() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMesh_set_name(this: &mut NMesh, value: String) { - this.set_name(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMesh_get_num_elements(this: &NMesh) -> i32 { - this.get_num_elements() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMesh_set_num_elements(this: &mut NMesh, value: i32) { - this.set_num_elements(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMesh_get_material_index(this: &NMesh) -> i32 { - this.get_material_index() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMesh_set_material_index(this: &mut NMesh, value: i32) { - this.set_material_index(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMesh_vertices_len(this: &NMesh) -> usize { - this.vertices_len() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMesh_vertices_get( - this: &NMesh, - index: usize, - ) -> diplomat_runtime::DiplomatResult<NModelVertex, ()> { - this.vertices_get(index).ok_or(()).into() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMesh_vertices_push(this: &mut NMesh, value: NModelVertex) { - this.vertices_push(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMesh_destroy(this: Box<NMesh>) {} - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMeshList_len(this: &NMeshList) -> usize { - this.len() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMeshList_get(this: &NMeshList, i: usize) -> Option<&NMesh> { - this.get(i) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NMeshList_destroy(this: Box<NMeshList>) {} - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NModelVertex_new( - position: crate::types::NVector3, - normal: crate::types::NVector3, - tangent: crate::types::NVector4, - tex_coords0: crate::types::NVector2, - tex_coords1: crate::types::NVector2, - colour0: crate::types::NVector4, - joints0: diplomat_runtime::DiplomatSlice<i32>, - weights0: crate::types::NVector4, - ) -> Box<NModelVertex> { - let joints0 = joints0.into(); - NModelVertex::new( - position, - normal, - tangent, - tex_coords0, - tex_coords1, - colour0, - joints0, - weights0, - ) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NModelVertex_get_position( - this: &NModelVertex, - ) -> crate::types::NVector3 { - this.get_position() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NModelVertex_set_position( - this: &mut NModelVertex, - value: crate::types::NVector3, - ) { - this.set_position(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NModelVertex_get_normal( - this: &NModelVertex, - ) -> crate::types::NVector3 { - this.get_normal() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NModelVertex_set_normal( - this: &mut NModelVertex, - value: crate::types::NVector3, - ) { - this.set_normal(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NModelVertex_get_tangent( - this: &NModelVertex, - ) -> crate::types::NVector4 { - this.get_tangent() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NModelVertex_set_tangent( - this: &mut NModelVertex, - value: crate::types::NVector4, - ) { - this.set_tangent(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NModelVertex_get_tex_coords0( - this: &NModelVertex, - ) -> crate::types::NVector2 { - this.get_tex_coords0() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NModelVertex_set_tex_coords0( - this: &mut NModelVertex, - value: crate::types::NVector2, - ) { - this.set_tex_coords0(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NModelVertex_get_tex_coords1( - this: &NModelVertex, - ) -> crate::types::NVector2 { - this.get_tex_coords1() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NModelVertex_set_tex_coords1( - this: &mut NModelVertex, - value: crate::types::NVector2, - ) { - this.set_tex_coords1(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NModelVertex_get_colour0( - this: &NModelVertex, - ) -> crate::types::NVector4 { - this.get_colour0() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NModelVertex_set_colour0( - this: &mut NModelVertex, - value: crate::types::NVector4, - ) { - this.set_colour0(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NModelVertex_joints0_len(this: &NModelVertex) -> usize { - this.joints0_len() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NModelVertex_joints0_get( - this: &NModelVertex, - index: usize, - ) -> diplomat_runtime::DiplomatResult<i32, ()> { - this.joints0_get(index).ok_or(()).into() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NModelVertex_joints0_push(this: &mut NModelVertex, value: i32) { - this.joints0_push(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NModelVertex_get_weights0( - this: &NModelVertex, - ) -> crate::types::NVector4 { - this.get_weights0() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NModelVertex_set_weights0( - this: &mut NModelVertex, - value: crate::types::NVector4, - ) { - this.set_weights0(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NModelVertex_destroy(this: Box<NModelVertex>) {} - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNode_new( - name: String, - parent: diplomat_runtime::DiplomatOption<i32>, - children: diplomat_runtime::DiplomatSlice<i32>, - transform: NNodeTransform, - ) -> Box<NNode> { - let parent: Option<i32> = parent.into(); - let children = children.into(); - NNode::new(name, parent, children, transform) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNode_get_name(this: &NNode) -> String { - this.get_name() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNode_set_name(this: &mut NNode, value: String) { - this.set_name(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNode_get_parent( - this: &NNode, - ) -> diplomat_runtime::DiplomatResult<i32, ()> { - this.get_parent().ok_or(()).into() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNode_set_parent( - this: &mut NNode, - value: diplomat_runtime::DiplomatOption<i32>, - ) { - let value: Option<i32> = value.into(); - this.set_parent(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNode_children_len(this: &NNode) -> usize { - this.children_len() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNode_children_get( - this: &NNode, - index: usize, - ) -> diplomat_runtime::DiplomatResult<i32, ()> { - this.children_get(index).ok_or(()).into() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNode_children_push(this: &mut NNode, value: i32) { - this.children_push(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNode_get_transform(this: &NNode) -> NNodeTransform { - this.get_transform() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNode_set_transform(this: &mut NNode, value: NNodeTransform) { - this.set_transform(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNode_destroy(this: Box<NNode>) {} - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNodeList_len(this: &NNodeList) -> usize { - this.len() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNodeList_get(this: &NNodeList, i: usize) -> Option<&NNode> { - this.get(i) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNodeList_destroy(this: Box<NNodeList>) {} - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNodeTransform_new( - translation: crate::types::NVector3, - rotation: crate::types::NQuaternion, - scale: crate::types::NVector3, - ) -> Box<NNodeTransform> { - NNodeTransform::new(translation, rotation, scale) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNodeTransform_get_translation( - this: &NNodeTransform, - ) -> crate::types::NVector3 { - this.get_translation() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNodeTransform_set_translation( - this: &mut NNodeTransform, - value: crate::types::NVector3, - ) { - this.set_translation(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNodeTransform_get_rotation( - this: &NNodeTransform, - ) -> crate::types::NQuaternion { - this.get_rotation() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNodeTransform_set_rotation( - this: &mut NNodeTransform, - value: crate::types::NQuaternion, - ) { - this.set_rotation(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNodeTransform_get_scale( - this: &NNodeTransform, - ) -> crate::types::NVector3 { - this.get_scale() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNodeTransform_set_scale( - this: &mut NNodeTransform, - value: crate::types::NVector3, - ) { - this.set_scale(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NNodeTransform_destroy(this: Box<NNodeTransform>) {} - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NSkin_get_name(this: &NSkin) -> String { - this.get_name() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NSkin_set_name(this: &mut NSkin, value: String) { - this.set_name(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NSkin_joints_len(this: &NSkin) -> usize { - this.joints_len() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NSkin_joints_get( - this: &NSkin, - index: usize, - ) -> diplomat_runtime::DiplomatResult<i32, ()> { - this.joints_get(index).ok_or(()).into() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NSkin_joints_push(this: &mut NSkin, value: i32) { - this.joints_push(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NSkin_get_skeleton_root( - this: &NSkin, - ) -> diplomat_runtime::DiplomatResult<i32, ()> { - this.get_skeleton_root().ok_or(()).into() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NSkin_set_skeleton_root( - this: &mut NSkin, - value: diplomat_runtime::DiplomatOption<i32>, - ) { - let value: Option<i32> = value.into(); - this.set_skeleton_root(value) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NSkin_destroy(this: Box<NSkin>) {} - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NSkinList_len(this: &NSkinList) -> usize { - this.len() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NSkinList_get(this: &NSkinList, i: usize) -> Option<&NSkin> { - this.get(i) - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn NSkinList_destroy(this: Box<NSkinList>) {} - #[no_mangle] - #[allow(deprecated)] - extern "C" fn diplomat_external_dropbear_asset_model_get_animations( - asset_registry: u64, - model_handle: u64, - ) -> diplomat_runtime::DiplomatResult< - Box<NAnimationList>, - crate::scripting::native::DropbearNativeError, - > { - dropbear_asset_model_get_animations(asset_registry, model_handle).into() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn diplomat_external_dropbear_asset_model_get_label( - asset_registry: u64, - model_handle: u64, - ) -> diplomat_runtime::DiplomatResult< - String, - crate::scripting::native::DropbearNativeError, - > { - dropbear_asset_model_get_label(asset_registry, model_handle).into() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn diplomat_external_dropbear_asset_model_get_materials( - asset_registry: u64, - model_handle: u64, - ) -> diplomat_runtime::DiplomatResult< - Box<NMaterialList>, - crate::scripting::native::DropbearNativeError, - > { - dropbear_asset_model_get_materials(asset_registry, model_handle).into() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn diplomat_external_dropbear_asset_model_get_meshes( - asset_registry: u64, - model_handle: u64, - ) -> diplomat_runtime::DiplomatResult< - Box<NMeshList>, - crate::scripting::native::DropbearNativeError, - > { - dropbear_asset_model_get_meshes(asset_registry, model_handle).into() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn diplomat_external_dropbear_asset_model_get_nodes( - asset_registry: u64, - model_handle: u64, - ) -> diplomat_runtime::DiplomatResult< - Box<NNodeList>, - crate::scripting::native::DropbearNativeError, - > { - dropbear_asset_model_get_nodes(asset_registry, model_handle).into() - } - #[no_mangle] - #[allow(deprecated)] - extern "C" fn diplomat_external_dropbear_asset_model_get_skins( - asset_registry: u64, - model_handle: u64, - ) -> diplomat_runtime::DiplomatResult< - Box<NSkinList>, - crate::scripting::native::DropbearNativeError, - > { - dropbear_asset_model_get_skins(asset_registry, model_handle).into() - } - } - fn texture_handle_id( - registry: &dropbear_engine::asset::AssetRegistry, - texture: &Texture, - ) -> u64 { - texture - .hash() - .and_then(|hash| registry.texture_handle_by_hash(hash).map(|h| h.id)) - .unwrap_or(0) - } - fn map_vertex(vertex: &ModelVertex) -> NModelVertex { - NModelVertex { - 0: NModelVertexInner { - position: NVector3::from(vertex.position), - normal: NVector3::from(vertex.normal), - tangent: NVector4::from(vertex.tangent), - tex_coords0: NVector2::from(vertex.tex_coords0), - tex_coords1: NVector2::from(vertex.tex_coords1), - colour0: NVector4::from(vertex.colour0), - joints0: vertex.joints0.iter().map(|v| *v as i32).collect(), - weights0: NVector4::from(vertex.weights0), - }, - } - } - fn map_mesh(mesh: &Mesh) -> NMesh { - NMesh { - 0: NMeshInner { - name: mesh.name.clone(), - num_elements: mesh.num_elements as i32, - material_index: mesh.material as i32, - vertices: mesh.vertices.iter().map(map_vertex).collect(), - }, - } - } - fn map_material( - registry: &dropbear_engine::asset::AssetRegistry, - material: &Material, - ) -> NMaterial { - NMaterial { - 0: NMaterialInner { - name: material.name.clone(), - diffuse_texture: texture_handle_id(registry, &material.diffuse_texture), - normal_texture: texture_handle_id(registry, &material.normal_texture), - tint: NVector4::from(material.tint), - emissive_factor: NVector3::from(material.emissive_factor), - metallic_factor: material.metallic_factor, - roughness_factor: material.roughness_factor, - alpha_cutoff: material.alpha_cutoff, - double_sided: material.double_sided, - occlusion_strength: material.occlusion_strength, - normal_scale: material.normal_scale, - uv_tiling: NVector2::from(material.uv_tiling), - emissive_texture: material - .emissive_texture - .as_ref() - .map(|tex| texture_handle_id(registry, tex)) - .filter(|id| *id != 0), - metallic_roughness_texture: material - .metallic_roughness_texture - .as_ref() - .map(|tex| texture_handle_id(registry, tex)) - .filter(|id| *id != 0), - occlusion_texture: material - .occlusion_texture - .as_ref() - .map(|tex| texture_handle_id(registry, tex)) - .filter(|id| *id != 0), - }, - } - } - fn map_node_transform(transform: &NodeTransform) -> NNodeTransform { - NNodeTransform { - 0: NNodeTransformInner { - translation: NVector3::from(transform.translation), - rotation: NQuaternion::from(transform.rotation), - scale: NVector3::from(transform.scale), - }, - } - } - fn map_node(node: &Node) -> NNode { - NNode { - 0: NNodeInner { - name: node.name.clone(), - parent: node.parent.map(|v| v as i32), - children: node.children.iter().map(|v| *v as i32).collect(), - transform: map_node_transform(&node.transform), - }, - } - } - fn map_skin(skin: &Skin) -> NSkin { - let inverse_bind_matrices = skin - .inverse_bind_matrices - .iter() - .map(|matrix| matrix.to_cols_array().iter().map(|v| *v as f64).collect()) - .collect(); - NSkin { - 0: NSkinInner { - name: skin.name.clone(), - joints: skin.joints.iter().map(|v| *v as i32).collect(), - inverse_bind_matrices, - skeleton_root: skin.skeleton_root.map(|v| v as i32), - }, - } - } - fn map_interpolation( - value: &AnimationInterpolation, - ) -> Box<NAnimationInterpolation> { - match value { - AnimationInterpolation::Linear => NAnimationInterpolation::new_linear(), - AnimationInterpolation::Step => NAnimationInterpolation::new_step(), - AnimationInterpolation::CubicSpline => { - NAnimationInterpolation::new_cubicspline() - } - } - } - fn map_channel_values(values: &ChannelValues) -> Box<NChannelValues> { - match values { - ChannelValues::Translations(list) => { - let values: Vec<NVector3> = list - .iter() - .map(|v| NVector3::from(*v)) - .collect(); - NChannelValues::new_translations(&values) - } - ChannelValues::Rotations(list) => { - let values: Vec<NQuaternion> = list - .iter() - .map(|v| NQuaternion::from(*v)) - .collect(); - NChannelValues::new_rotations(&values) - } - ChannelValues::Scales(list) => { - let values: Vec<NVector3> = list - .iter() - .map(|v| NVector3::from(*v)) - .collect(); - NChannelValues::new_scales(&values) - } - } - } - fn map_animation_channel(channel: &AnimationChannel) -> Box<NAnimationChannel> { - let times: Vec<f64> = channel.times.iter().map(|v| *v as f64).collect(); - NAnimationChannel::new( - channel.target_node as i32, - ×, - map_channel_values(&channel.values), - map_interpolation(&channel.interpolation), - ) - } - fn map_animation(animation: &Animation) -> Box<NAnimation> { - let channels: Vec<Box<NAnimationChannel>> = animation - .channels - .iter() - .map(map_animation_channel) - .collect(); - NAnimation::new(animation.name.clone(), &channels, animation.duration) - } -} @@ -1,3 +1,8 @@ +// Machine generated header bindings by goanna-gen. +// DO NOT EDIT UNLESS YOU KNOW WHAT YOU ARE DOING (it will get regenerated anyways with a modification to eucalyptus-core/src). +// Licensed under MIT or Apache 2.0 depending on your mood. +// part of the dropbear project, by tirbofish + #ifndef DROPBEAR_H #define DROPBEAR_H @@ -6,28 +11,271 @@ #include <stddef.h> -typedef void* WorldPtr; +typedef enum AssetKind { + AssetKind_Texture = 0, + AssetKind_Model = 1, +} AssetKind; + +typedef enum ColliderShapeTag { + ColliderShapeTag_Box = 0, + ColliderShapeTag_Sphere = 1, + ColliderShapeTag_Capsule = 2, + ColliderShapeTag_Cylinder = 3, + ColliderShapeTag_Cone = 4, +} ColliderShapeTag; + +typedef struct ColliderShapeBox { + void half_extents; +} ColliderShapeBox; + +typedef struct ColliderShapeSphere { + float radius; +} ColliderShapeSphere; + +typedef struct ColliderShapeCapsule { + float half_height; + float radius; +} ColliderShapeCapsule; + +typedef struct ColliderShapeCylinder { + float half_height; + float radius; +} ColliderShapeCylinder; + +typedef struct ColliderShapeCone { + float half_height; + float radius; +} ColliderShapeCone; + +typedef union ColliderShapeData { + ColliderShapeBox Box; + ColliderShapeSphere Sphere; + ColliderShapeCapsule Capsule; + ColliderShapeCylinder Cylinder; + ColliderShapeCone Cone; +} ColliderShapeData; + +typedef struct ColliderShapeFfi { + ColliderShapeTag tag; + ColliderShapeData data; +} ColliderShapeFfi; + +typedef ColliderShapeFfi ColliderShape; + +typedef enum NShapeCastStatusTag { + NShapeCastStatusTag_OutOfIterations = 0, + NShapeCastStatusTag_Converged = 1, + NShapeCastStatusTag_Failed = 2, + NShapeCastStatusTag_PenetratingOrWithinTargetDist = 3, +} NShapeCastStatusTag; + +typedef struct NShapeCastStatusOutOfIterations { +} NShapeCastStatusOutOfIterations; + +typedef struct NShapeCastStatusConverged { +} NShapeCastStatusConverged; + +typedef struct NShapeCastStatusFailed { +} NShapeCastStatusFailed; + +typedef struct NShapeCastStatusPenetratingOrWithinTargetDist { +} NShapeCastStatusPenetratingOrWithinTargetDist; + +typedef union NShapeCastStatusData { + NShapeCastStatusOutOfIterations OutOfIterations; + NShapeCastStatusConverged Converged; + NShapeCastStatusFailed Failed; + NShapeCastStatusPenetratingOrWithinTargetDist PenetratingOrWithinTargetDist; +} NShapeCastStatusData; + +typedef struct NShapeCastStatusFfi { + NShapeCastStatusTag tag; + NShapeCastStatusData data; +} NShapeCastStatusFfi; + +typedef NShapeCastStatusFfi NShapeCastStatus; + +typedef enum NAnimationInterpolationTag { + NAnimationInterpolationTag_Linear = 0, + NAnimationInterpolationTag_Step = 1, + NAnimationInterpolationTag_CubicSpline = 2, +} NAnimationInterpolationTag; + +typedef struct NAnimationInterpolationLinear { +} NAnimationInterpolationLinear; + +typedef struct NAnimationInterpolationStep { +} NAnimationInterpolationStep; + +typedef struct NAnimationInterpolationCubicSpline { +} NAnimationInterpolationCubicSpline; + +typedef union NAnimationInterpolationData { + NAnimationInterpolationLinear Linear; + NAnimationInterpolationStep Step; + NAnimationInterpolationCubicSpline CubicSpline; +} NAnimationInterpolationData; + +typedef struct NAnimationInterpolationFfi { + NAnimationInterpolationTag tag; + NAnimationInterpolationData data; +} NAnimationInterpolationFfi; + +typedef NAnimationInterpolationFfi NAnimationInterpolation; -typedef struct NVector4 { +typedef struct NVector3 { double x; double y; double z; - double w; -} NVector4; +} NVector3; -typedef struct NVector3 { +typedef struct NVector3Array { + NVector3* values; + size_t length; + size_t capacity; +} NVector3Array; + +typedef struct NQuaternion { double x; double y; double z; -} NVector3; + double w; +} NQuaternion; + +typedef struct NQuaternionArray { + NQuaternion* values; + size_t length; + size_t capacity; +} NQuaternionArray; + +typedef enum NChannelValuesTag { + NChannelValuesTag_Translations = 0, + NChannelValuesTag_Rotations = 1, + NChannelValuesTag_Scales = 2, +} NChannelValuesTag; + +typedef struct NChannelValuesTranslations { + NVector3Array values; +} NChannelValuesTranslations; -typedef struct Option Option;// opaque +typedef struct NChannelValuesRotations { + NQuaternionArray values; +} NChannelValuesRotations; + +typedef struct NChannelValuesScales { + NVector3Array values; +} NChannelValuesScales; + +typedef union NChannelValuesData { + NChannelValuesTranslations Translations; + NChannelValuesRotations Rotations; + NChannelValuesScales Scales; +} NChannelValuesData; + +typedef struct NChannelValuesFfi { + NChannelValuesTag tag; + NChannelValuesData data; +} NChannelValuesFfi; + +typedef NChannelValuesFfi NChannelValues; + +typedef void* SceneLoaderPtr; + +typedef void* AssetRegistryPtr; typedef struct NVector2 { double x; double y; } NVector2; +typedef struct Progress { + size_t current; + size_t total; + const char* message; +} Progress; + +typedef struct u64Array { + uint64_t* values; + size_t length; + size_t capacity; +} u64Array; + +typedef struct ConnectedGamepadIds { + u64Array ids; +} ConnectedGamepadIds; + +typedef struct NAttenuation { + float constant; + float linear; + float quadratic; +} NAttenuation; + +typedef struct NRange { + float start; + float end; +} NRange; + +typedef struct IndexNative { + uint32_t index; + uint32_t generation; +} IndexNative; + +typedef struct NCollider { + IndexNative index; + uint64_t entity_id; + uint32_t id; +} NCollider; + +typedef struct NColliderArray { + NCollider* values; + size_t length; + size_t capacity; +} NColliderArray; + +typedef struct NTransform { + NVector3 position; + NQuaternion rotation; + NVector3 scale; +} NTransform; + +typedef void* InputStatePtr; + +typedef struct IndexNativeArray { + IndexNative* values; + size_t length; + size_t capacity; +} IndexNativeArray; + +typedef struct CharacterCollisionArray { + uint64_t entity_id; + IndexNativeArray collisions; +} CharacterCollisionArray; + +typedef struct NShapeCastHit { + NCollider collider; + double distance; + NVector3 witness1; + NVector3 witness2; + NVector3 normal1; + NVector3 normal2; + NShapeCastStatus status; +} NShapeCastHit; + +typedef struct AxisLock { + bool x; + bool y; + bool z; +} AxisLock; + +typedef void* CommandBufferPtr; + +typedef struct NVector4 { + double x; + double y; + double z; + double w; +} NVector4; + typedef struct NMaterial { const char* name; uint64_t diffuse_texture; @@ -36,95 +284,86 @@ typedef struct NMaterial { NVector3 emissive_factor; float metallic_factor; float roughness_factor; - Option alpha_cutoff; + const float* alpha_cutoff; bool double_sided; float occlusion_strength; float normal_scale; NVector2 uv_tiling; - Option emissive_texture; - Option metallic_roughness_texture; - Option occlusion_texture; + const uint64_t* emissive_texture; + const uint64_t* metallic_roughness_texture; + const uint64_t* occlusion_texture; } NMaterial; -typedef struct NMaterialArrayFfi { - const NMaterial* ptr; - size_t len; -} NMaterialArrayFfi; - -typedef void* AssetRegistryPtr; +typedef struct NMaterialArray { + NMaterial* values; + size_t length; + size_t capacity; +} NMaterialArray; -typedef void* SceneLoaderPtr; +typedef struct i32Array { + int32_t* values; + size_t length; + size_t capacity; +} i32Array; -typedef struct size_t size_t;// opaque - -typedef struct Progress { - size_t current; - size_t total; - const char* message; -} Progress; - -typedef struct i32ArrayFfi { - const int32_t* ptr; - size_t len; -} i32ArrayFfi; - -typedef struct f64ArrayFfiArrayFfi { - const double* ptr; - size_t len; -} f64ArrayFfiArrayFfi; +typedef struct f64ArrayArray { + double* values; + size_t length; + size_t capacity; +} f64ArrayArray; typedef struct NSkin { const char* name; - i32ArrayFfi joints; - f64ArrayFfiArrayFfi inverse_bind_matrices; - Option skeleton_root; + i32Array joints; + f64ArrayArray inverse_bind_matrices; + const int32_t* skeleton_root; } NSkin; -typedef struct NSkinArrayFfi { - const NSkin* ptr; - size_t len; -} NSkinArrayFfi; +typedef struct NSkinArray { + NSkin* values; + size_t length; + size_t capacity; +} NSkinArray; -typedef struct f64ArrayFfi { - const double* ptr; - size_t len; -} f64ArrayFfi; - -typedef struct NChannelValues NChannelValues;// opaque - -typedef struct NAnimationInterpolation NAnimationInterpolation;// opaque +typedef struct f64Array { + double* values; + size_t length; + size_t capacity; +} f64Array; typedef struct NAnimationChannel { int32_t target_node; - f64ArrayFfi times; + f64Array times; NChannelValues values; NAnimationInterpolation interpolation; } NAnimationChannel; -typedef struct NAnimationChannelArrayFfi { - const NAnimationChannel* ptr; - size_t len; -} NAnimationChannelArrayFfi; +typedef struct NAnimationChannelArray { + NAnimationChannel* values; + size_t length; + size_t capacity; +} NAnimationChannelArray; typedef struct NAnimation { const char* name; - NAnimationChannelArrayFfi channels; + NAnimationChannelArray channels; float duration; } NAnimation; -typedef struct NAnimationArrayFfi { - const NAnimation* ptr; - size_t len; -} NAnimationArrayFfi; +typedef struct NAnimationArray { + NAnimation* values; + size_t length; + size_t capacity; +} NAnimationArray; -typedef struct AssetKind AssetKind;// opaque +typedef struct NColour { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; +} NColour; -typedef struct NQuaternion { - double x; - double y; - double z; - double w; -} NQuaternion; +typedef void* PhysicsStatePtr; typedef struct NNodeTransform { NVector3 translation; @@ -134,15 +373,18 @@ typedef struct NNodeTransform { typedef struct NNode { const char* name; - Option parent; - i32ArrayFfi children; + const int32_t* parent; + i32Array children; NNodeTransform transform; } NNode; -typedef struct NNodeArrayFfi { - const NNode* ptr; - size_t len; -} NNodeArrayFfi; +typedef struct NNodeArray { + NNode* values; + size_t length; + size_t capacity; +} NNodeArray; + +typedef void* GraphicsContextPtr; typedef struct NModelVertex { NVector3 position; @@ -151,35 +393,198 @@ typedef struct NModelVertex { NVector2 tex_coords0; NVector2 tex_coords1; NVector4 colour0; - i32ArrayFfi joints0; + i32Array joints0; NVector4 weights0; } NModelVertex; -typedef struct NModelVertexArrayFfi { - const NModelVertex* ptr; - size_t len; -} NModelVertexArrayFfi; +typedef struct NModelVertexArray { + NModelVertex* values; + size_t length; + size_t capacity; +} NModelVertexArray; typedef struct NMesh { const char* name; int32_t num_elements; int32_t material_index; - NModelVertexArrayFfi vertices; + NModelVertexArray vertices; } NMesh; -typedef struct NMeshArrayFfi { - const NMesh* ptr; - size_t len; -} NMeshArrayFfi; +typedef struct NMeshArray { + NMesh* values; + size_t length; + size_t capacity; +} NMeshArray; + +typedef void* WorldPtr; +typedef struct RayHit { + NCollider collider; + double distance; +} RayHit; + +typedef struct RigidBodyContext { + IndexNative index; + uint64_t entity_id; +} RigidBodyContext; + +int32_t dropbear_gamepad_is_button_pressed(InputStatePtr input, uint64_t gamepad_id, int32_t button_ordinal, bool* out0); +int32_t dropbear_gamepad_get_left_stick_position(InputStatePtr input, uint64_t gamepad_id, NVector2* out0); +int32_t dropbear_gamepad_get_right_stick_position(InputStatePtr input, uint64_t gamepad_id, NVector2* out0); +int32_t dropbear_collider_group_exists_for_entity(WorldPtr world, uint64_t entity, bool* out0); +int32_t dropbear_collider_group_get_colliders(WorldPtr world, PhysicsStatePtr physics, uint64_t entity, NColliderArray* out0); +int32_t dropbear_character_collision_get_character_collision_collider(WorldPtr world, uint64_t entity, const IndexNative* collision_handle, NCollider* out0); +int32_t dropbear_character_collision_get_character_collision_position(WorldPtr world, uint64_t entity, const IndexNative* collision_handle, NTransform* out0); +int32_t dropbear_character_collision_get_character_collision_translation_applied(WorldPtr world, uint64_t entity, const IndexNative* collision_handle, NVector3* out0); +int32_t dropbear_character_collision_get_character_collision_translation_remaining(WorldPtr world, uint64_t entity, const IndexNative* collision_handle, NVector3* out0); +int32_t dropbear_character_collision_get_character_collision_time_of_impact(WorldPtr world, uint64_t entity, const IndexNative* collision_handle, double* out0); +int32_t dropbear_character_collision_get_character_collision_witness1(WorldPtr world, uint64_t entity, const IndexNative* collision_handle, NVector3* out0); +int32_t dropbear_character_collision_get_character_collision_witness2(WorldPtr world, uint64_t entity, const IndexNative* collision_handle, NVector3* out0); +int32_t dropbear_character_collision_get_character_collision_normal1(WorldPtr world, uint64_t entity, const IndexNative* collision_handle, NVector3* out0); +int32_t dropbear_character_collision_get_character_collision_normal2(WorldPtr world, uint64_t entity, const IndexNative* collision_handle, NVector3* out0); +int32_t dropbear_character_collision_get_character_collision_status(WorldPtr world, uint64_t entity, const IndexNative* collision_handle, NShapeCastStatus* out0); +int32_t dropbear_collider_get_collider_shape(PhysicsStatePtr physics, const NCollider* collider, ColliderShape* out0); +int32_t dropbear_collider_set_collider_shape(PhysicsStatePtr physics, const NCollider* collider, const ColliderShape* shape); +int32_t dropbear_collider_get_collider_density(PhysicsStatePtr physics, const NCollider* collider, double* out0); +int32_t dropbear_collider_set_collider_density(PhysicsStatePtr physics, const NCollider* collider, double density); +int32_t dropbear_collider_get_collider_friction(PhysicsStatePtr physics, const NCollider* collider, double* out0); +int32_t dropbear_collider_set_collider_friction(PhysicsStatePtr physics, const NCollider* collider, double friction); +int32_t dropbear_collider_get_collider_restitution(PhysicsStatePtr physics, const NCollider* collider, double* out0); +int32_t dropbear_collider_set_collider_restitution(PhysicsStatePtr physics, const NCollider* collider, double restitution); +int32_t dropbear_collider_get_collider_mass(PhysicsStatePtr physics, const NCollider* collider, double* out0); +int32_t dropbear_collider_set_collider_mass(PhysicsStatePtr physics, const NCollider* collider, double mass); +int32_t dropbear_collider_get_collider_is_sensor(PhysicsStatePtr physics, const NCollider* collider, bool* out0); +int32_t dropbear_collider_set_collider_is_sensor(PhysicsStatePtr physics, const NCollider* collider, bool is_sensor); +int32_t dropbear_collider_get_collider_translation(PhysicsStatePtr physics, const NCollider* collider, NVector3* out0); +int32_t dropbear_collider_set_collider_translation(PhysicsStatePtr physics, const NCollider* collider, const NVector3* translation); +int32_t dropbear_collider_get_collider_rotation(PhysicsStatePtr physics, const NCollider* collider, NVector3* out0); +int32_t dropbear_collider_set_collider_rotation(PhysicsStatePtr physics, const NCollider* collider, const NVector3* rotation); +int32_t dropbear_rigidbody_rigid_body_exists_for_entity(WorldPtr world, PhysicsStatePtr physics, uint64_t entity, IndexNative* out0, bool* out0_present); +int32_t dropbear_rigidbody_get_rigidbody_mode(WorldPtr _world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, int32_t* out0); +int32_t dropbear_rigidbody_set_rigidbody_mode(WorldPtr world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, int32_t mode); +int32_t dropbear_rigidbody_get_rigidbody_gravity_scale(WorldPtr _world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, double* out0); +int32_t dropbear_rigidbody_set_rigidbody_gravity_scale(WorldPtr world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, double gravity_scale); +int32_t dropbear_rigidbody_get_rigidbody_linear_damping(WorldPtr _world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, double* out0); +int32_t dropbear_rigidbody_set_rigidbody_linear_damping(WorldPtr world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, double linear_damping); +int32_t dropbear_rigidbody_get_rigidbody_angular_damping(WorldPtr _world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, double* out0); +int32_t dropbear_rigidbody_set_rigidbody_angular_damping(WorldPtr world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, double angular_damping); +int32_t dropbear_rigidbody_get_rigidbody_sleep(WorldPtr _world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, bool* out0); +int32_t dropbear_rigidbody_set_rigidbody_sleep(WorldPtr world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, bool sleep); +int32_t dropbear_rigidbody_get_rigidbody_ccd_enabled(WorldPtr _world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, bool* out0); +int32_t dropbear_rigidbody_set_rigidbody_ccd_enabled(WorldPtr world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, bool ccd_enabled); +int32_t dropbear_rigidbody_get_rigidbody_linear_velocity(WorldPtr _world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, NVector3* out0); +int32_t dropbear_rigidbody_set_rigidbody_linear_velocity(WorldPtr world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, const NVector3* linear_velocity); +int32_t dropbear_rigidbody_get_rigidbody_angular_velocity(WorldPtr _world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, NVector3* out0); +int32_t dropbear_rigidbody_set_rigidbody_angular_velocity(WorldPtr world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, const NVector3* angular_velocity); +int32_t dropbear_rigidbody_get_rigidbody_lock_translation(WorldPtr _world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, AxisLock* out0); +int32_t dropbear_rigidbody_set_rigidbody_lock_translation(WorldPtr world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, const AxisLock* lock_translation); +int32_t dropbear_rigidbody_get_rigidbody_lock_rotation(WorldPtr _world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, AxisLock* out0); +int32_t dropbear_rigidbody_set_rigidbody_lock_rotation(WorldPtr world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, const AxisLock* lock_rotation); +int32_t dropbear_rigidbody_get_rigidbody_children(WorldPtr _world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, NColliderArray* out0); +int32_t dropbear_rigidbody_apply_impulse(WorldPtr world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, double x, double y, double z); +int32_t dropbear_rigidbody_apply_torque_impulse(WorldPtr world, PhysicsStatePtr physics, const RigidBodyContext* rigidbody, double x, double y, double z); +int32_t dropbear_kcc_kcc_exists_for_entity(WorldPtr world, uint64_t entity, bool* out0); +int32_t dropbear_kcc_move_character(WorldPtr world, PhysicsStatePtr physics_state, uint64_t entity, const NVector3* translation, double delta_time); +int32_t dropbear_kcc_set_rotation(WorldPtr world, PhysicsStatePtr physics_state, uint64_t entity, const NQuaternion* rotation); +int32_t dropbear_kcc_get_hit(WorldPtr world, uint64_t entity, CharacterCollisionArray* out0); int32_t dropbear_scene_get_scene_load_progress(SceneLoaderPtr scene_loader, uint64_t scene_id, Progress* out0); -int32_t dropbear_get_entity(WorldPtr world, const char* label, uint64_t* out0); +int32_t dropbear_camera_exists_for_entity(WorldPtr world, uint64_t entity, bool* out0); +int32_t dropbear_camera_get_eye(WorldPtr world, uint64_t entity, NVector3* out0); +int32_t dropbear_camera_set_eye(WorldPtr world, uint64_t entity, const NVector3* eye); +int32_t dropbear_camera_get_target(WorldPtr world, uint64_t entity, NVector3* out0); +int32_t dropbear_camera_set_target(WorldPtr world, uint64_t entity, const NVector3* target); +int32_t dropbear_camera_get_up(WorldPtr world, uint64_t entity, NVector3* out0); +int32_t dropbear_camera_set_up(WorldPtr world, uint64_t entity, const NVector3* up); +int32_t dropbear_camera_get_aspect(WorldPtr world, uint64_t entity, double* out0); +int32_t dropbear_camera_get_fovy(WorldPtr world, uint64_t entity, double* out0); +int32_t dropbear_camera_set_fovy(WorldPtr world, uint64_t entity, double fovy); +int32_t dropbear_camera_get_znear(WorldPtr world, uint64_t entity, double* out0); +int32_t dropbear_camera_set_znear(WorldPtr world, uint64_t entity, double znear); +int32_t dropbear_camera_get_zfar(WorldPtr world, uint64_t entity, double* out0); +int32_t dropbear_camera_set_zfar(WorldPtr world, uint64_t entity, double zfar); +int32_t dropbear_camera_get_yaw(WorldPtr world, uint64_t entity, double* out0); +int32_t dropbear_camera_set_yaw(WorldPtr world, uint64_t entity, double yaw); +int32_t dropbear_camera_get_pitch(WorldPtr world, uint64_t entity, double* out0); +int32_t dropbear_camera_set_pitch(WorldPtr world, uint64_t entity, double pitch); +int32_t dropbear_camera_get_speed(WorldPtr world, uint64_t entity, double* out0); +int32_t dropbear_camera_set_speed(WorldPtr world, uint64_t entity, double speed); +int32_t dropbear_camera_get_sensitivity(WorldPtr world, uint64_t entity, double* out0); +int32_t dropbear_camera_set_sensitivity(WorldPtr world, uint64_t entity, double sensitivity); +int32_t dropbear_entity_label_exists_for_entity(WorldPtr world, uint64_t entity, bool* out0); +int32_t dropbear_entity_get_label(WorldPtr world, uint64_t entity, char** out0); +int32_t dropbear_entity_get_children(WorldPtr world, uint64_t entity, u64Array* out0); +int32_t dropbear_entity_get_child_by_label(WorldPtr world, uint64_t entity, const char* target, uint64_t* out0, bool* out0_present); +int32_t dropbear_entity_get_parent(WorldPtr world, uint64_t entity, uint64_t* out0, bool* out0_present); +int32_t dropbear_input_print_input_state(InputStatePtr input); +int32_t dropbear_input_is_key_pressed(InputStatePtr input, int32_t key_code, bool* out0); +int32_t dropbear_input_get_mouse_position(InputStatePtr input, NVector2* out0); +int32_t dropbear_input_is_mouse_button_pressed(InputStatePtr input, int32_t button_ordinal, bool* out0); +int32_t dropbear_input_get_mouse_delta(InputStatePtr input, NVector2* out0); +int32_t dropbear_input_is_cursor_locked(InputStatePtr input, bool* out0); +int32_t dropbear_input_set_cursor_locked(CommandBufferPtr command_buffer, InputStatePtr input, bool locked); +int32_t dropbear_input_get_last_mouse_pos(InputStatePtr input, NVector2* out0); +int32_t dropbear_input_is_cursor_hidden(InputStatePtr input, bool* out0); +int32_t dropbear_input_set_cursor_hidden(CommandBufferPtr command_buffer, InputStatePtr input, bool hidden); +int32_t dropbear_input_get_connected_gamepads(InputStatePtr input, ConnectedGamepadIds* out0); +int32_t dropbear_lighting_light_exists_for_entity(WorldPtr world, uint64_t entity, bool* out0); +int32_t dropbear_lighting_get_position(WorldPtr world, uint64_t entity, NVector3* out0); +int32_t dropbear_lighting_set_position(WorldPtr world, uint64_t entity, const NVector3* position); +int32_t dropbear_lighting_get_direction(WorldPtr world, uint64_t entity, NVector3* out0); +int32_t dropbear_lighting_set_direction(WorldPtr world, uint64_t entity, const NVector3* direction); +int32_t dropbear_lighting_get_colour(WorldPtr world, uint64_t entity, NColour* out0); +int32_t dropbear_lighting_set_colour(WorldPtr world, uint64_t entity, const NColour* colour); +int32_t dropbear_lighting_get_light_type(WorldPtr world, uint64_t entity, int32_t* out0); +int32_t dropbear_lighting_set_light_type(WorldPtr world, uint64_t entity, int32_t light_type); +int32_t dropbear_lighting_get_intensity(WorldPtr world, uint64_t entity, double* out0); +int32_t dropbear_lighting_set_intensity(WorldPtr world, uint64_t entity, double intensity); +int32_t dropbear_lighting_get_attenuation(WorldPtr world, uint64_t entity, NAttenuation* out0); +int32_t dropbear_lighting_set_attenuation(WorldPtr world, uint64_t entity, const NAttenuation* attenuation); +int32_t dropbear_lighting_get_enabled(WorldPtr world, uint64_t entity, bool* out0); +int32_t dropbear_lighting_set_enabled(WorldPtr world, uint64_t entity, bool enabled); +int32_t dropbear_lighting_get_cutoff_angle(WorldPtr world, uint64_t entity, double* out0); +int32_t dropbear_lighting_set_cutoff_angle(WorldPtr world, uint64_t entity, double cutoff_angle); +int32_t dropbear_lighting_get_outer_cutoff_angle(WorldPtr world, uint64_t entity, double* out0); +int32_t dropbear_lighting_set_outer_cutoff_angle(WorldPtr world, uint64_t entity, double outer_cutoff_angle); +int32_t dropbear_lighting_get_casts_shadows(WorldPtr world, uint64_t entity, bool* out0); +int32_t dropbear_lighting_set_casts_shadows(WorldPtr world, uint64_t entity, bool casts_shadows); +int32_t dropbear_lighting_get_depth(WorldPtr world, uint64_t entity, NRange* out0); +int32_t dropbear_lighting_set_depth(WorldPtr world, uint64_t entity, const NRange* depth); +int32_t dropbear_physics_get_gravity(PhysicsStatePtr physics, NVector3* out0); +int32_t dropbear_physics_set_gravity(PhysicsStatePtr physics, const NVector3* gravity); +int32_t dropbear_physics_raycast(PhysicsStatePtr physics, const NVector3* origin, const NVector3* dir, double time_of_impact, bool solid, RayHit* out0, bool* out0_present); +int32_t dropbear_physics_shape_cast(PhysicsStatePtr physics, const NVector3* origin, const NVector3* direction, const ColliderShape* shape, double time_of_impact, bool solid, NShapeCastHit* out0, bool* out0_present); +int32_t dropbear_physics_is_overlapping(PhysicsStatePtr physics, const NCollider* collider1, const NCollider* collider2, bool* out0); +int32_t dropbear_physics_is_triggering(PhysicsStatePtr physics, const NCollider* collider1, const NCollider* collider2, bool* out0); +int32_t dropbear_physics_is_touching(PhysicsStatePtr physics, uint64_t entity1, uint64_t entity2, bool* out0); +int32_t dropbear_properties_custom_properties_exists_for_entity(WorldPtr world, uint64_t entity, bool* out0); +int32_t dropbear_properties_get_string_property(WorldPtr world, uint64_t entity, const char* key, char** out0, bool* out0_present); +int32_t dropbear_properties_get_int_property(WorldPtr world, uint64_t entity, const char* key, int32_t* out0, bool* out0_present); +int32_t dropbear_properties_get_long_property(WorldPtr world, uint64_t entity, const char* key, int64_t* out0, bool* out0_present); +int32_t dropbear_properties_get_double_property(WorldPtr world, uint64_t entity, const char* key, double* out0, bool* out0_present); +int32_t dropbear_properties_get_float_property(WorldPtr world, uint64_t entity, const char* key, float* out0, bool* out0_present); +int32_t dropbear_properties_get_bool_property(WorldPtr world, uint64_t entity, const char* key, bool* out0, bool* out0_present); +int32_t dropbear_properties_get_vec3_property(WorldPtr world, uint64_t entity, const char* key, NVector3* out0, bool* out0_present); +int32_t dropbear_properties_set_string_property(WorldPtr world, uint64_t entity, const char* key, const char* value); +int32_t dropbear_properties_set_int_property(WorldPtr world, uint64_t entity, const char* key, int32_t value); +int32_t dropbear_properties_set_long_property(WorldPtr world, uint64_t entity, const char* key, int64_t value); +int32_t dropbear_properties_set_double_property(WorldPtr world, uint64_t entity, const char* key, double value); +int32_t dropbear_properties_set_float_property(WorldPtr world, uint64_t entity, const char* key, double value); +int32_t dropbear_properties_set_bool_property(WorldPtr world, uint64_t entity, const char* key, bool value); +int32_t dropbear_properties_set_vec3_property(WorldPtr world, uint64_t entity, const char* key, const NVector3* value); +int32_t dropbear_engine_get_entity(WorldPtr world, const char* label, uint64_t* out0); +int32_t dropbear_engine_quit(CommandBufferPtr command_buffer); int32_t dropbear_engine_get_asset(AssetRegistryPtr asset, const char* label, const AssetKind* kind, uint64_t* out0, bool* out0_present); int32_t dropbear_asset_model_get_label(AssetRegistryPtr asset, uint64_t model_handle, char** out0); -int32_t dropbear_asset_model_get_meshes(AssetRegistryPtr asset, uint64_t model_handle, NMeshArrayFfi* out0); -int32_t dropbear_asset_model_get_materials(AssetRegistryPtr asset, uint64_t model_handle, NMaterialArrayFfi* out0); -int32_t dropbear_asset_model_get_skins(AssetRegistryPtr asset, uint64_t model_handle, NSkinArrayFfi* out0); -int32_t dropbear_asset_model_get_animations(AssetRegistryPtr asset, uint64_t model_handle, NAnimationArrayFfi* out0); -int32_t dropbear_asset_model_get_nodes(AssetRegistryPtr asset, uint64_t model_handle, NNodeArrayFfi* out0); +int32_t dropbear_asset_model_get_meshes(AssetRegistryPtr asset, uint64_t model_handle, NMeshArray* out0); +int32_t dropbear_asset_model_get_materials(AssetRegistryPtr asset, uint64_t model_handle, NMaterialArray* out0); +int32_t dropbear_asset_model_get_skins(AssetRegistryPtr asset, uint64_t model_handle, NSkinArray* out0); +int32_t dropbear_asset_model_get_animations(AssetRegistryPtr asset, uint64_t model_handle, NAnimationArray* out0); +int32_t dropbear_asset_model_get_nodes(AssetRegistryPtr asset, uint64_t model_handle, NNodeArray* out0); +int32_t dropbear_asset_texture_get_label(AssetRegistryPtr asset_manager, uint64_t texture_handle, char** out0, bool* out0_present); +int32_t dropbear_asset_texture_get_width(AssetRegistryPtr asset_manager, uint64_t texture_handle, uint32_t* out0); +int32_t dropbear_asset_texture_get_height(AssetRegistryPtr asset_manager, uint64_t texture_handle, uint32_t* out0); +int32_t dropbear_mesh_get_texture(WorldPtr world, AssetRegistryPtr asset, uint64_t entity, const char* material_name, uint64_t* out0, bool* out0_present); +int32_t dropbear_mesh_set_texture_override(WorldPtr world, AssetRegistryPtr asset, uint64_t entity, const char* material_name, uint64_t texture_handle); +int32_t dropbear_mesh_set_material_tint(WorldPtr world, AssetRegistryPtr asset, GraphicsContextPtr graphics, uint64_t entity, const char* material_name, float r, float g, float b, float a); #endif /* DROPBEAR_H */ @@ -1,22 +1,16 @@ package com.dropbear.asset class Texture(override val id: Long): AssetType(id) { - var label: String? + val label: String? get() = getLabel() - set(value) = setLabel(value) val width: Int get() = getWidth() val height: Int get() = getHeight() - - val depth: Int - get() = getDepth() } expect fun Texture.getLabel(): String? -expect fun Texture.setLabel(value: String?) expect fun Texture.getWidth(): Int -expect fun Texture.getHeight(): Int -expect fun Texture.getDepth(): Int +expect fun Texture.getHeight(): Int @@ -6,7 +6,7 @@ import com.dropbear.math.Quaternionf data class Animation( val name: String, val channels: List<AnimationChannel>, - val duration: Float + val duration: Double ) data class AnimationChannel( @@ -1,23 +1,23 @@ package com.dropbear.asset.model import com.dropbear.asset.Texture -import com.dropbear.math.Vector2f -import com.dropbear.math.Vector3f -import com.dropbear.math.Vector4f +import com.dropbear.math.Vector2d +import com.dropbear.math.Vector3d +import com.dropbear.math.Vector4d data class Material( val name: String, val diffuseTexture: Texture, val normalTexture: Texture, - val tint: Vector4f, - val emissiveFactor: Vector3f, - val metallicFactor: Float, - val roughnessFactor: Float, - val alphaCutoff: Float?, + val tint: Vector4d, + val emissiveFactor: Vector3d, + val metallicFactor: Double, + val roughnessFactor: Double, + val alphaCutoff: Double?, val doubleSided: Boolean, - val occlusionStrength: Float, - val normalScale: Float, - val uvTiling: Vector2f, + val occlusionStrength: Double, + val normalScale: Double, + val uvTiling: Vector2d, val emissiveTexture: Texture?, val metallicRoughnessTexture: Texture?, val occlusionTexture: Texture? @@ -13,20 +13,20 @@ class Gamepad( * The position of the left stick. */ val leftStickPosition: Vector2d - get() = getLeftStickPosition(id) + get() = getLeftStickPosition() /** * The position of the right stick. */ val rightStickPosition: Vector2d - get() = getRightStickPosition(id) + get() = getRightStickPosition() /** * Queries if a button is pressed, and returns either `true` if pressed * or `false` if not. */ fun isButtonPressed(button: GamepadButton): Boolean { - return isGamepadButtonPressed(id, button) + return isGamepadButtonPressed(button) } override fun toString(): String { @@ -34,6 +34,6 @@ class Gamepad( } } -internal expect fun Gamepad.isGamepadButtonPressed(id: Long, button: GamepadButton): Boolean -internal expect fun Gamepad.getLeftStickPosition(id: Long): Vector2d -internal expect fun Gamepad.getRightStickPosition(id: Long): Vector2d +internal expect fun Gamepad.isGamepadButtonPressed(button: GamepadButton): Boolean +internal expect fun Gamepad.getLeftStickPosition(): Vector2d +internal expect fun Gamepad.getRightStickPosition(): Vector2d @@ -0,0 +1,13 @@ +package com.dropbear.asset; + +import com.dropbear.EucalyptusCoreLoader; + +public class TextureNative { + static { + new EucalyptusCoreLoader().ensureLoaded(); + } + + public static native String getLabel(long assetManagerHandle, long textureHandle); + public static native int getWidth(long assetManagerHandle, long textureHandle); + public static native int getHeight(long assetManagerHandle, long textureHandle); +} @@ -14,4 +14,5 @@ public class MeshRendererNative { public static native long[] getAllTextureIds(long worldHandle, long assetRegistryHandle, long entityId); public static native Long getTexture(long worldHandle, long assetRegistryHandle, long entityId, String materialName); public static native void setTextureOverride(long worldHandle, long assetRegistryHandle, long entityId, String meshName, long textureHandle); + public static native void setMaterialTint(long worldHandle, long assetRegistryHandle, long graphicsContextHandle, long entityId, String materialName, float r, float g, float b, float a); } @@ -11,7 +11,7 @@ public class InputStateNative { public static native void printInputState(long inputStateHandle); public static native boolean isKeyPressed(long inputStateHandle, int keyCode); public static native Vector2d getMousePosition(long inputStateHandle); - public static native boolean isMouseButtonPressed(long inputStateHandle, MouseButton mouseButton); + public static native boolean isMouseButtonPressed(long inputStateHandle, int mouseButtonOrdinal); public static native Vector2d getMouseDelta(long inputStateHandle); public static native boolean isCursorLocked(long inputStateHandle); public static native void setCursorLocked(long commandBufferPtr, long inputStateHandle, boolean locked); @@ -7,6 +7,6 @@ public class ColliderGroupNative { new EucalyptusCoreLoader().ensureLoaded(); } - public static native Collider[] getColliderGroupColliders(long worldPtr, long physicsPtr, long entityId); public static native boolean colliderGroupExistsForEntity(long worldPtr, long entityId); + public static native Collider[] getColliderGroupColliders(long worldPtr, long physicsPtr, long entityId); } @@ -14,5 +14,5 @@ public class KinematicCharacterControllerNative { public static native void moveCharacter(long worldHandle, long physicsHandle, long entityHandle, Vector3d translation, double deltaTime); public static native void setRotation(long worldHandle, long physicsHandle, long entityHandle, Quaterniond rotation); - public static native CharacterCollision[] getHitNative(long worldHandle, long entity); + public static native CharacterCollision[] getHit(long worldHandle, long entity); } @@ -1,21 +1,15 @@ package com.dropbear.asset -actual fun Texture.getLabel(): String? { - TODO("Not yet implemented") -} +import com.dropbear.DropbearEngine -actual fun Texture.setLabel(value: String?) { - TODO("Not yet implemented") +actual fun Texture.getLabel(): String? { + return TextureNative.getLabel(DropbearEngine.native.assetHandle, id) } actual fun Texture.getWidth(): Int { - TODO("Not yet implemented") + return TextureNative.getWidth(DropbearEngine.native.assetHandle, id) } actual fun Texture.getHeight(): Int { - TODO("Not yet implemented") -} - -actual fun Texture.getDepth(): Int { - TODO("Not yet implemented") + return TextureNative.getHeight(DropbearEngine.native.assetHandle, id) } @@ -7,6 +7,7 @@ class DropbearContext( val worldHandle: Long, val inputHandle: Long, val commandBufferHandle: Long, + val graphicsContextHandle: Long, val assetHandle: Long, val sceneLoaderHandle: Long, val physicsEngineHandle: Long, @@ -6,6 +6,7 @@ actual class NativeEngine { internal var worldHandle: Long = 0L internal var inputHandle: Long = 0L internal var commandBufferHandle: Long = 0L + internal var graphicsContextHandle: Long = 0L internal var assetHandle: Long = 0L internal var sceneLoaderHandle: Long = 0L internal var physicsEngineHandle: Long = 0L @@ -16,6 +17,7 @@ actual class NativeEngine { this.worldHandle = ctx.worldHandle this.inputHandle = ctx.inputHandle this.commandBufferHandle = ctx.commandBufferHandle + this.graphicsContextHandle = ctx.graphicsContextHandle this.assetHandle = ctx.assetHandle this.sceneLoaderHandle = ctx.sceneLoaderHandle this.physicsEngineHandle = ctx.physicsEngineHandle @@ -33,6 +35,10 @@ actual class NativeEngine { Logger.error("NativeEngine: Error - Invalid graphics handle received!") return } + if (this.graphicsContextHandle <= 0L) { + Logger.error("NativeEngine: Error - Invalid graphics context handle received!") + return + } if (this.assetHandle <= 0L) { Logger.error("NativeEngine: Error - Invalid asset handle received!") return @@ -4,7 +4,6 @@ import com.dropbear.DropbearEngine import com.dropbear.math.Vector2d internal actual fun Gamepad.isGamepadButtonPressed( - id: Long, button: GamepadButton ): Boolean { return GamepadNative.isGamepadButtonPressed( @@ -15,7 +14,7 @@ internal actual fun Gamepad.isGamepadButtonPressed( } @Suppress("UNCHECKED_CAST") -internal actual fun Gamepad.getLeftStickPosition(id: Long): Vector2d { +internal actual fun Gamepad.getLeftStickPosition(): Vector2d { val result = GamepadNative.getLeftStickPosition( DropbearEngine.native.inputHandle, id @@ -25,7 +24,7 @@ internal actual fun Gamepad.getLeftStickPosition(id: Long): Vector2d { } @Suppress("UNCHECKED_CAST") -internal actual fun Gamepad.getRightStickPosition(id: Long): Vector2d { +internal actual fun Gamepad.getRightStickPosition(): Vector2d { val result = GamepadNative.getRightStickPosition( DropbearEngine.native.inputHandle, id @@ -17,7 +17,7 @@ actual class InputState actual constructor() { } actual fun isMouseButtonPressed(button: MouseButton): Boolean { - return InputStateNative.isMouseButtonPressed(DropbearEngine.native.inputHandle, button) + return InputStateNative.isMouseButtonPressed(DropbearEngine.native.inputHandle, button.ordinal) } actual fun getMouseDelta(): Vector2d { @@ -4,10 +4,6 @@ actual fun Texture.getLabel(): String? { TODO("Not yet implemented") } -actual fun Texture.setLabel(value: String?) { - TODO("Not yet implemented") -} - actual fun Texture.getWidth(): Int { TODO("Not yet implemented") } @@ -15,7 +11,3 @@ actual fun Texture.getWidth(): Int { actual fun Texture.getHeight(): Int { TODO("Not yet implemented") } - -actual fun Texture.getDepth(): Int { - TODO("Not yet implemented") -} @@ -13,7 +13,9 @@ data class DropbearContext( val world: NativeHandle?, val input: NativeHandle?, val graphics: NativeHandle?, + val graphics_context: NativeHandle?, val assets: NativeHandle?, val scene_loader: NativeHandle?, - val physics_engine: NativeHandle? + val physics_engine: NativeHandle?, + val ui_buf: NativeHandle? ) @@ -3,17 +3,16 @@ package com.dropbear.input import com.dropbear.math.Vector2d internal actual fun Gamepad.isGamepadButtonPressed( - id: Long, button: GamepadButton ): Boolean { TODO("Not yet implemented") } -internal actual fun Gamepad.getLeftStickPosition(id: Long): Vector2d { +internal actual fun Gamepad.getLeftStickPosition(): Vector2d { TODO("Not yet implemented") } -internal actual fun Gamepad.getRightStickPosition(id: Long): Vector2d { +internal actual fun Gamepad.getRightStickPosition(): Vector2d { TODO("Not yet implemented") }