tirbofish/dropbear · commit
bd6a938fb8ca0bccdf5fc28f24d18b5a7465902a
feature: native kotlin
fix: fixed up model not being saved properly
refactor: removed building for the time being.
jarvis, run github actions
Signature present but could not be verified.
Unverified
@@ -1132,6 +1132,7 @@ impl Model { B: AsRef<[u8]>, { puffin::profile_function!(label.unwrap_or("unlabelled model")); + log::debug!("Loading model: {:?}", label); let mut registry = registry.write(); let model_label = label @@ -2,7 +2,7 @@ use crate::hierarchy::EntityTransformExt; use crate::physics::PhysicsState; use crate::ser::model::EucalyptusModel; use crate::states::{SerializedMaterialCustomisation, SerializedMeshRenderer}; -use crate::utils::{AsFile, ResolveReference}; +use crate::utils::{ResolveReference}; use downcast_rs::{Downcast, impl_downcast}; use dropbear_engine::asset::{ASSET_REGISTRY, Handle}; use dropbear_engine::entity::{EntityTransform, MeshRenderer, Transform}; @@ -600,7 +600,7 @@ impl Component for MeshRenderer { match crate::metadata::find_asset_by_uuid(&project_root, uuid) { Ok(entry) => { if let crate::resource::ResourceReference::File(rel) = &entry.location { - let abs = project_root.join("resources").join(rel); + let abs = project_root.join(rel); match ResourceReference::from_path(&abs) { Ok(engine_ref) => { log::debug!("Loading model '{}' via UUID {}", entry.name, uuid); @@ -4,10 +4,8 @@ use crossbeam_channel::Sender; use eucalyptus_core::APP_INFO; use eucalyptus_core::config::ProjectConfig; use eucalyptus_core::runtime::RuntimeProjectConfig; -use eucalyptus_core::scene::SceneConfig; use magna_carta::Target; use ron::ser::PrettyConfig; -use semver::Version; use std::fs; use std::path::{Path, PathBuf}; use std::time::UNIX_EPOCH; @@ -16,83 +14,85 @@ use tokio::{fs as tokio_fs, process::Command, task}; /// Builds a eucalyptus project into a single bundle. /// /// Returns the path of the build directory -pub fn build(project_config: PathBuf) -> anyhow::Result<PathBuf> { +pub fn build(_project_config: PathBuf) -> anyhow::Result<PathBuf> { // todo: remake this entire function return Err(anyhow::anyhow!("Not implemented yet")); - log::info!("Started project building"); - // create a build directory - let project_root = project_config - .parent() - .ok_or(anyhow::anyhow!("Unable to locate parent folder of config"))? - .to_path_buf(); - let build_dir = project_root.join("build/output"); - if build_dir.exists() { - fs::remove_dir_all(&build_dir)?; - } - fs::create_dir_all(&build_dir)?; - log::debug!("Readied build directory"); - - // load the project config manually to avoid overwriting global state - let ron_str = fs::read_to_string(&project_config)?; - let mut config: ProjectConfig = ron::de::from_str(&ron_str)?; - config.project_path = project_root.clone(); - log::debug!("Loaded project config"); - - // load scenes - let mut scenes = Vec::new(); - let scene_folder = project_root.join("resources").join("scenes"); - if scene_folder.exists() { - for entry in fs::read_dir(scene_folder)? { - let entry = entry?; - let path = entry.path(); - if path.is_file() && path.extension().and_then(|s| s.to_str()) == Some("eucs") { - match SceneConfig::read_from(&path) { - Ok(scene) => { - scenes.push(scene); - } - Err(e) => { - log::warn!("Failed to load scene {:?} during build: {}", path, e); - } - } - } - } - } + + // log::info!("Started project building"); + // // create a build directory + // let project_root = project_config + // .parent() + // .ok_or(anyhow::anyhow!("Unable to locate parent folder of config"))? + // .to_path_buf(); + // let build_dir = project_root.join("build/output"); + + // if build_dir.exists() { + // fs::remove_dir_all(&build_dir)?; + // } + // fs::create_dir_all(&build_dir)?; + // log::debug!("Readied build directory"); + + // // load the project config manually to avoid overwriting global state + // let ron_str = fs::read_to_string(&project_config)?; + // let mut config: ProjectConfig = ron::de::from_str(&ron_str)?; + // config.project_path = project_root.clone(); + // log::debug!("Loaded project config"); + + // // load scenes + // let mut scenes = Vec::new(); + // let scene_folder = project_root.join("resources").join("scenes"); + // if scene_folder.exists() { + // for entry in fs::read_dir(scene_folder)? { + // let entry = entry?; + // let path = entry.path(); + // if path.is_file() && path.extension().and_then(|s| s.to_str()) == Some("eucs") { + // match SceneConfig::read_from(&path) { + // Ok(scene) => { + // scenes.push(scene); + // } + // Err(e) => { + // log::warn!("Failed to load scene {:?} during build: {}", path, e); + // } + // } + // } + // } + // } - // convert to runtime project config - let runtime_config = RuntimeProjectConfig { - project_name: config.project_name.clone(), - runtime_settings: config.runtime_settings.clone(), - scenes, - authors: config.authors.clone(), - editor_version: Version::parse(env!("CARGO_PKG_VERSION"))?, - project_version: Version::parse(config.project_version.clone().as_str())?, - initial_scene: config - .runtime_settings - .initial_scene - .ok_or(anyhow::anyhow!( - "Project was expected to be an initial scene" - ))?, - }; - log::debug!("Converted to runtime project config"); - - // export to .eupak - let eupak_path = build_dir.join("data.eupak"); - let config_bytes = postcard::to_stdvec::<RuntimeProjectConfig>(&runtime_config)?; - fs::write(&eupak_path, config_bytes)?; - log::debug!("Exported scene config to {:?}", eupak_path); - - // copy resources - let resources_src = project_root.join("resources"); - let resources_dst = build_dir.join("resources"); - if resources_src.exists() { - copy_dir_recursive(&resources_src, &resources_dst)?; - log::debug!("Copied resources to {:?}", resources_dst); - } + // // convert to runtime project config + // let runtime_config = RuntimeProjectConfig { + // project_name: config.project_name.clone(), + // runtime_settings: config.runtime_settings.clone(), + // scenes, + // authors: config.authors.clone(), + // editor_version: Version::parse(env!("CARGO_PKG_VERSION"))?, + // project_version: Version::parse(config.project_version.clone().as_str())?, + // initial_scene: config + // .runtime_settings + // .initial_scene + // .ok_or(anyhow::anyhow!( + // "Project was expected to be an initial scene" + // ))?, + // }; + // log::debug!("Converted to runtime project config"); + + // // export to .eupak + // let eupak_path = build_dir.join("data.eupak"); + // let config_bytes = postcard::to_stdvec::<RuntimeProjectConfig>(&runtime_config)?; + // fs::write(&eupak_path, config_bytes)?; + // log::debug!("Exported scene config to {:?}", eupak_path); + + // // copy resources + // let resources_src = project_root.join("resources"); + // let resources_dst = build_dir.join("resources"); + // if resources_src.exists() { + // copy_dir_recursive(&resources_src, &resources_dst)?; + // log::debug!("Copied resources to {:?}", resources_dst); + // } - log::info!("Success creating data.eupak file!"); + // log::info!("Success creating data.eupak file!"); - Ok(build_dir) + // Ok(build_dir) } fn copy_dir_recursive(src: &Path, dst: &Path) -> anyhow::Result<()> { @@ -737,49 +737,6 @@ impl Editor { Ok(()) } - pub(crate) fn queue_scene_load_by_name(&mut self, scene_name: &str) -> anyhow::Result<()> { - if scene_name.trim().is_empty() { - return Err(anyhow::anyhow!("Scene name cannot be empty")); - } - - let should_persist_current = self.current_scene_name.is_some() - && self.is_world_loaded.is_fully_loaded() - && self.world.len() > 0 - && { - let scenes = SCENES.read(); - !scenes.is_empty() - }; - - if should_persist_current { - self.save_current_scene()?; - } - - if let Some(current) = self.current_scene_name.as_deref() { - states::unload_scene(current); - } - - let scene = states::load_scene(scene_name)?; - - { - let mut scenes = SCENES.write(); - scenes.retain(|existing| existing.scene_name != scene.scene_name); - scenes.insert(0, scene.clone()); - } - - { - let mut project = PROJECT.write(); - project.last_opened_scene = Some(scene.scene_name.clone()); - project.write_to_all()?; - } - - log::info!("Scene '{}' staged for loading", scene.scene_name); - - self.current_scene_name = Some(scene.scene_name.clone()); - self.pending_scene_load = Some(PendingSceneLoad { scene }); - - Ok(()) - } - fn cleanup_scene_resources( &mut self, graphics: std::sync::Arc<dropbear_engine::graphics::SharedGraphicsContext>, @@ -1,4 +1,3 @@ package: com.dropbear.ffi.generated headers: dropbear.h -headerFilter: *.h -libraryPaths: src +headerFilter: *.h @@ -2,6 +2,7 @@ package com.dropbear.asset; import com.dropbear.EucalyptusCoreLoader; import com.dropbear.asset.model.*; +import java.util.List; public class ModelNative { static { @@ -9,9 +10,9 @@ public class ModelNative { } public static native String getLabel(long assetManagerHandle, String modelName); - public static native Mesh[] getMeshes(long assetManagerHandle, long modelHandle); - public static native Material[] getMaterials(long assetManagerHandle, long modelHandle); - public static native Skin[] getSkins(long assetManagerHandle, long modelHandle); - public static native Animation[] getAnimations(long assetManagerHandle, long modelHandle); - public static native Node[] getNodes(long assetManagerHandle, long modelHandle); + public static native List<Mesh> getMeshes(long assetManagerHandle, long modelHandle); + public static native List<Material> getMaterials(long assetManagerHandle, long modelHandle); + public static native List<Skin> getSkins(long assetManagerHandle, long modelHandle); + public static native List<Animation> getAnimations(long assetManagerHandle, long modelHandle); + public static native List<Node> getNodes(long assetManagerHandle, long modelHandle); } @@ -1,6 +1,7 @@ package com.dropbear.physics; import com.dropbear.EucalyptusCoreLoader; +import java.util.List; public class ColliderGroupNative { static { @@ -8,5 +9,5 @@ public class ColliderGroupNative { } public static native boolean colliderGroupExistsForEntity(long worldPtr, long entityId); - public static native Collider[] getColliderGroupColliders(long worldPtr, long physicsPtr, long entityId); + public static native List<Collider> getColliderGroupColliders(long worldPtr, long physicsPtr, long entityId); } @@ -3,6 +3,7 @@ package com.dropbear.physics; import com.dropbear.EucalyptusCoreLoader; import com.dropbear.math.Vector3d; import com.dropbear.math.Quaterniond; +import java.util.List; // fuck, this got a long ass name public class KinematicCharacterControllerNative { @@ -14,6 +15,6 @@ 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[] getHit(long worldHandle, long entity); + public static native List<CharacterCollision> getHit(long worldHandle, long entity); public static native CharacterMovementResult getMovementResult(long worldHandle, long entity); } @@ -33,17 +33,23 @@ class HotSwapUtility( InstantiationException::class ) fun getInstance(parameterTypes: Array<Class<*>>, args: Array<out Any?>): Any { - val clazz = classLoader.loadClass(className) - if (clazz.isAnnotationPresent(Metadata::class.java)) { - try { - val instanceField = clazz.getDeclaredField("INSTANCE") - return instanceField.get(null) - } catch (e: NoSuchFieldException) { - Logger.error("Failed to get instance of class: ${e.message}") + try { + val clazz = classLoader.loadClass(className) + if (clazz.isAnnotationPresent(Metadata::class.java)) { + try { + val instanceField = clazz.getDeclaredField("INSTANCE") + return instanceField.get(null) + } catch (e: NoSuchFieldException) { + Logger.error("Failed to get instance of class: ${e.message}") + } } + val constructor = clazz.getConstructor(*parameterTypes) + return constructor.newInstance(*args) + } catch (e: ClassNotFoundException) { + throw ClassNotFoundException("Class not found: $className. It seems like you have not generated your magna-carta manifest file.\n$e") + } catch (e: Exception) { + throw e } - val constructor = clazz.getConstructor(*parameterTypes) - return constructor.newInstance(*args) } fun reloadJar(newJarFilePath: String) { @@ -1,19 +1,41 @@ +@file:OptIn(ExperimentalForeignApi::class) + package com.dropbear -import com.dropbear.components.Camera +import com.dropbear.ffi.generated.* +import kotlin.String import com.dropbear.ui.UIInstruction +import kotlinx.cinterop.* -internal actual fun getEntity(label: String): Long? { - TODO("Not yet implemented") +internal actual fun getEntity(label: String): Long? = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped null + val out = alloc<ULongVar>() + val rc = dropbear_engine_get_entity(world, label, out.ptr) + if (rc != 0) null else out.value.toLong() } -internal actual fun getAsset(eucaURI: String): Long? { - TODO("Not yet implemented") +internal actual fun getAsset(eucaURI: String): Long? = memScoped { + val assets = DropbearEngine.native.assetHandle ?: return@memScoped null + val outId = alloc<ULongVar>() + val outPresent = alloc<BooleanVar>() + + val kindVar = alloc<UIntVar>() + // Try Texture + kindVar.value = AssetKind_Texture + var rc = dropbear_engine_get_asset(assets, eucaURI, kindVar.ptr, outId.ptr, outPresent.ptr) + if (rc == 0 && outPresent.value) return@memScoped outId.value.toLong() + + // Try Model + kindVar.value = AssetKind_Model + rc = dropbear_engine_get_asset(assets, eucaURI, kindVar.ptr, outId.ptr, outPresent.ptr) + if (rc == 0 && outPresent.value) outId.value.toLong() else null } internal actual fun quit() { - + val cmd = DropbearEngine.native.commandBufferHandle ?: return + memScoped { dropbear_engine_quit(cmd) } } internal actual fun renderUI(instructions: List<UIInstruction>) { + // UI rendering via native scripting is not yet wired } @@ -1,20 +1,40 @@ +@file:OptIn(ExperimentalForeignApi::class) + package com.dropbear -internal actual fun EntityRef.Companion.getEntityLabel(entity: EntityId): String { - TODO("Not yet implemented") +import com.dropbear.ffi.generated.* +import kotlin.String +import kotlinx.cinterop.* + +internal actual fun EntityRef.Companion.getEntityLabel(entity: EntityId): String = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped "" + val out = alloc<CPointerVar<ByteVar>>() + val rc = dropbear_entity_get_label(world, entity.raw.toULong(), out.ptr) + if (rc != 0) "" else out.value?.toKString() ?: "" } -internal actual fun EntityRef.getChildren(entityId: EntityId): Array<EntityRef>? { - TODO("Not yet implemented") +internal actual fun EntityRef.getChildren(entityId: EntityId): Array<EntityRef>? = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped null + val out = alloc<u64Array>() + val rc = dropbear_entity_get_children(world, entityId.raw.toULong(), out.ptr) + if (rc != 0) return@memScoped null + val ptr = out.values ?: return@memScoped emptyArray() + val len = out.length.toInt() + Array(len) { i -> EntityRef(EntityId(ptr[i].toLong())) } } -internal actual fun EntityRef.getChildByLabel( - entityId: EntityId, - label: String -): EntityRef? { - TODO("Not yet implemented") +internal actual fun EntityRef.getChildByLabel(entityId: EntityId, label: String): EntityRef? = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped null + val out = alloc<ULongVar>() + val present = alloc<BooleanVar>() + val rc = dropbear_entity_get_child_by_label(world, entityId.raw.toULong(), label, out.ptr, present.ptr) + if (rc != 0 || !present.value) null else EntityRef(EntityId(out.value.toLong())) } -internal actual fun EntityRef.getParent(entityId: EntityId): EntityRef? { - TODO("Not yet implemented") +internal actual fun EntityRef.getParent(entityId: EntityId): EntityRef? = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped null + val out = alloc<ULongVar>() + val present = alloc<BooleanVar>() + val rc = dropbear_entity_get_parent(world, entityId.raw.toULong(), out.ptr, present.ptr) + if (rc != 0 || !present.value) null else EntityRef(EntityId(out.value.toLong())) } @@ -1,50 +1,101 @@ +@file:OptIn(ExperimentalForeignApi::class) + package com.dropbear.animation +import com.dropbear.DropbearEngine import com.dropbear.EntityId +import com.dropbear.ffi.generated.* +import kotlin.String +import kotlinx.cinterop.* -actual fun AnimationComponent.getActiveAnimationIndex(): Int? { - TODO("Not yet implemented") +actual fun AnimationComponent.getActiveAnimationIndex(): Int? = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped null + val out = alloc<IntVar>() + val present = alloc<BooleanVar>() + dropbear_animation_get_active_animation_index(world, parentEntity.raw.toULong(), out.ptr, present.ptr) + if (!present.value) null else out.value } -actual fun AnimationComponent.setActiveAnimationIndex(index: Int?) { +actual fun AnimationComponent.setActiveAnimationIndex(index: Int?) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + if (index == null) { + dropbear_animation_set_active_animation_index(world, parentEntity.raw.toULong(), null) + } else { + val iv = alloc<IntVar>(); iv.value = index + val pv = alloc<CPointerVar<IntVar>>(); pv.value = iv.ptr + dropbear_animation_set_active_animation_index(world, parentEntity.raw.toULong(), pv.ptr) + } } -actual fun AnimationComponent.getTime(): Double { - TODO("Not yet implemented") +actual fun AnimationComponent.getTime(): Double = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped 0.0 + val out = alloc<DoubleVar>() + dropbear_animation_get_time(world, parentEntity.raw.toULong(), out.ptr) + out.value } -actual fun AnimationComponent.setTime(value: Double) { +actual fun AnimationComponent.setTime(value: Double) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_animation_set_time(world, parentEntity.raw.toULong(), value) } -actual fun AnimationComponent.getSpeed(): Double { - TODO("Not yet implemented") +actual fun AnimationComponent.getSpeed(): Double = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped 1.0 + val out = alloc<DoubleVar>() + dropbear_animation_get_speed(world, parentEntity.raw.toULong(), out.ptr) + out.value } -actual fun AnimationComponent.setSpeed(value: Double) { +actual fun AnimationComponent.setSpeed(value: Double) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_animation_set_speed(world, parentEntity.raw.toULong(), value) } -actual fun AnimationComponent.getLooping(): Boolean { - TODO("Not yet implemented") +actual fun AnimationComponent.getLooping(): Boolean = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped false + val out = alloc<BooleanVar>() + dropbear_animation_get_looping(world, parentEntity.raw.toULong(), out.ptr) + out.value } -actual fun AnimationComponent.setLooping(value: Boolean) { +actual fun AnimationComponent.setLooping(value: Boolean) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_animation_set_looping(world, parentEntity.raw.toULong(), value) } -actual fun AnimationComponent.getIsPlaying(): Boolean { - TODO("Not yet implemented") +actual fun AnimationComponent.getIsPlaying(): Boolean = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped false + val out = alloc<BooleanVar>() + dropbear_animation_get_is_playing(world, parentEntity.raw.toULong(), out.ptr) + out.value } -actual fun AnimationComponent.setIsPlaying(value: Boolean) { +actual fun AnimationComponent.setIsPlaying(value: Boolean) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_animation_set_is_playing(world, parentEntity.raw.toULong(), value) } -actual fun AnimationComponent.getIndexFromString(name: String): Int? { - TODO("Not yet implemented") +actual fun AnimationComponent.getIndexFromString(name: String): Int? = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped null + val out = alloc<IntVar>() + val present = alloc<BooleanVar>() + dropbear_animation_get_index_from_string(world, parentEntity.raw.toULong(), name, out.ptr, present.ptr) + if (!present.value) null else out.value } -actual fun AnimationComponent.getAvailableAnimations(): List<String> { - TODO("Not yet implemented") +actual fun AnimationComponent.getAvailableAnimations(): List<String> = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped emptyList() + val out = alloc<StringArray>() + val rc = dropbear_animation_get_available_animations(world, parentEntity.raw.toULong(), out.ptr) + if (rc != 0) return@memScoped emptyList() + val ptr = out.values ?: return@memScoped emptyList() + val len = out.length.toInt() + (0 until len).mapNotNull { i -> ptr[i]?.toKString() } } -actual fun animationComponentExistsForEntity(entityId: EntityId): Boolean { - TODO("Not yet implemented") +actual fun animationComponentExistsForEntity(entityId: EntityId): Boolean = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped false + val out = alloc<BooleanVar>() + dropbear_animation_exists_for_entity(world, entityId.raw.toULong(), out.ptr) + out.value } @@ -1,31 +1,26 @@ +@file:OptIn(ExperimentalForeignApi::class) + package com.dropbear.asset +import com.dropbear.DropbearEngine import com.dropbear.asset.model.Animation import com.dropbear.asset.model.Material import com.dropbear.asset.model.Mesh import com.dropbear.asset.model.Node import com.dropbear.asset.model.Skin +import com.dropbear.ffi.generated.* +import kotlin.String +import kotlinx.cinterop.* -actual fun Model.getLabel(): String { - TODO("Not yet implemented") -} - -actual fun Model.getMeshes(): List<Mesh> { - return emptyList() -} - -actual fun Model.getMaterials(): List<Material> { - return emptyList() +actual fun Model.getLabel(): String = memScoped { + val assets = DropbearEngine.native.assetHandle ?: return@memScoped "" + val out = alloc<CPointerVar<ByteVar>>() + val rc = dropbear_asset_model_get_label(assets, id.toULong(), out.ptr) + if (rc != 0) "" else out.value?.toKString() ?: "" } -actual fun Model.getSkins(): List<Skin> { - return emptyList() -} - -actual fun Model.getAnimations(): List<Animation> { - return emptyList() -} - -actual fun Model.getNodes(): List<Node> { - return emptyList() -} +actual fun Model.getMeshes(): List<Mesh> = emptyList() // complex C array parsing deferred +actual fun Model.getMaterials(): List<Material> = emptyList() +actual fun Model.getSkins(): List<Skin> = emptyList() +actual fun Model.getAnimations(): List<Animation> = emptyList() +actual fun Model.getNodes(): List<Node> = emptyList() @@ -1,13 +1,30 @@ +@file:OptIn(ExperimentalForeignApi::class) + package com.dropbear.asset -actual fun Texture.getLabel(): String? { - TODO("Not yet implemented") -} +import com.dropbear.DropbearEngine +import com.dropbear.ffi.generated.* +import kotlin.String +import kotlinx.cinterop.* -actual fun Texture.getWidth(): Int { - TODO("Not yet implemented") +actual fun Texture.getLabel(): String? = memScoped { + val assets = DropbearEngine.native.assetHandle ?: return@memScoped null + val out = alloc<CPointerVar<ByteVar>>() + val present = alloc<BooleanVar>() + val rc = dropbear_asset_texture_get_label(assets, id.toULong(), out.ptr, present.ptr) + if (rc != 0 || !present.value) null else out.value?.toKString() } -actual fun Texture.getHeight(): Int { - TODO("Not yet implemented") +actual fun Texture.getWidth(): Int = memScoped { + val assets = DropbearEngine.native.assetHandle ?: return@memScoped 0 + val out = alloc<UIntVar>() + dropbear_asset_texture_get_width(assets, id.toULong(), out.ptr) + out.value.toInt() } + +actual fun Texture.getHeight(): Int = memScoped { + val assets = DropbearEngine.native.assetHandle ?: return@memScoped 0 + val out = alloc<UIntVar>() + dropbear_asset_texture_get_height(assets, id.toULong(), out.ptr) + out.value.toInt() +} @@ -1,82 +1,147 @@ +@file:OptIn(ExperimentalForeignApi::class) + package com.dropbear.components +import com.dropbear.DropbearEngine import com.dropbear.EntityId +import com.dropbear.ffi.generated.* +import kotlin.String import com.dropbear.math.Vector3d +import kotlinx.cinterop.* -internal actual fun Camera.getCameraEye(entity: EntityId): Vector3d { - TODO("Not yet implemented") +internal actual fun Camera.getCameraEye(entity: EntityId): Vector3d = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped Vector3d.zero() + val out = alloc<NVector3>() + dropbear_camera_get_eye(world, entity.raw.toULong(), out.ptr) + Vector3d(out.x, out.y, out.z) } -internal actual fun Camera.setCameraEye(entity: EntityId, value: Vector3d) { +internal actual fun Camera.setCameraEye(entity: EntityId, value: Vector3d) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val v = allocVec3(value) + dropbear_camera_set_eye(world, entity.raw.toULong(), v.ptr) } -internal actual fun Camera.getCameraTarget(entity: EntityId): Vector3d { - TODO("Not yet implemented") +internal actual fun Camera.getCameraTarget(entity: EntityId): Vector3d = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped Vector3d.zero() + val out = alloc<NVector3>() + dropbear_camera_get_target(world, entity.raw.toULong(), out.ptr) + Vector3d(out.x, out.y, out.z) } -internal actual fun Camera.setCameraTarget(entity: EntityId, value: Vector3d) { +internal actual fun Camera.setCameraTarget(entity: EntityId, value: Vector3d) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val v = allocVec3(value) + dropbear_camera_set_target(world, entity.raw.toULong(), v.ptr) } -internal actual fun Camera.getCameraUp(entity: EntityId): Vector3d { - TODO("Not yet implemented") +internal actual fun Camera.getCameraUp(entity: EntityId): Vector3d = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped Vector3d.zero() + val out = alloc<NVector3>() + dropbear_camera_get_up(world, entity.raw.toULong(), out.ptr) + Vector3d(out.x, out.y, out.z) } -internal actual fun Camera.setCameraUp(entity: EntityId, value: Vector3d) { +internal actual fun Camera.setCameraUp(entity: EntityId, value: Vector3d) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val v = allocVec3(value) + dropbear_camera_set_up(world, entity.raw.toULong(), v.ptr) } -internal actual fun Camera.getCameraAspect(entity: EntityId): Double { - TODO("Not yet implemented") +internal actual fun Camera.getCameraAspect(entity: EntityId): Double = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped 1.0 + val out = alloc<DoubleVar>() + dropbear_camera_get_aspect(world, entity.raw.toULong(), out.ptr) + out.value } -internal actual fun Camera.getCameraFovY(entity: EntityId): Double { - TODO("Not yet implemented") +internal actual fun Camera.getCameraFovY(entity: EntityId): Double = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped 60.0 + val out = alloc<DoubleVar>() + dropbear_camera_get_fovy(world, entity.raw.toULong(), out.ptr) + out.value } -internal actual fun Camera.setCameraFovY(entity: EntityId, value: Double) { +internal actual fun Camera.setCameraFovY(entity: EntityId, value: Double) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_camera_set_fovy(world, entity.raw.toULong(), value) } -internal actual fun Camera.getCameraZNear(entity: EntityId): Double { - TODO("Not yet implemented") +internal actual fun Camera.getCameraZNear(entity: EntityId): Double = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped 0.1 + val out = alloc<DoubleVar>() + dropbear_camera_get_znear(world, entity.raw.toULong(), out.ptr) + out.value } -internal actual fun Camera.setCameraZNear(entity: EntityId, value: Double) { +internal actual fun Camera.setCameraZNear(entity: EntityId, value: Double) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_camera_set_znear(world, entity.raw.toULong(), value) } -internal actual fun Camera.getCameraZFar(entity: EntityId): Double { - TODO("Not yet implemented") +internal actual fun Camera.getCameraZFar(entity: EntityId): Double = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped 1000.0 + val out = alloc<DoubleVar>() + dropbear_camera_get_zfar(world, entity.raw.toULong(), out.ptr) + out.value } -internal actual fun Camera.setCameraZFar(entity: EntityId, value: Double) { +internal actual fun Camera.setCameraZFar(entity: EntityId, value: Double) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_camera_set_zfar(world, entity.raw.toULong(), value) } -internal actual fun Camera.getCameraYaw(entity: EntityId): Double { - TODO("Not yet implemented") +internal actual fun Camera.getCameraYaw(entity: EntityId): Double = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped 0.0 + val out = alloc<DoubleVar>() + dropbear_camera_get_yaw(world, entity.raw.toULong(), out.ptr) + out.value } -internal actual fun Camera.getCameraPitch(entity: EntityId): Double { - TODO("Not yet implemented") +internal actual fun Camera.getCameraPitch(entity: EntityId): Double = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped 0.0 + val out = alloc<DoubleVar>() + dropbear_camera_get_pitch(world, entity.raw.toULong(), out.ptr) + out.value } -internal actual fun Camera.setCameraYaw(entity: EntityId, value: Double) { +internal actual fun Camera.setCameraYaw(entity: EntityId, value: Double) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_camera_set_yaw(world, entity.raw.toULong(), value) } -internal actual fun Camera.setCameraPitch(entity: EntityId, value: Double) { +internal actual fun Camera.setCameraPitch(entity: EntityId, value: Double) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_camera_set_pitch(world, entity.raw.toULong(), value) } -internal actual fun Camera.getCameraSpeed(entity: EntityId): Double { - TODO("Not yet implemented") +internal actual fun Camera.getCameraSpeed(entity: EntityId): Double = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped 1.0 + val out = alloc<DoubleVar>() + dropbear_camera_get_speed(world, entity.raw.toULong(), out.ptr) + out.value } -internal actual fun Camera.setCameraSpeed(entity: EntityId, value: Double) { +internal actual fun Camera.setCameraSpeed(entity: EntityId, value: Double) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_camera_set_speed(world, entity.raw.toULong(), value) } -internal actual fun Camera.getCameraSensitivity(entity: EntityId): Double { - TODO("Not yet implemented") +internal actual fun Camera.getCameraSensitivity(entity: EntityId): Double = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped 1.0 + val out = alloc<DoubleVar>() + dropbear_camera_get_sensitivity(world, entity.raw.toULong(), out.ptr) + out.value } -internal actual fun Camera.setCameraSensitivity(entity: EntityId, value: Double) { +internal actual fun Camera.setCameraSensitivity(entity: EntityId, value: Double) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_camera_set_sensitivity(world, entity.raw.toULong(), value) } -internal actual fun cameraExistsForEntity(entity: EntityId): Boolean { - TODO("Not yet implemented") +internal actual fun cameraExistsForEntity(entity: EntityId): Boolean = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped false + val out = alloc<BooleanVar>() + dropbear_camera_exists_for_entity(world, entity.raw.toULong(), out.ptr) + out.value } @@ -1,96 +1,104 @@ +@file:OptIn(ExperimentalForeignApi::class) + package com.dropbear.components +import com.dropbear.DropbearEngine import com.dropbear.EntityId +import com.dropbear.ffi.generated.* +import kotlin.String import com.dropbear.math.Vector3d +import kotlinx.cinterop.* -actual fun CustomProperties.getStringProperty( - entityHandle: Long, - label: String -): String? { - TODO("Not yet implemented") +actual fun CustomProperties.getStringProperty(entityHandle: Long, label: String): String? = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped null + val out = alloc<CPointerVar<ByteVar>>() + val present = alloc<BooleanVar>() + val rc = dropbear_properties_get_string_property(world, entityHandle.toULong(), label, out.ptr, present.ptr) + if (rc != 0 || !present.value) null else out.value?.toKString() } -actual fun CustomProperties.getIntProperty(entityHandle: Long, label: String): Int? { - TODO("Not yet implemented") +actual fun CustomProperties.getIntProperty(entityHandle: Long, label: String): Int? = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped null + val out = alloc<IntVar>() + val present = alloc<BooleanVar>() + val rc = dropbear_properties_get_int_property(world, entityHandle.toULong(), label, out.ptr, present.ptr) + if (rc != 0 || !present.value) null else out.value } -actual fun CustomProperties.getLongProperty( - entityHandle: Long, - label: String -): Long? { - TODO("Not yet implemented") +actual fun CustomProperties.getLongProperty(entityHandle: Long, label: String): Long? = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped null + val out = alloc<LongVar>() + val present = alloc<BooleanVar>() + val rc = dropbear_properties_get_long_property(world, entityHandle.toULong(), label, out.ptr, present.ptr) + if (rc != 0 || !present.value) null else out.value } -actual fun CustomProperties.getDoubleProperty( - entityHandle: Long, - label: String -): Double? { - TODO("Not yet implemented") +actual fun CustomProperties.getDoubleProperty(entityHandle: Long, label: String): Double? = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped null + val out = alloc<DoubleVar>() + val present = alloc<BooleanVar>() + val rc = dropbear_properties_get_double_property(world, entityHandle.toULong(), label, out.ptr, present.ptr) + if (rc != 0 || !present.value) null else out.value } -actual fun CustomProperties.getFloatProperty( - entityHandle: Long, - label: String -): Float? { - TODO("Not yet implemented") +actual fun CustomProperties.getFloatProperty(entityHandle: Long, label: String): Float? = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped null + val out = alloc<FloatVar>() + val present = alloc<BooleanVar>() + val rc = dropbear_properties_get_float_property(world, entityHandle.toULong(), label, out.ptr, present.ptr) + if (rc != 0 || !present.value) null else out.value } -actual fun CustomProperties.getBoolProperty( - entityHandle: Long, - label: String -): Boolean? { - TODO("Not yet implemented") +actual fun CustomProperties.getBoolProperty(entityHandle: Long, label: String): Boolean? = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped null + val out = alloc<BooleanVar>() + val present = alloc<BooleanVar>() + val rc = dropbear_properties_get_bool_property(world, entityHandle.toULong(), label, out.ptr, present.ptr) + if (rc != 0 || !present.value) null else out.value } -actual fun CustomProperties.getVec3Property( - entityHandle: Long, - label: String -): Vector3d? { - TODO("Not yet implemented") +actual fun CustomProperties.getVec3Property(entityHandle: Long, label: String): Vector3d? = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped null + val out = alloc<NVector3>() + val present = alloc<BooleanVar>() + val rc = dropbear_properties_get_vec3_property(world, entityHandle.toULong(), label, out.ptr, present.ptr) + if (rc != 0 || !present.value) null else Vector3d(out.x, out.y, out.z) } -actual fun CustomProperties.setStringProperty( - entityHandle: Long, - label: String, - value: String -) { +actual fun CustomProperties.setStringProperty(entityHandle: Long, label: String, value: String) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_properties_set_string_property(world, entityHandle.toULong(), label, value) } -actual fun CustomProperties.setIntProperty( - entityHandle: Long, - label: String, - value: Int -) { +actual fun CustomProperties.setIntProperty(entityHandle: Long, label: String, value: Int) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_properties_set_int_property(world, entityHandle.toULong(), label, value) } -actual fun CustomProperties.setLongProperty( - entityHandle: Long, - label: String, - value: Long -) { +actual fun CustomProperties.setLongProperty(entityHandle: Long, label: String, value: Long) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_properties_set_long_property(world, entityHandle.toULong(), label, value) } -actual fun CustomProperties.setFloatProperty( - entityHandle: Long, - label: String, - value: Double -) { +actual fun CustomProperties.setFloatProperty(entityHandle: Long, label: String, value: Double) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_properties_set_float_property(world, entityHandle.toULong(), label, value) } -actual fun CustomProperties.setBoolProperty( - entityHandle: Long, - label: String, - value: Boolean -) { +actual fun CustomProperties.setBoolProperty(entityHandle: Long, label: String, value: Boolean) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_properties_set_bool_property(world, entityHandle.toULong(), label, value) } -actual fun CustomProperties.setVec3Property( - entityHandle: Long, - label: String, - value: Vector3d -) { +actual fun CustomProperties.setVec3Property(entityHandle: Long, label: String, value: Vector3d) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val nv = allocVec3(value) + dropbear_properties_set_vec3_property(world, entityHandle.toULong(), label, nv.ptr) } -internal actual fun customPropertiesExistsForEntity(entityId: EntityId): Boolean { - TODO("Not yet implemented") +internal actual fun customPropertiesExistsForEntity(entityId: EntityId): Boolean = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped false + val out = alloc<BooleanVar>() + dropbear_properties_custom_properties_exists_for_entity(world, entityId.raw.toULong(), out.ptr) + out.value } @@ -1,32 +1,50 @@ +@file:OptIn(ExperimentalForeignApi::class) + package com.dropbear.components +import com.dropbear.DropbearEngine import com.dropbear.EntityId +import com.dropbear.ffi.generated.* +import kotlin.String import com.dropbear.math.Transform +import kotlinx.cinterop.* -internal actual fun EntityTransform.getLocalTransform(entityId: EntityId): Transform { - TODO("Not yet implemented") +internal actual fun entityTransformExistsForEntity(entityId: EntityId): Boolean = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped false + val out = alloc<BooleanVar>() + dropbear_transform_exists_for_entity(world, entityId.raw.toULong(), out.ptr) + out.value } -internal actual fun EntityTransform.setLocalTransform( - entityId: EntityId, - transform: Transform -) { +internal actual fun EntityTransform.getLocalTransform(entityId: EntityId): Transform = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped Transform.identity() + val out = alloc<NTransform>() + dropbear_transform_get_local_transform(world, entityId.raw.toULong(), out.ptr) + readTransform(out) } -internal actual fun EntityTransform.getWorldTransform(entityId: EntityId): Transform { - TODO("Not yet implemented") +internal actual fun EntityTransform.setLocalTransform(entityId: EntityId, transform: Transform) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val nt = allocTransform(transform) + dropbear_transform_set_local_transform(world, entityId.raw.toULong(), nt.ptr) } -internal actual fun EntityTransform.setWorldTransform( - entityId: EntityId, - transform: Transform -) { +internal actual fun EntityTransform.getWorldTransform(entityId: EntityId): Transform = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped Transform.identity() + val out = alloc<NTransform>() + dropbear_transform_get_world_transform(world, entityId.raw.toULong(), out.ptr) + readTransform(out) } -internal actual fun EntityTransform.propagateTransform(entityId: EntityId): Transform? { - TODO("Not yet implemented") +internal actual fun EntityTransform.setWorldTransform(entityId: EntityId, transform: Transform) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val nt = allocTransform(transform) + dropbear_transform_set_world_transform(world, entityId.raw.toULong(), nt.ptr) } -internal actual fun entityTransformExistsForEntity(entityId: EntityId): Boolean { - TODO("Not yet implemented") +internal actual fun EntityTransform.propagateTransform(entityId: EntityId): Transform? = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped null + val out = alloc<NTransform>() + val rc = dropbear_transform_propogate_transform(world, entityId.raw.toULong(), out.ptr) + if (rc != 0) null else readTransform(out) } @@ -1,7 +1,16 @@ +@file:OptIn(ExperimentalForeignApi::class) + package com.dropbear.components +import com.dropbear.DropbearEngine import com.dropbear.EntityId +import com.dropbear.ffi.generated.* +import kotlin.String +import kotlinx.cinterop.* -internal actual fun labelExistsForEntity(entityId: EntityId): Boolean { - TODO("Not implemented yet") +internal actual fun labelExistsForEntity(entityId: EntityId): Boolean = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped false + val out = alloc<BooleanVar>() + dropbear_entity_label_exists_for_entity(world, entityId.raw.toULong(), out.ptr) + out.value } @@ -1,31 +1,36 @@ +@file:OptIn(ExperimentalForeignApi::class) + package com.dropbear.components +import com.dropbear.DropbearEngine import com.dropbear.EntityId import com.dropbear.asset.ModelHandle import com.dropbear.asset.TextureHandle +import com.dropbear.ffi.generated.* +import kotlin.String +import kotlinx.cinterop.* -internal actual fun MeshRenderer.getModel(id: EntityId): ModelHandle? { - TODO("Not yet implemented") -} +internal actual fun MeshRenderer.getModel(id: EntityId): ModelHandle? = null // no C API for mesh renderer model getter internal actual fun MeshRenderer.setModel(id: EntityId, model: ModelHandle?) { + // no C API for mesh renderer model setter } -internal actual fun MeshRenderer.getAllTextureIds(id: EntityId): List<TextureHandle>? { - TODO("Not yet implemented") -} +internal actual fun MeshRenderer.getAllTextureIds(id: EntityId): List<TextureHandle>? = null // no C API for bulk texture listing -internal actual fun MeshRenderer.getTexture(id: EntityId, materialName: String): Long? { - TODO("Not yet implemented") +internal actual fun MeshRenderer.getTexture(id: EntityId, materialName: String): Long? = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped null + val assets = DropbearEngine.native.assetHandle ?: return@memScoped null + val out = alloc<ULongVar>() + val present = alloc<BooleanVar>() + val rc = dropbear_mesh_get_texture(world, assets, id.raw.toULong(), materialName, out.ptr, present.ptr) + if (rc != 0 || !present.value) null else out.value.toLong() } -internal actual fun MeshRenderer.setTextureOverride( - id: EntityId, - materialName: String, - textureHandle: Long -) { +internal actual fun MeshRenderer.setTextureOverride(id: EntityId, materialName: String, textureHandle: Long) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val assets = DropbearEngine.native.assetHandle ?: return@memScoped + dropbear_mesh_set_texture_override(world, assets, id.raw.toULong(), materialName, textureHandle.toULong()) } -internal actual fun meshRendererExistsForEntity(entityId: EntityId): Boolean { - TODO("Not yet implemented") -} +internal actual fun meshRendererExistsForEntity(entityId: EntityId): Boolean = false // no dedicated exists check in C API @@ -13,13 +13,14 @@ import kotlinx.cinterop.interpretCPointer import kotlin.experimental.ExperimentalNativeApi actual class NativeEngine { - private var worldHandle: COpaquePointer? = null - private var inputHandle: COpaquePointer? = null - private var commandBufferHandle: COpaquePointer? = null - private var assetHandle: COpaquePointer? = null - private var sceneLoaderHandle: COpaquePointer? = null - private var physicsEngineHandle: COpaquePointer? = null - private var uiBufferHandle: COpaquePointer? = null + internal var worldHandle: COpaquePointer? = null + internal var inputHandle: COpaquePointer? = null + internal var commandBufferHandle: COpaquePointer? = null + internal var graphicsContextHandle: COpaquePointer? = null + internal var assetHandle: COpaquePointer? = null + internal var sceneLoaderHandle: COpaquePointer? = null + internal var physicsEngineHandle: COpaquePointer? = null + internal var uiBufferHandle: COpaquePointer? = null @Suppress("unused") fun init( @@ -27,11 +28,12 @@ actual class NativeEngine { ) { this.worldHandle = ctx?.world?.rawValue?.let { interpretCPointer(it) } this.inputHandle = ctx?.input?.rawValue?.let { interpretCPointer(it) } - this.commandBufferHandle = ctx?.graphics?.rawValue?.let { interpretCPointer(it) } + this.commandBufferHandle = ctx?.commandBuffer?.rawValue?.let { interpretCPointer(it) } + this.graphicsContextHandle = ctx?.graphicsContext?.rawValue?.let { interpretCPointer(it) } this.assetHandle = ctx?.assets?.rawValue?.let { interpretCPointer(it) } - this.sceneLoaderHandle = ctx?.scene_loader?.rawValue?.let { interpretCPointer(it) } - this.physicsEngineHandle = ctx?.physics_engine?.rawValue?.let { interpretCPointer(it) } - this.uiBufferHandle = ctx?.graphics?.rawValue?.let { interpretCPointer(it) } + this.sceneLoaderHandle = ctx?.sceneLoader?.rawValue?.let { interpretCPointer(it) } + this.physicsEngineHandle = ctx?.physicsEngine?.rawValue?.let { interpretCPointer(it) } + this.uiBufferHandle = ctx?.uiBuffer?.rawValue?.let { interpretCPointer(it) } Logger.init(com.dropbear.logging.SocketWriter()) @@ -2,7 +2,6 @@ package com.dropbear.ffi.generated -import kotlinx.cinterop.ExperimentalForeignApi import kotlinx.cinterop.NativePtr data class NativeHandle( @@ -12,10 +11,10 @@ data class NativeHandle( data class DropbearContext( val world: NativeHandle?, val input: NativeHandle?, - val graphics: NativeHandle?, - val graphics_context: NativeHandle?, + val commandBuffer: NativeHandle?, + val graphicsContext: NativeHandle?, val assets: NativeHandle?, - val scene_loader: NativeHandle?, - val physics_engine: NativeHandle?, - val ui_buf: NativeHandle? + val sceneLoader: NativeHandle?, + val physicsEngine: NativeHandle?, + val uiBuffer: NativeHandle? ) @@ -0,0 +1,138 @@ +@file:OptIn(ExperimentalForeignApi::class) + +package com.dropbear.ffi.generated + +import com.dropbear.EntityId +import com.dropbear.math.Quaterniond +import com.dropbear.math.Transform +import com.dropbear.math.Vector3d +import com.dropbear.physics.Collider +import com.dropbear.physics.ColliderShape +import com.dropbear.physics.Index +import com.dropbear.physics.RigidBody +import com.dropbear.physics.ShapeCastStatus +import com.dropbear.utils.Colour +import kotlinx.cinterop.* + +internal fun readTransform(nt: NTransform): Transform = Transform( + Vector3d(nt.position.x, nt.position.y, nt.position.z), + Quaterniond(nt.rotation.x, nt.rotation.y, nt.rotation.z, nt.rotation.w), + Vector3d(nt.scale.x, nt.scale.y, nt.scale.z), +) + +internal fun MemScope.allocTransform(t: Transform): NTransform { + val nt = alloc<NTransform>() + nt.position.x = t.position.x + nt.position.y = t.position.y + nt.position.z = t.position.z + nt.rotation.x = t.rotation.x + nt.rotation.y = t.rotation.y + nt.rotation.z = t.rotation.z + nt.rotation.w = t.rotation.w + nt.scale.x = t.scale.x + nt.scale.y = t.scale.y + nt.scale.z = t.scale.z + return nt +} + +internal fun MemScope.allocVec3(v: Vector3d): NVector3 { + val nv = alloc<NVector3>() + nv.x = v.x; nv.y = v.y; nv.z = v.z + return nv +} + +internal fun MemScope.allocQuat(q: Quaterniond): NQuaternion { + val nq = alloc<NQuaternion>() + nq.x = q.x; nq.y = q.y; nq.z = q.z; nq.w = q.w + return nq +} + +internal fun readCollider(nc: NCollider): Collider = Collider( + Index(nc.index.index, nc.index.generation), + EntityId(nc.entity_id.toLong()), + nc.id, +) + +internal fun MemScope.allocCollider(c: Collider): NCollider { + val nc = alloc<NCollider>() + nc.index.index = c.index.index + nc.index.generation = c.index.generation + nc.entity_id = c.entity.raw.toULong() + nc.id = c.id + return nc +} + +internal fun MemScope.allocRigidBodyCtx(rb: RigidBody): RigidBodyContext { + val ctx = alloc<RigidBodyContext>() + ctx.index.index = rb.index.index + ctx.index.generation = rb.index.generation + ctx.entity_id = rb.entity.raw.toULong() + return ctx +} + +internal fun MemScope.allocIndexNative(idx: Index): IndexNative { + val ni = alloc<IndexNative>() + ni.index = idx.index + ni.generation = idx.generation + return ni +} + +internal fun readColour(nc: NColour): Colour = Colour(nc.r, nc.g, nc.b, nc.a) + +internal fun MemScope.allocColour(c: Colour): NColour { + val nc = alloc<NColour>() + nc.r = c.r; nc.g = c.g; nc.b = c.b; nc.a = c.a + return nc +} + + +internal fun readShapeCastStatus(s: NShapeCastStatus): ShapeCastStatus = when (s.tag) { + NShapeCastStatusTag_OutOfIterations -> ShapeCastStatus.OutOfIterations + NShapeCastStatusTag_Converged -> ShapeCastStatus.Converged + NShapeCastStatusTag_Failed -> ShapeCastStatus.Failed + NShapeCastStatusTag_PenetratingOrWithinTargetDist -> ShapeCastStatus.PenetratingOrWithinTargetDist + else -> ShapeCastStatus.Failed +} + +internal fun readColliderShape(ffi: ColliderShapeFfi): ColliderShape = when (ffi.tag) { + ColliderShapeTag_Box -> ColliderShape.Box( + Vector3d(ffi.data.Box.half_extents.x, ffi.data.Box.half_extents.y, ffi.data.Box.half_extents.z) + ) + ColliderShapeTag_Sphere -> ColliderShape.Sphere(ffi.data.Sphere.radius) + ColliderShapeTag_Capsule -> ColliderShape.Capsule(ffi.data.Capsule.half_height, ffi.data.Capsule.radius) + ColliderShapeTag_Cylinder -> ColliderShape.Cylinder(ffi.data.Cylinder.half_height, ffi.data.Cylinder.radius) + ColliderShapeTag_Cone -> ColliderShape.Cone(ffi.data.Cone.half_height, ffi.data.Cone.radius) + else -> ColliderShape.Box(Vector3d.zero()) +} + +internal fun MemScope.allocColliderShape(shape: ColliderShape): ColliderShapeFfi { + val ffi = alloc<ColliderShapeFfi>() + when (shape) { + is ColliderShape.Box -> { + ffi.tag = ColliderShapeTag_Box + ffi.data.Box.half_extents.x = shape.halfExtents.x + ffi.data.Box.half_extents.y = shape.halfExtents.y + ffi.data.Box.half_extents.z = shape.halfExtents.z + } + is ColliderShape.Sphere -> { + ffi.tag = ColliderShapeTag_Sphere + ffi.data.Sphere.radius = shape.radius + } + is ColliderShape.Capsule -> { + ffi.tag = ColliderShapeTag_Capsule + ffi.data.Capsule.half_height = shape.halfHeight + ffi.data.Capsule.radius = shape.radius + } + is ColliderShape.Cylinder -> { + ffi.tag = ColliderShapeTag_Cylinder + ffi.data.Cylinder.half_height = shape.halfHeight + ffi.data.Cylinder.radius = shape.radius + } + is ColliderShape.Cone -> { + ffi.tag = ColliderShapeTag_Cone + ffi.data.Cone.half_height = shape.halfHeight + ffi.data.Cone.radius = shape.radius + } + } + return ffi +} @@ -1,18 +1,30 @@ +@file:OptIn(ExperimentalForeignApi::class) + package com.dropbear.input +import com.dropbear.DropbearEngine +import com.dropbear.ffi.generated.* +import kotlin.String import com.dropbear.math.Vector2d +import kotlinx.cinterop.* -internal actual fun Gamepad.isGamepadButtonPressed( - button: GamepadButton -): Boolean { - TODO("Not yet implemented") +internal actual fun Gamepad.isGamepadButtonPressed(button: GamepadButton): Boolean = memScoped { + val input = DropbearEngine.native.inputHandle ?: return@memScoped false + val out = alloc<BooleanVar>() + dropbear_gamepad_is_button_pressed(input, id.toULong(), button.ordinal, out.ptr) + out.value } -internal actual fun Gamepad.getLeftStickPosition(): Vector2d { - TODO("Not yet implemented") +internal actual fun Gamepad.getLeftStickPosition(): Vector2d = memScoped { + val input = DropbearEngine.native.inputHandle ?: return@memScoped Vector2d(0.0, 0.0) + val out = alloc<NVector2>() + dropbear_gamepad_get_left_stick_position(input, id.toULong(), out.ptr) + Vector2d(out.x, out.y) } -internal actual fun Gamepad.getRightStickPosition(): Vector2d { - TODO("Not yet implemented") +internal actual fun Gamepad.getRightStickPosition(): Vector2d = memScoped { + val input = DropbearEngine.native.inputHandle ?: return@memScoped Vector2d(0.0, 0.0) + val out = alloc<NVector2>() + dropbear_gamepad_get_right_stick_position(input, id.toULong(), out.ptr) + Vector2d(out.x, out.y) } - @@ -1,46 +1,87 @@ +@file:OptIn(ExperimentalForeignApi::class) + package com.dropbear.input +import com.dropbear.DropbearEngine +import com.dropbear.ffi.generated.* +import kotlin.String import com.dropbear.math.Vector2d +import kotlinx.cinterop.* actual class InputState actual constructor() { actual fun printInputState() { + val input = DropbearEngine.native.inputHandle ?: return + memScoped { dropbear_input_print_input_state(input) } } - actual fun isKeyPressed(key: KeyCode): Boolean { - TODO("Not yet implemented") + actual fun isKeyPressed(key: KeyCode): Boolean = memScoped { + val input = DropbearEngine.native.inputHandle ?: return@memScoped false + val out = alloc<BooleanVar>() + dropbear_input_is_key_pressed(input, key.ordinal, out.ptr) + out.value } - actual fun getMousePosition(): Vector2d { - TODO("Not yet implemented") + actual fun getMousePosition(): Vector2d = memScoped { + val input = DropbearEngine.native.inputHandle ?: return@memScoped Vector2d(0.0, 0.0) + val out = alloc<NVector2>() + dropbear_input_get_mouse_position(input, out.ptr) + Vector2d(out.x, out.y) } - actual fun isMouseButtonPressed(button: MouseButton): Boolean { - TODO("Not yet implemented") + actual fun isMouseButtonPressed(button: MouseButton): Boolean = memScoped { + val input = DropbearEngine.native.inputHandle ?: return@memScoped false + val out = alloc<BooleanVar>() + dropbear_input_is_mouse_button_pressed(input, button.ordinal, out.ptr) + out.value } - actual fun getMouseDelta(): Vector2d { - TODO("Not yet implemented") + actual fun getMouseDelta(): Vector2d = memScoped { + val input = DropbearEngine.native.inputHandle ?: return@memScoped Vector2d(0.0, 0.0) + val out = alloc<NVector2>() + dropbear_input_get_mouse_delta(input, out.ptr) + Vector2d(out.x, out.y) } - actual fun isCursorLocked(): Boolean { - TODO("Not yet implemented") + actual fun isCursorLocked(): Boolean = memScoped { + val input = DropbearEngine.native.inputHandle ?: return@memScoped false + val out = alloc<BooleanVar>() + dropbear_input_is_cursor_locked(input, out.ptr) + out.value } actual fun setCursorLocked(locked: Boolean) { + val cmd = DropbearEngine.native.commandBufferHandle ?: return + val input = DropbearEngine.native.inputHandle ?: return + memScoped { dropbear_input_set_cursor_locked(cmd, input, locked) } } - actual fun getLastMousePos(): Vector2d { - TODO("Not yet implemented") + actual fun getLastMousePos(): Vector2d = memScoped { + val input = DropbearEngine.native.inputHandle ?: return@memScoped Vector2d(0.0, 0.0) + val out = alloc<NVector2>() + dropbear_input_get_last_mouse_pos(input, out.ptr) + Vector2d(out.x, out.y) } - actual fun isCursorHidden(): Boolean { - TODO("Not yet implemented") + actual fun isCursorHidden(): Boolean = memScoped { + val input = DropbearEngine.native.inputHandle ?: return@memScoped false + val out = alloc<BooleanVar>() + dropbear_input_is_cursor_hidden(input, out.ptr) + out.value } actual fun setCursorHidden(hidden: Boolean) { + val cmd = DropbearEngine.native.commandBufferHandle ?: return + val input = DropbearEngine.native.inputHandle ?: return + memScoped { dropbear_input_set_cursor_hidden(cmd, input, hidden) } } - actual fun getConnectedGamepads(): List<Gamepad> { - TODO("Not yet implemented") + actual fun getConnectedGamepads(): List<Gamepad> = memScoped { + val input = DropbearEngine.native.inputHandle ?: return@memScoped emptyList() + val out = alloc<ConnectedGamepadIds>() + val rc = dropbear_input_get_connected_gamepads(input, out.ptr) + if (rc != 0) return@memScoped emptyList() + val ptr = out.ids.values ?: return@memScoped emptyList() + val len = out.ids.length.toInt() + (0 until len).map { i -> Gamepad(ptr[i].toLong()) } } } @@ -1,87 +1,159 @@ +@file:OptIn(ExperimentalForeignApi::class) + package com.dropbear.lighting +import com.dropbear.DropbearEngine import com.dropbear.EntityId +import com.dropbear.ffi.generated.* +import kotlin.String import com.dropbear.math.Vector3d import com.dropbear.utils.Colour import com.dropbear.utils.Range +import kotlinx.cinterop.* -internal actual fun lightExistsForEntity(entityId: EntityId): Boolean { - TODO("Not yet implemented") +internal actual fun lightExistsForEntity(entityId: EntityId): Boolean = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped false + val out = alloc<BooleanVar>() + dropbear_lighting_light_exists_for_entity(world, entityId.raw.toULong(), out.ptr) + out.value } -internal actual fun Light.getPosition(): Vector3d { - TODO("Not yet implemented") +internal actual fun Light.getPosition(): Vector3d = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped Vector3d.zero() + val out = alloc<NVector3>() + dropbear_lighting_get_position(world, entity.raw.toULong(), out.ptr) + Vector3d(out.x, out.y, out.z) } -internal actual fun Light.setPosition(position: Vector3d) { +internal actual fun Light.setPosition(position: Vector3d) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val nv = allocVec3(position) + dropbear_lighting_set_position(world, entity.raw.toULong(), nv.ptr) } -internal actual fun Light.getDirection(): Vector3d { - TODO("Not yet implemented") +internal actual fun Light.getDirection(): Vector3d = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped Vector3d.zero() + val out = alloc<NVector3>() + dropbear_lighting_get_direction(world, entity.raw.toULong(), out.ptr) + Vector3d(out.x, out.y, out.z) } -internal actual fun Light.setDirection(direction: Vector3d) { +internal actual fun Light.setDirection(direction: Vector3d) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val nv = allocVec3(direction) + dropbear_lighting_set_direction(world, entity.raw.toULong(), nv.ptr) } -internal actual fun Light.getColour(): Colour { - TODO("Not yet implemented") +internal actual fun Light.getColour(): Colour = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped Colour(255u, 255u, 255u, 255u) + val out = alloc<NColour>() + dropbear_lighting_get_colour(world, entity.raw.toULong(), out.ptr) + readColour(out) } -internal actual fun Light.setColour(colour: Colour) { +internal actual fun Light.setColour(colour: Colour) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val nc = allocColour(colour) + dropbear_lighting_set_colour(world, entity.raw.toULong(), nc.ptr) } -internal actual fun Light.getLightType(): LightType { - TODO("Not yet implemented") +internal actual fun Light.getLightType(): LightType = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped LightType.Directional + val out = alloc<IntVar>() + dropbear_lighting_get_light_type(world, entity.raw.toULong(), out.ptr) + LightType.entries[out.value.coerceIn(0, LightType.entries.lastIndex)] } -internal actual fun Light.setLightType(lightType: LightType) { +internal actual fun Light.setLightType(lightType: LightType) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_lighting_set_light_type(world, entity.raw.toULong(), lightType.ordinal) } -internal actual fun Light.getIntensity(): Double { - TODO("Not yet implemented") +internal actual fun Light.getIntensity(): Double = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped 1.0 + val out = alloc<DoubleVar>() + dropbear_lighting_get_intensity(world, entity.raw.toULong(), out.ptr) + out.value } -internal actual fun Light.setIntensity(intensity: Double) { +internal actual fun Light.setIntensity(intensity: Double) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_lighting_set_intensity(world, entity.raw.toULong(), intensity) } -internal actual fun Light.getAttenuation(): Attenuation { - TODO("Not yet implemented") +internal actual fun Light.getAttenuation(): Attenuation = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped Attenuation() + val out = alloc<NAttenuation>() + dropbear_lighting_get_attenuation(world, entity.raw.toULong(), out.ptr) + Attenuation(out.constant, out.linear, out.quadratic) } -internal actual fun Light.setAttenuation(attenuation: Attenuation) { +internal actual fun Light.setAttenuation(attenuation: Attenuation) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val na = alloc<NAttenuation>() + na.constant = attenuation.constant + na.linear = attenuation.linear + na.quadratic = attenuation.quadratic + dropbear_lighting_set_attenuation(world, entity.raw.toULong(), na.ptr) } -internal actual fun Light.getEnabled(): Boolean { - TODO("Not yet implemented") +internal actual fun Light.getEnabled(): Boolean = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped false + val out = alloc<BooleanVar>() + dropbear_lighting_get_enabled(world, entity.raw.toULong(), out.ptr) + out.value } -internal actual fun Light.setEnabled(enabled: Boolean) { +internal actual fun Light.setEnabled(enabled: Boolean) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_lighting_set_enabled(world, entity.raw.toULong(), enabled) } -internal actual fun Light.getCutoffAngle(): Double { - TODO("Not yet implemented") +internal actual fun Light.getCutoffAngle(): Double = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped 0.0 + val out = alloc<DoubleVar>() + dropbear_lighting_get_cutoff_angle(world, entity.raw.toULong(), out.ptr) + out.value } -internal actual fun Light.setCutoffAngle(cutoffAngle: Double) { +internal actual fun Light.setCutoffAngle(cutoffAngle: Double) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_lighting_set_cutoff_angle(world, entity.raw.toULong(), cutoffAngle) } -internal actual fun Light.getOuterCutoffAngle(): Double { - TODO("Not yet implemented") +internal actual fun Light.getOuterCutoffAngle(): Double = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped 0.0 + val out = alloc<DoubleVar>() + dropbear_lighting_get_outer_cutoff_angle(world, entity.raw.toULong(), out.ptr) + out.value } -internal actual fun Light.setOuterCutoffAngle(outerCutoffAngle: Double) { +internal actual fun Light.setOuterCutoffAngle(outerCutoffAngle: Double) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_lighting_set_outer_cutoff_angle(world, entity.raw.toULong(), outerCutoffAngle) } -internal actual fun Light.getCastShadows(): Boolean { - TODO("Not yet implemented") +internal actual fun Light.getCastShadows(): Boolean = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped false + val out = alloc<BooleanVar>() + dropbear_lighting_get_casts_shadows(world, entity.raw.toULong(), out.ptr) + out.value } -internal actual fun Light.setCastShadows(castShadows: Boolean) { +internal actual fun Light.setCastShadows(castShadows: Boolean) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + dropbear_lighting_set_casts_shadows(world, entity.raw.toULong(), castShadows) } -internal actual fun Light.getDepth(): Range { - TODO("Not yet implemented") +internal actual fun Light.getDepth(): Range = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped Range(0.0, 100.0) + val out = alloc<NRange>() + dropbear_lighting_get_depth(world, entity.raw.toULong(), out.ptr) + Range(out.start.toDouble(), out.end.toDouble()) } -internal actual fun Light.setDepth(depth: Range) { +internal actual fun Light.setDepth(depth: Range) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val nr = alloc<NRange>().also { it.start = depth.start.toFloat(); it.end = depth.end.toFloat() } + dropbear_lighting_set_depth(world, entity.raw.toULong(), nr.ptr) } @@ -1,44 +1,106 @@ +@file:OptIn(ExperimentalForeignApi::class) + package com.dropbear.physics +import com.dropbear.DropbearEngine +import com.dropbear.ffi.generated.NCollider +import com.dropbear.ffi.generated.NShapeCastStatus +import com.dropbear.ffi.generated.NTransform +import com.dropbear.ffi.generated.NVector3 +import com.dropbear.ffi.generated.allocIndexNative +import com.dropbear.ffi.generated.dropbear_character_collision_get_character_collision_collider +import com.dropbear.ffi.generated.dropbear_character_collision_get_character_collision_normal1 +import com.dropbear.ffi.generated.dropbear_character_collision_get_character_collision_normal2 +import com.dropbear.ffi.generated.dropbear_character_collision_get_character_collision_position +import com.dropbear.ffi.generated.dropbear_character_collision_get_character_collision_status +import com.dropbear.ffi.generated.dropbear_character_collision_get_character_collision_time_of_impact +import com.dropbear.ffi.generated.dropbear_character_collision_get_character_collision_translation_applied +import com.dropbear.ffi.generated.dropbear_character_collision_get_character_collision_translation_remaining +import com.dropbear.ffi.generated.dropbear_character_collision_get_character_collision_witness1 +import com.dropbear.ffi.generated.dropbear_character_collision_get_character_collision_witness2 +import com.dropbear.ffi.generated.readCollider +import com.dropbear.ffi.generated.readShapeCastStatus +import com.dropbear.ffi.generated.readTransform import com.dropbear.math.Transform import com.dropbear.math.Vector3d +import kotlinx.cinterop.* -internal actual fun CharacterCollision.getCollider(): Collider { - TODO("Not yet implemented") +internal actual fun CharacterCollision.getCollider(): Collider = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped Collider(Index(0u, 0u), entity, 0u) + val ni = allocIndexNative(collisionHandle) + val out = alloc<NCollider>() + dropbear_character_collision_get_character_collision_collider(world, entity.raw.toULong(), ni.ptr, out.ptr) + readCollider(out) } -internal actual fun CharacterCollision.getCharacterPosition(): Transform { - TODO("Not yet implemented") +internal actual fun CharacterCollision.getCharacterPosition(): Transform = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped Transform.identity() + val ni = allocIndexNative(collisionHandle) + val out = alloc<NTransform>() + dropbear_character_collision_get_character_collision_position(world, entity.raw.toULong(), ni.ptr, out.ptr) + readTransform(out) } -internal actual fun CharacterCollision.getTranslationApplied(): Vector3d { - TODO("Not yet implemented") +internal actual fun CharacterCollision.getTranslationApplied(): Vector3d = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped Vector3d.zero() + val ni = allocIndexNative(collisionHandle) + val out = alloc<NVector3>() + dropbear_character_collision_get_character_collision_translation_applied(world, entity.raw.toULong(), ni.ptr, out.ptr) + Vector3d(out.x, out.y, out.z) } -internal actual fun CharacterCollision.getTranslationRemaining(): Vector3d { - TODO("Not yet implemented") +internal actual fun CharacterCollision.getTranslationRemaining(): Vector3d = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped Vector3d.zero() + val ni = allocIndexNative(collisionHandle) + val out = alloc<NVector3>() + dropbear_character_collision_get_character_collision_translation_remaining(world, entity.raw.toULong(), ni.ptr, out.ptr) + Vector3d(out.x, out.y, out.z) } -internal actual fun CharacterCollision.getTimeOfImpact(): Double { - TODO("Not yet implemented") +internal actual fun CharacterCollision.getTimeOfImpact(): Double = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped 0.0 + val ni = allocIndexNative(collisionHandle) + val out = alloc<DoubleVar>() + dropbear_character_collision_get_character_collision_time_of_impact(world, entity.raw.toULong(), ni.ptr, out.ptr) + out.value } -internal actual fun CharacterCollision.getWitness1(): Vector3d { - TODO("Not yet implemented") +internal actual fun CharacterCollision.getWitness1(): Vector3d = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped Vector3d.zero() + val ni = allocIndexNative(collisionHandle) + val out = alloc<NVector3>() + dropbear_character_collision_get_character_collision_witness1(world, entity.raw.toULong(), ni.ptr, out.ptr) + Vector3d(out.x, out.y, out.z) } -internal actual fun CharacterCollision.getWitness2(): Vector3d { - TODO("Not yet implemented") +internal actual fun CharacterCollision.getWitness2(): Vector3d = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped Vector3d.zero() + val ni = allocIndexNative(collisionHandle) + val out = alloc<NVector3>() + dropbear_character_collision_get_character_collision_witness2(world, entity.raw.toULong(), ni.ptr, out.ptr) + Vector3d(out.x, out.y, out.z) } -internal actual fun CharacterCollision.getNormal1(): Vector3d { - TODO("Not yet implemented") +internal actual fun CharacterCollision.getNormal1(): Vector3d = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped Vector3d.zero() + val ni = allocIndexNative(collisionHandle) + val out = alloc<NVector3>() + dropbear_character_collision_get_character_collision_normal1(world, entity.raw.toULong(), ni.ptr, out.ptr) + Vector3d(out.x, out.y, out.z) } -internal actual fun CharacterCollision.getNormal2(): Vector3d { - TODO("Not yet implemented") +internal actual fun CharacterCollision.getNormal2(): Vector3d = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped Vector3d.zero() + val ni = allocIndexNative(collisionHandle) + val out = alloc<NVector3>() + dropbear_character_collision_get_character_collision_normal2(world, entity.raw.toULong(), ni.ptr, out.ptr) + Vector3d(out.x, out.y, out.z) } -internal actual fun CharacterCollision.getStatus(): ShapeCastStatus { - TODO("Not yet implemented") +internal actual fun CharacterCollision.getStatus(): ShapeCastStatus = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped ShapeCastStatus.Failed + val ni = allocIndexNative(collisionHandle) + val out = alloc<NShapeCastStatus>() + dropbear_character_collision_get_character_collision_status(world, entity.raw.toULong(), ni.ptr, out.ptr) + readShapeCastStatus(out) } @@ -1,81 +1,144 @@ +@file:OptIn(ExperimentalForeignApi::class) + package com.dropbear.physics +import com.dropbear.DropbearEngine +import com.dropbear.ffi.generated.ColliderShapeFfi +import com.dropbear.ffi.generated.NVector3 +import com.dropbear.ffi.generated.allocCollider +import com.dropbear.ffi.generated.allocColliderShape +import com.dropbear.ffi.generated.allocVec3 +import com.dropbear.ffi.generated.dropbear_collider_get_collider_density +import com.dropbear.ffi.generated.dropbear_collider_get_collider_friction +import com.dropbear.ffi.generated.dropbear_collider_get_collider_is_sensor +import com.dropbear.ffi.generated.dropbear_collider_get_collider_mass +import com.dropbear.ffi.generated.dropbear_collider_get_collider_restitution +import com.dropbear.ffi.generated.dropbear_collider_get_collider_rotation +import com.dropbear.ffi.generated.dropbear_collider_get_collider_shape +import com.dropbear.ffi.generated.dropbear_collider_get_collider_translation +import com.dropbear.ffi.generated.dropbear_collider_set_collider_density +import com.dropbear.ffi.generated.dropbear_collider_set_collider_friction +import com.dropbear.ffi.generated.dropbear_collider_set_collider_is_sensor +import com.dropbear.ffi.generated.dropbear_collider_set_collider_mass +import com.dropbear.ffi.generated.dropbear_collider_set_collider_restitution +import com.dropbear.ffi.generated.dropbear_collider_set_collider_rotation +import com.dropbear.ffi.generated.dropbear_collider_set_collider_shape +import com.dropbear.ffi.generated.dropbear_collider_set_collider_translation +import com.dropbear.ffi.generated.readColliderShape import com.dropbear.math.Vector3d +import kotlinx.cinterop.* -internal actual fun Collider.getColliderShape(collider: Collider): ColliderShape { - TODO("Not yet implemented") +internal actual fun Collider.getColliderShape(collider: Collider): ColliderShape = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped ColliderShape.Box(Vector3d.zero()) + val nc = allocCollider(collider) + val out = alloc<ColliderShapeFfi>() + dropbear_collider_get_collider_shape(physics, nc.ptr, out.ptr) + readColliderShape(out) } -internal actual fun Collider.setColliderShape( - collider: Collider, - shape: ColliderShape -) { +internal actual fun Collider.setColliderShape(collider: Collider, shape: ColliderShape) = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + val nc = allocCollider(collider) + val ns = allocColliderShape(shape) + dropbear_collider_set_collider_shape(physics, nc.ptr, ns.ptr) } -internal actual fun Collider.setColliderDensity( - collider: Collider, - density: Double -) { +internal actual fun Collider.setColliderDensity(collider: Collider, density: Double) = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + val nc = allocCollider(collider) + dropbear_collider_set_collider_density(physics, nc.ptr, density) } -internal actual fun Collider.getColliderFriction(collider: Collider): Double { - TODO("Not yet implemented") +internal actual fun Collider.getColliderFriction(collider: Collider): Double = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped 0.0 + val nc = allocCollider(collider) + val out = alloc<DoubleVar>() + dropbear_collider_get_collider_friction(physics, nc.ptr, out.ptr) + out.value } -internal actual fun Collider.setColliderFriction( - collider: Collider, - friction: Double -) { +internal actual fun Collider.setColliderFriction(collider: Collider, friction: Double) = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + val nc = allocCollider(collider) + dropbear_collider_set_collider_friction(physics, nc.ptr, friction) } -internal actual fun Collider.getColliderRestitution(collider: Collider): Double { - TODO("Not yet implemented") +internal actual fun Collider.getColliderRestitution(collider: Collider): Double = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped 0.0 + val nc = allocCollider(collider) + val out = alloc<DoubleVar>() + dropbear_collider_get_collider_restitution(physics, nc.ptr, out.ptr) + out.value } -internal actual fun Collider.setColliderRestitution( - collider: Collider, - restitution: Double -) { +internal actual fun Collider.setColliderRestitution(collider: Collider, restitution: Double) = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + val nc = allocCollider(collider) + dropbear_collider_set_collider_restitution(physics, nc.ptr, restitution) } -internal actual fun Collider.getColliderIsSensor(collider: Collider): Boolean { - TODO("Not yet implemented") +internal actual fun Collider.getColliderIsSensor(collider: Collider): Boolean = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped false + val nc = allocCollider(collider) + val out = alloc<BooleanVar>() + dropbear_collider_get_collider_is_sensor(physics, nc.ptr, out.ptr) + out.value } -internal actual fun Collider.setColliderIsSensor( - collider: Collider, - isSensor: Boolean -) { +internal actual fun Collider.setColliderIsSensor(collider: Collider, isSensor: Boolean) = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + val nc = allocCollider(collider) + dropbear_collider_set_collider_is_sensor(physics, nc.ptr, isSensor) } -internal actual fun Collider.getColliderTranslation(collider: Collider): Vector3d { - TODO("Not yet implemented") +internal actual fun Collider.getColliderTranslation(collider: Collider): Vector3d = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped Vector3d.zero() + val nc = allocCollider(collider) + val out = alloc<NVector3>() + dropbear_collider_get_collider_translation(physics, nc.ptr, out.ptr) + Vector3d(out.x, out.y, out.z) } -internal actual fun Collider.setColliderTranslation( - collider: Collider, - translation: Vector3d -) { +internal actual fun Collider.setColliderTranslation(collider: Collider, translation: Vector3d) = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + val nc = allocCollider(collider) + val nv = allocVec3(translation) + dropbear_collider_set_collider_translation(physics, nc.ptr, nv.ptr) } -internal actual fun Collider.getColliderRotation(collider: Collider): Vector3d { - TODO("Not yet implemented") +internal actual fun Collider.getColliderRotation(collider: Collider): Vector3d = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped Vector3d.zero() + val nc = allocCollider(collider) + val out = alloc<NVector3>() + dropbear_collider_get_collider_rotation(physics, nc.ptr, out.ptr) + Vector3d(out.x, out.y, out.z) } -internal actual fun Collider.setColliderRotation( - collider: Collider, - rotation: Vector3d -) { +internal actual fun Collider.setColliderRotation(collider: Collider, rotation: Vector3d) = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + val nc = allocCollider(collider) + val nv = allocVec3(rotation) + dropbear_collider_set_collider_rotation(physics, nc.ptr, nv.ptr) } -internal actual fun Collider.getColliderMass(collider: Collider): Double { - TODO("Not yet implemented") +internal actual fun Collider.getColliderMass(collider: Collider): Double = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped 0.0 + val nc = allocCollider(collider) + val out = alloc<DoubleVar>() + dropbear_collider_get_collider_mass(physics, nc.ptr, out.ptr) + out.value } -internal actual fun Collider.setColliderMass(collider: Collider, mass: Double) { +internal actual fun Collider.setColliderMass(collider: Collider, mass: Double) = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + val nc = allocCollider(collider) + dropbear_collider_set_collider_mass(physics, nc.ptr, mass) } -internal actual fun Collider.getColliderDensity(collider: Collider): Double { - TODO("Not yet implemented") +internal actual fun Collider.getColliderDensity(collider: Collider): Double = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped 0.0 + val nc = allocCollider(collider) + val out = alloc<DoubleVar>() + dropbear_collider_get_collider_density(physics, nc.ptr, out.ptr) + out.value } - @@ -1,11 +1,27 @@ +@file:OptIn(ExperimentalForeignApi::class) + package com.dropbear.physics +import com.dropbear.DropbearEngine import com.dropbear.EntityId +import com.dropbear.ffi.generated.* +import kotlin.String +import kotlinx.cinterop.* -internal actual fun ColliderGroup.getColliderGroupColliders(colliderGroup: ColliderGroup): List<Collider> { - TODO("Not yet implemented") +internal actual fun ColliderGroup.getColliderGroupColliders(colliderGroup: ColliderGroup): List<Collider> = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped emptyList() + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped emptyList() + val out = alloc<NColliderArray>() + val rc = dropbear_collider_group_get_colliders(world, physics, colliderGroup.entity.raw.toULong(), out.ptr) + if (rc != 0) return@memScoped emptyList() + val ptr = out.values ?: return@memScoped emptyList() + val len = out.length.toInt() + (0 until len).map { i -> readCollider(ptr[i]) } } -internal actual fun colliderGroupExistsForEntity(entityId: EntityId): Boolean { - TODO("Not yet implemented") +internal actual fun colliderGroupExistsForEntity(entityId: EntityId): Boolean = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped false + val out = alloc<BooleanVar>() + dropbear_collider_group_exists_for_entity(world, entityId.raw.toULong(), out.ptr) + out.value } @@ -1,24 +1,66 @@ +@file:OptIn(ExperimentalForeignApi::class) + package com.dropbear.physics +import com.dropbear.DropbearEngine import com.dropbear.EntityId +import com.dropbear.ffi.generated.CharacterCollisionArray +import com.dropbear.ffi.generated.CharacterMovementResult as FfiCharacterMovementResult +import com.dropbear.ffi.generated.NQuaternion +import com.dropbear.ffi.generated.NVector3 +import com.dropbear.ffi.generated.allocIndexNative +import com.dropbear.ffi.generated.dropbear_kcc_get_hit +import com.dropbear.ffi.generated.dropbear_kcc_get_movement_result +import com.dropbear.ffi.generated.dropbear_kcc_kcc_exists_for_entity +import com.dropbear.ffi.generated.dropbear_kcc_move_character +import com.dropbear.ffi.generated.dropbear_kcc_set_rotation import com.dropbear.math.Quaterniond import com.dropbear.math.Vector3d +import kotlinx.cinterop.* -internal actual fun KinematicCharacterController.moveCharacter(dt: Double, translation: Vector3d) { +internal actual fun KinematicCharacterController.moveCharacter(dt: Double, translation: Vector3d) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + val nv = alloc<NVector3>().also { it.x = translation.x; it.y = translation.y; it.z = translation.z } + dropbear_kcc_move_character(world, physics, entity.raw.toULong(), nv.ptr, dt) } -internal actual fun KinematicCharacterController.setRotationNative(rotation: Quaterniond) { - TODO("Not yet implemented") +internal actual fun KinematicCharacterController.setRotationNative(rotation: Quaterniond) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + val nq = alloc<NQuaternion>().also { it.x = rotation.x; it.y = rotation.y; it.z = rotation.z; it.w = rotation.w } + dropbear_kcc_set_rotation(world, physics, entity.raw.toULong(), nq.ptr) } -internal actual fun kccExistsForEntity(entityId: EntityId): Boolean { - TODO("Not yet implemented") +internal actual fun kccExistsForEntity(entityId: EntityId): Boolean = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped false + val out = alloc<BooleanVar>() + dropbear_kcc_kcc_exists_for_entity(world, entityId.raw.toULong(), out.ptr) + out.value } -internal actual fun KinematicCharacterController.getHitsNative(): List<CharacterCollision> { - TODO("Not yet implemented") +internal actual fun KinematicCharacterController.getHitsNative(): List<CharacterCollision> = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped emptyList() + val out = alloc<CharacterCollisionArray>() + val rc = dropbear_kcc_get_hit(world, entity.raw.toULong(), out.ptr) + if (rc != 0) return@memScoped emptyList() + val collisionEntityId = EntityId(out.entity_id.toLong()) + val ptr = out.collisions.values ?: return@memScoped emptyList() + val len = out.collisions.length.toInt() + (0 until len).map { i -> + val idx = ptr[i] + CharacterCollision(collisionEntityId, Index(idx.index, idx.generation)) + } } -internal actual fun KinematicCharacterController.getMovementResult(): CharacterMovementResult? { - TODO("Not yet implemented") +internal actual fun KinematicCharacterController.getMovementResult(): CharacterMovementResult? = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped null + val out = alloc<FfiCharacterMovementResult>() + val present = alloc<BooleanVar>() + val rc = dropbear_kcc_get_movement_result(world, entity.raw.toULong(), out.ptr, present.ptr) + if (rc != 0 || !present.value) null else CharacterMovementResult( + Vector3d(out.translation.x, out.translation.y, out.translation.z), + out.grounded, + out.is_sliding_down_slope, + ) } @@ -1,42 +1,90 @@ +@file:OptIn(ExperimentalForeignApi::class) + package com.dropbear.physics +import com.dropbear.DropbearEngine import com.dropbear.EntityRef +import com.dropbear.ffi.generated.NShapeCastHit +import com.dropbear.ffi.generated.NVector3 +import com.dropbear.ffi.generated.RayHit as FfiRayHit +import com.dropbear.ffi.generated.allocCollider +import com.dropbear.ffi.generated.allocColliderShape +import com.dropbear.ffi.generated.allocVec3 +import com.dropbear.ffi.generated.dropbear_physics_get_gravity +import com.dropbear.ffi.generated.dropbear_physics_is_overlapping +import com.dropbear.ffi.generated.dropbear_physics_is_touching +import com.dropbear.ffi.generated.dropbear_physics_is_triggering +import com.dropbear.ffi.generated.dropbear_physics_raycast +import com.dropbear.ffi.generated.dropbear_physics_set_gravity +import com.dropbear.ffi.generated.dropbear_physics_shape_cast +import com.dropbear.ffi.generated.readCollider +import com.dropbear.ffi.generated.readShapeCastStatus import com.dropbear.math.Vector3d +import kotlinx.cinterop.* -internal actual fun getGravity(): Vector3d { - TODO("Not yet implemented") +internal actual fun getGravity(): Vector3d = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped Vector3d.zero() + val out = alloc<NVector3>() + dropbear_physics_get_gravity(physics, out.ptr) + Vector3d(out.x, out.y, out.z) } -internal actual fun setGravity(gravity: Vector3d) { +internal actual fun setGravity(gravity: Vector3d) = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + val nv = allocVec3(gravity) + dropbear_physics_set_gravity(physics, nv.ptr) } -internal actual fun raycast( - origin: Vector3d, - direction: Vector3d, - toi: Double, - solid: Boolean -): RayHit? { - TODO("Not yet implemented") +internal actual fun raycast(origin: Vector3d, direction: Vector3d, toi: Double, solid: Boolean): RayHit? = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped null + val nOrigin = allocVec3(origin) + val nDir = allocVec3(direction) + val out = alloc<FfiRayHit>() + val present = alloc<BooleanVar>() + val rc = dropbear_physics_raycast(physics, nOrigin.ptr, nDir.ptr, toi, solid, out.ptr, present.ptr) + if (rc != 0 || !present.value) null else RayHit(readCollider(out.collider), out.distance) } -internal actual fun isOverlapping(collider1: Collider, collider2: Collider): Boolean { - TODO("Not implemented yet") +internal actual fun isOverlapping(collider1: Collider, collider2: Collider): Boolean = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped false + val nc1 = allocCollider(collider1) + val nc2 = allocCollider(collider2) + val out = alloc<BooleanVar>() + dropbear_physics_is_overlapping(physics, nc1.ptr, nc2.ptr, out.ptr) + out.value } -internal actual fun isTriggering(collider1: Collider, collider2: Collider): Boolean { - TODO("Not implemented yet") +internal actual fun isTriggering(collider1: Collider, collider2: Collider): Boolean = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped false + val nc1 = allocCollider(collider1) + val nc2 = allocCollider(collider2) + val out = alloc<BooleanVar>() + dropbear_physics_is_triggering(physics, nc1.ptr, nc2.ptr, out.ptr) + out.value } -internal actual fun isTouching(entity1: EntityRef, entity2: EntityRef): Boolean { - TODO("Not implemented yet") +internal actual fun isTouching(entity1: EntityRef, entity2: EntityRef): Boolean = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped false + val out = alloc<BooleanVar>() + dropbear_physics_is_touching(physics, entity1.id.raw.toULong(), entity2.id.raw.toULong(), out.ptr) + out.value } -internal actual fun shapeCast( - origin: Vector3d, - direction: Vector3d, - shape: ColliderShape, - toi: Double, - solid: Boolean -): ShapeCastHit? { - TODO("Not yet implemented") +internal actual fun shapeCast(origin: Vector3d, direction: Vector3d, shape: ColliderShape, toi: Double, solid: Boolean): ShapeCastHit? = memScoped { + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped null + val nOrigin = allocVec3(origin) + val nDir = allocVec3(direction) + val nShape = allocColliderShape(shape) + val out = alloc<NShapeCastHit>() + val present = alloc<BooleanVar>() + val rc = dropbear_physics_shape_cast(physics, nOrigin.ptr, nDir.ptr, nShape.ptr, toi, solid, out.ptr, present.ptr) + if (rc != 0 || !present.value) null else ShapeCastHit( + readCollider(out.collider), + out.distance, + Vector3d(out.witness1.x, out.witness1.y, out.witness1.z), + Vector3d(out.witness2.x, out.witness2.y, out.witness2.z), + Vector3d(out.normal1.x, out.normal1.y, out.normal1.z), + Vector3d(out.normal2.x, out.normal2.y, out.normal2.z), + readShapeCastStatus(out.status), + ) } @@ -1,128 +1,227 @@ +@file:OptIn(ExperimentalForeignApi::class) + package com.dropbear.physics +import com.dropbear.DropbearEngine import com.dropbear.EntityId +import com.dropbear.ffi.generated.AxisLock as FfiAxisLock +import com.dropbear.ffi.generated.NColliderArray +import com.dropbear.ffi.generated.NVector3 +import com.dropbear.ffi.generated.RigidBodyContext +import com.dropbear.ffi.generated.allocCollider +import com.dropbear.ffi.generated.allocRigidBodyCtx +import com.dropbear.ffi.generated.dropbear_rigidbody_apply_impulse +import com.dropbear.ffi.generated.dropbear_rigidbody_apply_torque_impulse +import com.dropbear.ffi.generated.dropbear_rigidbody_exists_for_entity +import com.dropbear.ffi.generated.dropbear_rigidbody_get_rigidbody_angular_damping +import com.dropbear.ffi.generated.dropbear_rigidbody_get_rigidbody_angular_velocity +import com.dropbear.ffi.generated.dropbear_rigidbody_get_rigidbody_ccd_enabled +import com.dropbear.ffi.generated.dropbear_rigidbody_get_rigidbody_children +import com.dropbear.ffi.generated.dropbear_rigidbody_get_rigidbody_gravity_scale +import com.dropbear.ffi.generated.dropbear_rigidbody_get_rigidbody_linear_damping +import com.dropbear.ffi.generated.dropbear_rigidbody_get_rigidbody_linear_velocity +import com.dropbear.ffi.generated.dropbear_rigidbody_get_rigidbody_lock_rotation +import com.dropbear.ffi.generated.dropbear_rigidbody_get_rigidbody_lock_translation +import com.dropbear.ffi.generated.dropbear_rigidbody_get_rigidbody_mode +import com.dropbear.ffi.generated.dropbear_rigidbody_get_rigidbody_sleep +import com.dropbear.ffi.generated.dropbear_rigidbody_set_rigidbody_angular_damping +import com.dropbear.ffi.generated.dropbear_rigidbody_set_rigidbody_angular_velocity +import com.dropbear.ffi.generated.dropbear_rigidbody_set_rigidbody_ccd_enabled +import com.dropbear.ffi.generated.dropbear_rigidbody_set_rigidbody_gravity_scale +import com.dropbear.ffi.generated.dropbear_rigidbody_set_rigidbody_linear_damping +import com.dropbear.ffi.generated.dropbear_rigidbody_set_rigidbody_linear_velocity +import com.dropbear.ffi.generated.dropbear_rigidbody_set_rigidbody_lock_rotation +import com.dropbear.ffi.generated.dropbear_rigidbody_set_rigidbody_lock_translation +import com.dropbear.ffi.generated.dropbear_rigidbody_set_rigidbody_mode +import com.dropbear.ffi.generated.dropbear_rigidbody_set_rigidbody_sleep +import com.dropbear.ffi.generated.IndexNative +import com.dropbear.ffi.generated.readCollider import com.dropbear.math.Vector3d +import kotlinx.cinterop.* -internal actual fun RigidBody.setRigidbodyMode( - rigidBody: RigidBody, - mode: RigidBodyMode -) { -} +private fun MemScope.rbCtx(rb: RigidBody): RigidBodyContext = allocRigidBodyCtx(rb) -internal actual fun RigidBody.getRigidbodyMode(rigidBody: RigidBody): RigidBodyMode { - TODO("Not yet implemented") +internal actual fun RigidBody.getRigidbodyMode(rigidBody: RigidBody): RigidBodyMode = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped RigidBodyMode.Dynamic + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped RigidBodyMode.Dynamic + val ctx = rbCtx(rigidBody) + val out = alloc<IntVar>() + dropbear_rigidbody_get_rigidbody_mode(world, physics, ctx.ptr, out.ptr) + RigidBodyMode.entries[out.value.coerceIn(0, RigidBodyMode.entries.lastIndex)] } -internal actual fun RigidBody.getRigidbodyGravityScale(rigidBody: RigidBody): Double { - TODO("Not yet implemented") +internal actual fun RigidBody.setRigidbodyMode(rigidBody: RigidBody, mode: RigidBodyMode) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + val ctx = rbCtx(rigidBody) + dropbear_rigidbody_set_rigidbody_mode(world, physics, ctx.ptr, mode.ordinal) } -internal actual fun RigidBody.setRigidbodyGravityScale( - rigidBody: RigidBody, - gravityScale: Double -) { +internal actual fun RigidBody.getRigidbodyGravityScale(rigidBody: RigidBody): Double = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped 1.0 + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped 1.0 + val ctx = rbCtx(rigidBody) + val out = alloc<DoubleVar>() + dropbear_rigidbody_get_rigidbody_gravity_scale(world, physics, ctx.ptr, out.ptr) + out.value } -internal actual fun RigidBody.getRigidBodySleep(rigidBody: RigidBody): Boolean { - TODO("Not yet implemented") +internal actual fun RigidBody.setRigidbodyGravityScale(rigidBody: RigidBody, gravityScale: Double) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + dropbear_rigidbody_set_rigidbody_gravity_scale(world, physics, rbCtx(rigidBody).ptr, gravityScale) } -internal actual fun RigidBody.setRigidBodySleep( - rigidBody: RigidBody, - canSleep: Boolean -) { +internal actual fun RigidBody.getRigidBodySleep(rigidBody: RigidBody): Boolean = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped false + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped false + val out = alloc<BooleanVar>() + dropbear_rigidbody_get_rigidbody_sleep(world, physics, rbCtx(rigidBody).ptr, out.ptr) + out.value } -internal actual fun RigidBody.getRigidbodyCcdEnabled(rigidBody: RigidBody): Boolean { - TODO("Not yet implemented") +internal actual fun RigidBody.setRigidBodySleep(rigidBody: RigidBody, canSleep: Boolean) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + dropbear_rigidbody_set_rigidbody_sleep(world, physics, rbCtx(rigidBody).ptr, canSleep) } -internal actual fun RigidBody.setRigidbodyCcdEnabled( - rigidBody: RigidBody, - ccdEnabled: Boolean -) { +internal actual fun RigidBody.getRigidbodyCcdEnabled(rigidBody: RigidBody): Boolean = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped false + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped false + val out = alloc<BooleanVar>() + dropbear_rigidbody_get_rigidbody_ccd_enabled(world, physics, rbCtx(rigidBody).ptr, out.ptr) + out.value } -internal actual fun RigidBody.getRigidbodyLinearVelocity(rigidBody: RigidBody): Vector3d { - TODO("Not yet implemented") +internal actual fun RigidBody.setRigidbodyCcdEnabled(rigidBody: RigidBody, ccdEnabled: Boolean) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + dropbear_rigidbody_set_rigidbody_ccd_enabled(world, physics, rbCtx(rigidBody).ptr, ccdEnabled) } -internal actual fun RigidBody.setRigidbodyLinearDamping( - rigidBody: RigidBody, - linearDamping: Double -) { +internal actual fun RigidBody.getRigidbodyLinearVelocity(rigidBody: RigidBody): Vector3d = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped Vector3d.zero() + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped Vector3d.zero() + val out = alloc<NVector3>() + dropbear_rigidbody_get_rigidbody_linear_velocity(world, physics, rbCtx(rigidBody).ptr, out.ptr) + Vector3d(out.x, out.y, out.z) } -internal actual fun RigidBody.setRigidbodyLinearVelocity( - rigidBody: RigidBody, - linearVelocity: Vector3d -) { +internal actual fun RigidBody.setRigidbodyLinearVelocity(rigidBody: RigidBody, linearVelocity: Vector3d) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + val nv = alloc<NVector3>().also { it.x = linearVelocity.x; it.y = linearVelocity.y; it.z = linearVelocity.z } + dropbear_rigidbody_set_rigidbody_linear_velocity(world, physics, rbCtx(rigidBody).ptr, nv.ptr) } -internal actual fun RigidBody.getRigidbodyAngularVelocity(rigidBody: RigidBody): Vector3d { - TODO("Not yet implemented") +internal actual fun RigidBody.getRigidbodyLinearDamping(rigidBody: RigidBody): Double = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped 0.0 + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped 0.0 + val out = alloc<DoubleVar>() + dropbear_rigidbody_get_rigidbody_linear_damping(world, physics, rbCtx(rigidBody).ptr, out.ptr) + out.value } -internal actual fun RigidBody.setRigidbodyAngularVelocity( - rigidBody: RigidBody, - angularVelocity: Vector3d -) { +internal actual fun RigidBody.setRigidbodyLinearDamping(rigidBody: RigidBody, linearDamping: Double) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + dropbear_rigidbody_set_rigidbody_linear_damping(world, physics, rbCtx(rigidBody).ptr, linearDamping) } -internal actual fun RigidBody.getRigidbodyLinearDamping(rigidBody: RigidBody): Double { - TODO("Not yet implemented") +internal actual fun RigidBody.getRigidbodyAngularVelocity(rigidBody: RigidBody): Vector3d = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped Vector3d.zero() + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped Vector3d.zero() + val out = alloc<NVector3>() + dropbear_rigidbody_get_rigidbody_angular_velocity(world, physics, rbCtx(rigidBody).ptr, out.ptr) + Vector3d(out.x, out.y, out.z) } -internal actual fun RigidBody.getRigidbodyAngularDamping(rigidBody: RigidBody): Double { - TODO("Not yet implemented") +internal actual fun RigidBody.setRigidbodyAngularVelocity(rigidBody: RigidBody, angularVelocity: Vector3d) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + val nv = alloc<NVector3>().also { it.x = angularVelocity.x; it.y = angularVelocity.y; it.z = angularVelocity.z } + dropbear_rigidbody_set_rigidbody_angular_velocity(world, physics, rbCtx(rigidBody).ptr, nv.ptr) } -internal actual fun RigidBody.setRigidbodyAngularDamping( - rigidBody: RigidBody, - angularDamping: Double -) { +internal actual fun RigidBody.getRigidbodyAngularDamping(rigidBody: RigidBody): Double = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped 0.0 + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped 0.0 + val out = alloc<DoubleVar>() + dropbear_rigidbody_get_rigidbody_angular_damping(world, physics, rbCtx(rigidBody).ptr, out.ptr) + out.value } -internal actual fun RigidBody.getRigidbodyLockTranslation(rigidBody: RigidBody): AxisLock { - TODO("Not yet implemented") +internal actual fun RigidBody.setRigidbodyAngularDamping(rigidBody: RigidBody, angularDamping: Double) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + dropbear_rigidbody_set_rigidbody_angular_damping(world, physics, rbCtx(rigidBody).ptr, angularDamping) } -internal actual fun RigidBody.setRigidbodyLockTranslation( - rigidBody: RigidBody, - lockTranslation: AxisLock -) { +internal actual fun RigidBody.getRigidbodyLockTranslation(rigidBody: RigidBody): AxisLock = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped AxisLock() + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped AxisLock() + val out = alloc<FfiAxisLock>() + dropbear_rigidbody_get_rigidbody_lock_translation(world, physics, rbCtx(rigidBody).ptr, out.ptr) + AxisLock(out.x, out.y, out.z) } -internal actual fun RigidBody.getRigidbodyLockRotation(rigidBody: RigidBody): AxisLock { - TODO("Not yet implemented") +internal actual fun RigidBody.setRigidbodyLockTranslation(rigidBody: RigidBody, lockTranslation: AxisLock) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + val al = alloc<FfiAxisLock>().also { it.x = lockTranslation.x; it.y = lockTranslation.y; it.z = lockTranslation.z } + dropbear_rigidbody_set_rigidbody_lock_translation(world, physics, rbCtx(rigidBody).ptr, al.ptr) } -internal actual fun RigidBody.setRigidbodyLockRotation( - rigidBody: RigidBody, - lockRotation: AxisLock -) { +internal actual fun RigidBody.getRigidbodyLockRotation(rigidBody: RigidBody): AxisLock = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped AxisLock() + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped AxisLock() + val out = alloc<FfiAxisLock>() + dropbear_rigidbody_get_rigidbody_lock_rotation(world, physics, rbCtx(rigidBody).ptr, out.ptr) + AxisLock(out.x, out.y, out.z) } -internal actual fun RigidBody.getRigidbodyChildren(rigidBody: RigidBody): List<Collider> { - TODO("Not yet implemented") +internal actual fun RigidBody.setRigidbodyLockRotation(rigidBody: RigidBody, lockRotation: AxisLock) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + val al = alloc<FfiAxisLock>().also { it.x = lockRotation.x; it.y = lockRotation.y; it.z = lockRotation.z } + dropbear_rigidbody_set_rigidbody_lock_rotation(world, physics, rbCtx(rigidBody).ptr, al.ptr) } -internal actual fun RigidBody.applyImpulse( - index: Index, - x: Double, - y: Double, - z: Double -) { +internal actual fun RigidBody.getRigidbodyChildren(rigidBody: RigidBody): List<Collider> = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped emptyList() + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped emptyList() + val out = alloc<NColliderArray>() + val rc = dropbear_rigidbody_get_rigidbody_children(world, physics, rbCtx(rigidBody).ptr, out.ptr) + if (rc != 0) return@memScoped emptyList() + val ptr = out.values ?: return@memScoped emptyList() + val len = out.length.toInt() + (0 until len).map { i -> readCollider(ptr[i]) } } -internal actual fun RigidBody.applyTorqueImpulse( - index: Index, - x: Double, - y: Double, - z: Double -) { +internal actual fun RigidBody.applyImpulse(index: Index, x: Double, y: Double, z: Double) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + val ctx = alloc<RigidBodyContext>() + ctx.index.index = index.index; ctx.index.generation = index.generation + ctx.entity_id = this@applyImpulse.entity.raw.toULong() + dropbear_rigidbody_apply_impulse(world, physics, ctx.ptr, x, y, z) } -internal actual fun rigidBodyExistsForEntity(entityId: EntityId): Index? { - TODO("Not yet implemented") +internal actual fun RigidBody.applyTorqueImpulse(index: Index, x: Double, y: Double, z: Double) = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped + val ctx = alloc<RigidBodyContext>() + ctx.index.index = index.index; ctx.index.generation = index.generation + ctx.entity_id = this@applyTorqueImpulse.entity.raw.toULong() + dropbear_rigidbody_apply_torque_impulse(world, physics, ctx.ptr, x, y, z) +} + +internal actual fun rigidBodyExistsForEntity(entityId: EntityId): Index? = memScoped { + val world = DropbearEngine.native.worldHandle ?: return@memScoped null + val physics = DropbearEngine.native.physicsEngineHandle ?: return@memScoped null + val out = alloc<IndexNative>() + val present = alloc<BooleanVar>() + dropbear_rigidbody_exists_for_entity(world, physics, entityId.raw.toULong(), out.ptr, present.ptr) + if (!present.value) null else Index(out.index, out.generation) } @@ -1,19 +1,44 @@ +@file:OptIn(ExperimentalForeignApi::class) + package com.dropbear.scene +import com.dropbear.DropbearEngine +import com.dropbear.ffi.generated.* +import kotlin.String import com.dropbear.utils.Progress +import kotlinx.cinterop.* internal actual fun SceneLoadHandle.switchToSceneAsync() { - TODO("Not yet implemented") + val cmd = DropbearEngine.native.commandBufferHandle ?: return + val sceneLoader = DropbearEngine.native.sceneLoaderHandle ?: return + memScoped { dropbear_scripting_switch_to_scene_async(cmd, sceneLoader, id.toULong()) } } -internal actual fun SceneLoadHandle.getSceneLoadProgress(): Progress { - TODO("Not yet implemented") +internal actual fun SceneLoadHandle.getSceneLoadProgress(): Progress = memScoped { + val sceneLoader = DropbearEngine.native.sceneLoaderHandle ?: return@memScoped Progress.nothing() + val out = alloc<com.dropbear.ffi.generated.Progress>() + val rc = dropbear_scripting_get_scene_load_progress(sceneLoader, id.toULong(), out.ptr) + if (rc != 0) Progress.nothing() else Progress( + out.current.toDouble(), + out.total.toDouble(), + out.message?.toKString() + ) } -internal actual fun SceneLoadHandle.getSceneLoadStatus(): SceneLoadStatus { - TODO("Not yet implemented") +internal actual fun SceneLoadHandle.getSceneLoadStatus(): SceneLoadStatus = memScoped { + val sceneLoader = DropbearEngine.native.sceneLoaderHandle ?: return@memScoped SceneLoadStatus.FAILED + val out = alloc<UIntVar>() + val rc = dropbear_scripting_get_scene_load_status(sceneLoader, id.toULong(), out.ptr) + if (rc != 0) SceneLoadStatus.FAILED else when (out.value.toInt()) { + 0 -> SceneLoadStatus.PENDING + 1 -> SceneLoadStatus.READY + else -> SceneLoadStatus.FAILED + } } -internal actual fun SceneLoadHandle.getSceneLoadHandleSceneName(id: Long): String { - TODO("Not yet implemented") +internal actual fun SceneLoadHandle.getSceneLoadHandleSceneName(id: Long): String = memScoped { + val sceneLoader = DropbearEngine.native.sceneLoaderHandle ?: return@memScoped "" + val out = alloc<CPointerVar<ByteVar>>() + val rc = dropbear_scripting_get_scene_load_handle_scene_name(sceneLoader, id.toULong(), out.ptr) + if (rc != 0) "" else out.value?.toKString() ?: "" } @@ -1,15 +1,29 @@ +@file:OptIn(ExperimentalForeignApi::class) + package com.dropbear.scene -internal actual fun SceneManager.loadSceneAsyncNative(sceneName: String): SceneLoadHandle? { - TODO("Not yet implemented") +import com.dropbear.DropbearEngine +import com.dropbear.ffi.generated.* +import kotlin.String +import kotlinx.cinterop.* + +internal actual fun SceneManager.loadSceneAsyncNative(sceneName: String): SceneLoadHandle? = memScoped { + val cmd = DropbearEngine.native.commandBufferHandle ?: return@memScoped null + val sceneLoader = DropbearEngine.native.sceneLoaderHandle ?: return@memScoped null + val out = alloc<ULongVar>() + val rc = dropbear_scripting_load_scene_async(cmd, sceneLoader, sceneName, out.ptr) + if (rc != 0) null else SceneLoadHandle(out.value.toLong()) } -internal actual fun SceneManager.loadSceneAsyncNative( - sceneName: String, - loadingScene: String -): SceneLoadHandle? { - TODO("Not yet implemented") +internal actual fun SceneManager.loadSceneAsyncNative(sceneName: String, loadingScene: String): SceneLoadHandle? = memScoped { + val cmd = DropbearEngine.native.commandBufferHandle ?: return@memScoped null + val sceneLoader = DropbearEngine.native.sceneLoaderHandle ?: return@memScoped null + val out = alloc<ULongVar>() + val rc = dropbear_scripting_load_scene_async_with_loading(cmd, sceneLoader, sceneName, loadingScene, out.ptr) + if (rc != 0) null else SceneLoadHandle(out.value.toLong()) } internal actual fun SceneManager.switchToSceneImmediateNative(sceneName: String) { + val cmd = DropbearEngine.native.commandBufferHandle ?: return + memScoped { dropbear_scripting_switch_to_scene_immediate(cmd, sceneName) } } @@ -2,10 +2,6 @@ package com.dropbear.ui import com.dropbear.ui.Response -actual fun Response.getClicked(): Boolean { - TODO("Not yet implemented") -} - -actual fun Response.getHovering(): Boolean { - TODO("Not yet implemented") -} +// UI response queries have no C API yet; always return non-interacted state +actual fun Response.getClicked(): Boolean = false +actual fun Response.getHovering(): Boolean = false @@ -1,8 +1,5 @@ package com.dropbear.ui.widgets import com.dropbear.ui.Response -import com.dropbear.ui.widgets.Rectangle -actual fun Rectangle.getResponse(): Response { - TODO("Not yet implemented") -} +actual fun Rectangle.getResponse(): Response = Response(id) @@ -2,6 +2,4 @@ package com.dropbear.ui.widgets import com.dropbear.ui.Response -actual fun Text.getResponse(): Response { - TODO("Not yet implemented") -} +actual fun Text.getResponse(): Response = Response(id)