tirbofish/dropbear · diff
wip: added JNI "*Native" java files and matched the jvmMain stuff.
todo: implement the rust side, and get `cbindgen` working.
Signature present but could not be verified.
Unverified
@@ -2,7 +2,7 @@ plugins { alias(libs.plugins.kotlinMultiplatform) alias(libs.plugins.kotlinxSerialization) `maven-publish` - id("org.jetbrains.dokka") version "2.0.0" + id("org.jetbrains.dokka") version "2.1.0" } group = "com.dropbear" @@ -36,9 +36,7 @@ val libPathProvider = provider { } kotlin { - jvm { - - } + jvm { } val nativeTarget = when { isMacOs && isArm64 -> macosArm64("nativeLib") @@ -100,7 +98,7 @@ kotlin { sourceSets { commonMain { dependencies { - api("org.jetbrains.kotlinx:kotlinx-datetime:0.6.0") + api("org.jetbrains.kotlinx:kotlinx-datetime:0.7.1") } } nativeMain { @@ -129,7 +127,7 @@ kotlin { } } -val extractJavaSources by tasks.registering(Copy::class) { +val extractJavaSources by tasks.registering(Sync::class) { group = "jni" description = "Copies .java files from jvmMain/kotlin to a temp directory for header generation" @@ -156,12 +154,19 @@ val generateJniHeaders by tasks.registering(JavaCompile::class) { val headerOutputDir = layout.buildDirectory.dir("generated/jni-headers") options.headerOutputDirectory.set(headerOutputDir) + doFirst { + val outDir = headerOutputDir.get().asFile + if (outDir.exists()) { + outDir.deleteRecursively() + outDir.mkdirs() + } + } + doLast { println("Generated JNI Headers at: ${headerOutputDir.get().asFile.absolutePath}") } } - tasks.named("jvmMainClasses") { dependsOn(generateJniHeaders) } @@ -182,8 +187,12 @@ publishing { licenses { license { - name.set("dropbear engine License, Version 1.2") - url.set("https://raw.githubusercontent.com/tirbofish/dropbear/refs/heads/main/LICENSE.md") + name.set("MIT") + url.set("https://opensource.org/license/mit") + } + license { + name.set("Apache-2.0") + url.set("https://www.apache.org/licenses/LICENSE-2.0") } } @@ -381,6 +381,7 @@ impl PlayMode { if let Some(physics_state) = self.pending_physics_state.take() { self.physics_state = physics_state; } + self.has_initial_resize_done = false; if let Some(new_camera) = self.pending_camera.take() { self.active_camera = Some(new_camera); } @@ -6,6 +6,7 @@ pluginManagement { gradlePluginPortal() } } + plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" } @@ -1,90 +0,0 @@ -package com.dropbear - -import com.dropbear.ecs.Component -import com.dropbear.ecs.ComponentType -import com.dropbear.math.Vector3D - -/** - * Describes a 3D camera, as defined in `dropbear_engine::camera::Camera` - */ -class Camera( - internal val entity: EntityId, -): Component(entity, "Camera3D") { - var eye: Vector3D - get() = getCameraEye(entity) - set(value) = setCameraEye(entity, value) - var target: Vector3D - get() = getCameraTarget(entity) - set(value) = setCameraTarget(entity, value) - var up: Vector3D - get() = getCameraUp(entity) - set(value) = setCameraUp(entity, value) - val aspect: Double - get() = getCameraAspect(entity) - var fov_y: Double - get() = getCameraFovY(entity) - set(value) = setCameraFovY(entity, value) - var znear: Double - get() = getCameraZNear(entity) - set(value) = setCameraZNear(entity, value) - var zfar: Double - get() = getCameraZFar(entity) - set(value) = setCameraZFar(entity, value) - var yaw: Double - get() = getCameraYaw(entity) - set(value) = setCameraYaw(entity, value) - var pitch: Double - get() = getCameraPitch(entity) - set(value) = setCameraPitch(entity, value) - var speed: Double - get() = getCameraSpeed(entity) - set(value) = setCameraSpeed(entity, value) - var sensitivity: Double - get() = getCameraSensitivity(entity) - set(value) = setCameraSensitivity(entity, value) - - override fun toString(): String { - return "Camera component of entity $entity \n" + - "eye: $eye\n" + - "target: $target\n" + - "up: $up\n " + - "aspect: $aspect \n" + - "fov_y: $fov_y \n" + - "znear: $znear \n" + - "zfar: $zfar \n" + - "yaw: $yaw \n" + - "pitch: $pitch" + - "speed: $speed" + - "sensitivity: $sensitivity" - } - - companion object : ComponentType<Camera> { - override fun get(entityId: EntityId): Camera? { - return if (cameraExistsForEntity(entityId)) Camera(entityId) else null - } - } -} - -expect fun Camera.getCameraEye(entity: EntityId): Vector3D -expect fun Camera.setCameraEye(entity: EntityId, value: Vector3D) -expect fun Camera.getCameraTarget(entity: EntityId): Vector3D -expect fun Camera.setCameraTarget(entity: EntityId, value: Vector3D) -expect fun Camera.getCameraUp(entity: EntityId): Vector3D -expect fun Camera.setCameraUp(entity: EntityId, value: Vector3D) -expect fun Camera.getCameraAspect(entity: EntityId): Double -expect fun Camera.getCameraFovY(entity: EntityId): Double -expect fun Camera.setCameraFovY(entity: EntityId, value: Double) -expect fun Camera.getCameraZNear(entity: EntityId): Double -expect fun Camera.setCameraZNear(entity: EntityId, value: Double) -expect fun Camera.getCameraZFar(entity: EntityId): Double -expect fun Camera.setCameraZFar(entity: EntityId, value: Double) -expect fun Camera.getCameraYaw(entity: EntityId): Double -expect fun Camera.setCameraYaw(entity: EntityId, value: Double) -expect fun Camera.getCameraPitch(entity: EntityId): Double -expect fun Camera.setCameraPitch(entity: EntityId, value: Double) -expect fun Camera.getCameraSpeed(entity: EntityId): Double -expect fun Camera.setCameraSpeed(entity: EntityId, value: Double) -expect fun Camera.getCameraSensitivity(entity: EntityId): Double -expect fun Camera.setCameraSensitivity(entity: EntityId, value: Double) - -expect fun cameraExistsForEntity(entity: EntityId): Boolean @@ -1,93 +0,0 @@ -package com.dropbear - -import com.dropbear.ecs.Component -import com.dropbear.ecs.ComponentType -import com.dropbear.math.Vector3 - -class CustomProperties(val id: EntityId): Component(id, "CustomProperties") { - /** - * Fetches the property of the ModelProperty component on the entity. - */ - inline fun <reified T> getProperty(key: String): T? { - return when (T::class) { - String::class -> getStringProperty(id.id, key) as T? - Long::class -> getLongProperty(id.id, key) as T? - Int::class -> getIntProperty(id.id, key) as T? - Double::class -> getDoubleProperty(id.id, key) as T? - - Float::class -> getFloatProperty(id.id, key) as T? - Boolean::class -> getBoolProperty(id.id, key) as T? - FloatArray::class -> getVec3Property(id.id, key) as T? - else -> throw IllegalArgumentException("Unsupported property type: ${T::class}") - } - } - - /** - * Sets a property of the ModelProperty component on the entity. - * - * # Supported types - * - [kotlin.String] - * - [kotlin.Long] - * - [kotlin.Int] - * - [kotlin.Double] - * - [kotlin.Float] - * - [kotlin.Boolean] - * - [com.dropbear.math.Vector3] - */ - /** - * Sets a property of the ModelProperty component on the entity. - * - * # Supported types - * - [kotlin.String] - * - [kotlin.Long] - * - [kotlin.Int] - * - [kotlin.Double] - * - [kotlin.Float] - * - [kotlin.Boolean] - * - [com.dropbear.math.Vector3] - */ - fun setProperty(key: String, value: Any) { - when (value) { - is String -> setStringProperty(id.id, key, value) - is Long -> setLongProperty(id.id, key, value) - is Int -> setIntProperty(id.id, key, value) - is Double -> setFloatProperty(id.id, key, value) - is Float -> setFloatProperty(id.id, key, value.toDouble()) - is Boolean -> setBoolProperty(id.id, key, value) - is Vector3<*> -> { - val vec = value.asDoubleVector() - setVec3Property(id.id, key, floatArrayOf(vec.x.toFloat(), vec.y.toFloat(), - vec.z.toFloat() - )) - } - is FloatArray -> { - require(value.size == 3) { "Vec3 property must have exactly 3 elements" } - setVec3Property(id.id, key, value) - } - else -> throw IllegalArgumentException("Unsupported property type: ${value::class}") - } - } - - companion object : ComponentType<CustomProperties> { - override fun get(entityId: EntityId): CustomProperties? { - return if (customPropertiesExistsForEntity(entityId)) CustomProperties(entityId) else null - } - } -} - -expect fun CustomProperties.getStringProperty(entityHandle: Long, label: String): String? -expect fun CustomProperties.getIntProperty(entityHandle: Long, label: String): Int? -expect fun CustomProperties.getLongProperty(entityHandle: Long, label: String): Long? -expect fun CustomProperties.getDoubleProperty(entityHandle: Long, label: String): Double? -expect fun CustomProperties.getFloatProperty(entityHandle: Long, label: String): Float? -expect fun CustomProperties.getBoolProperty(entityHandle: Long, label: String): Boolean? -expect fun CustomProperties.getVec3Property(entityHandle: Long, label: String): FloatArray? - -expect fun CustomProperties.setStringProperty(entityHandle: Long, label: String, value: String) -expect fun CustomProperties.setIntProperty(entityHandle: Long, label: String, value: Int) -expect fun CustomProperties.setLongProperty(entityHandle: Long, label: String, value: Long) -expect fun CustomProperties.setFloatProperty(entityHandle: Long, label: String, value: Double) -expect fun CustomProperties.setBoolProperty(entityHandle: Long, label: String, value: Boolean) -expect fun CustomProperties.setVec3Property(entityHandle: Long, label: String, value: FloatArray) - -expect fun customPropertiesExistsForEntity(entityId: EntityId): Boolean @@ -1,6 +1,7 @@ package com.dropbear import com.dropbear.asset.AssetHandle +import com.dropbear.components.Camera import com.dropbear.ffi.NativeEngine import com.dropbear.input.InputState import com.dropbear.logging.Logger @@ -97,6 +98,5 @@ class DropbearEngine(val native: NativeEngine) { } expect fun getEntity(label: String): Long? -expect fun getCamera(label: String): Camera? expect fun getAsset(eucaURI: String): Long? expect fun quit() @@ -3,4 +3,4 @@ package com.dropbear /** * The ID of an entity (represented as a [Long]) */ -data class EntityId(val id: Long) +data class EntityId(val raw: Long) @@ -1,59 +0,0 @@ -package com.dropbear - -import com.dropbear.ecs.Component -import com.dropbear.ecs.ComponentType -import com.dropbear.math.Transform - -/** - * A component that contains the local and world [Transform] of an entity. - */ -class EntityTransform(val id: EntityId): Component(id, "EntityTransform") { - var local: Transform - get() = getLocalTransform(id) - set(value) = setLocalTransform(id, value) - var world: Transform - get() = getWorldTransform(id) - set(value) = setWorldTransform(id, value) - - override fun toString(): String { - return "EntityTransform(id: $id, local=$local, world=$world)" - } - - /** - * Walks up the world hierarchy to find the transform of the parent, then multiply/add - * to create a propagated [Transform]. - */ - fun propagate(): Transform { - return propagateTransform(id) - } - - /** - * Merges the local and world transforms and return the merged [Transform] - */ - fun sync(): Transform { - val scaledPos = local.position * world.scale - val rotatedPos = world.rotation * scaledPos - val finalPos = world.position + rotatedPos - val finalRot = world.rotation * local.rotation - val finalScale = world.scale * local.scale - return Transform(finalPos, finalRot, finalScale) - } - - companion object : ComponentType<EntityTransform> { - override fun get(entityId: EntityId): EntityTransform? { - return if (entityTransformExistsForEntity(entityId)) { - EntityTransform(entityId) - } else { - null - } - } - } -} - -expect fun EntityTransform.getLocalTransform(entityId: EntityId): Transform -expect fun EntityTransform.setLocalTransform(entityId: EntityId, transform: Transform) -expect fun EntityTransform.getWorldTransform(entityId: EntityId): Transform -expect fun EntityTransform.setWorldTransform(entityId: EntityId, transform: Transform) -expect fun EntityTransform.propagateTransform(entityId: EntityId): Transform - -expect fun entityTransformExistsForEntity(entityId: EntityId): Boolean @@ -1,72 +0,0 @@ -package com.dropbear - -import com.dropbear.asset.ModelHandle -import com.dropbear.asset.TextureHandle -import com.dropbear.ecs.Component -import com.dropbear.ecs.ComponentType - -class MeshRenderer(val id: EntityId) : Component(id, "MeshRenderer") { - - /** - * The active model currently assigned to this entity. - * Setting this to null removes the model. - * - * Usage: - * ``` - * val handle = renderer.model - * renderer.model = newHandle - * ``` - */ - var model: ModelHandle? - get() { - return getModel(id) - } - set(value) { - setModel(id, value) - } - - /** - * A list of all active Texture handles currently applied to the model. - */ - val textures: List<TextureHandle>? - get() = getAllTextureIds(id) - - /** - * Returns a list of material names available on the current model. - * Useful for knowing what keys to use in [getTexture] or [setTextureOverride]. - */ - val materialNames: List<String> - get() = getMaterialNames(id) - - /** - * Fetches the texture assigned to a specific material slot. - * Returns null if the material doesn't exist or has no texture. - */ - fun getTexture(materialName: String): TextureHandle? { - val rawId = getTexture(id, materialName) - return if (rawId == 0L) null else TextureHandle(rawId) - } - - /** - * Overrides the texture for a specific material on the active model. - */ - fun setTextureOverride(materialName: String, textureHandle: TextureHandle) { - setTextureOverride(id, materialName, textureHandle.raw()) - } - - companion object : ComponentType<MeshRenderer> { - override fun get(entityId: EntityId): MeshRenderer? { - return if (meshRendererExistsForEntity(entityId)) MeshRenderer(entityId) else null - } - } -} - -expect fun MeshRenderer.getModel(id: EntityId): ModelHandle? -expect fun MeshRenderer.setModel(id: EntityId, model: ModelHandle?) -expect fun MeshRenderer.getAllTextureIds(id: EntityId): List<TextureHandle>? -expect fun MeshRenderer.getMaterialNames(id: EntityId): List<String> -expect fun MeshRenderer.setMaterialNames(id: EntityId, names: Array<String>) -expect fun MeshRenderer.getTexture(id: EntityId, materialName: String): Long -expect fun MeshRenderer.setTextureOverride(id: EntityId, materialName: String, textureHandle: Long) - -expect fun meshRendererExistsForEntity(entityId: EntityId): Boolean @@ -24,16 +24,20 @@ class AssetHandle(private val id: Long): Handle(id) { return this } + /** + * Converts an [AssetHandle] to a [TextureHandle]. + * + * It can return null if the asset is not a texture. + */ + fun asTextureHandle(): TextureHandle? { + return if (isTextureHandle(id)) TextureHandle(id) else null + } + override fun toString(): String { return "AssetHandle(id=$id)" } } -/** - * Converts an [AssetHandle] to a [TextureHandle]. - * - * It can return null if the asset is not a texture. - */ -expect fun AssetHandle.asTextureHandle(): TextureHandle? +expect fun isTextureHandle(id: Long): Boolean expect fun isModelHandle(id: Long): Boolean @@ -5,8 +5,14 @@ package com.dropbear.asset * * Aims to allow people to group up different handle types ([AssetHandle], [ModelHandle] etc...) * into a list or a vector. + * + * All handles must be positive, non-zero values. If the id does not follow that rule, it is considered invalid. */ abstract class Handle(private val id: Long) { + init { + require(id > 0) { "Handle id must be a positive, non-zero value. Got: $id" } + } + /** * Returns the raw id of the handle */ @@ -1,7 +1,5 @@ package com.dropbear.asset -import com.dropbear.DropbearEngine - /** * Another type of asset handle, this wraps the id into * another form that only texture related functions can use. @@ -0,0 +1,91 @@ +package com.dropbear.components + +import com.dropbear.EntityId +import com.dropbear.ecs.Component +import com.dropbear.ecs.ComponentType +import com.dropbear.math.Vector3d + +/** + * Describes a 3D camera, as defined in `dropbear_engine::camera::Camera` + */ +class Camera( + internal val entity: EntityId, +): Component(entity, "Camera3D") { + var eye: Vector3d + get() = getCameraEye(entity) + set(value) = setCameraEye(entity, value) + var target: Vector3d + get() = getCameraTarget(entity) + set(value) = setCameraTarget(entity, value) + var up: Vector3d + get() = getCameraUp(entity) + set(value) = setCameraUp(entity, value) + val aspect: Double + get() = getCameraAspect(entity) + var fov_y: Double + get() = getCameraFovY(entity) + set(value) = setCameraFovY(entity, value) + var znear: Double + get() = getCameraZNear(entity) + set(value) = setCameraZNear(entity, value) + var zfar: Double + get() = getCameraZFar(entity) + set(value) = setCameraZFar(entity, value) + var yaw: Double + get() = getCameraYaw(entity) + set(value) = setCameraYaw(entity, value) + var pitch: Double + get() = getCameraPitch(entity) + set(value) = setCameraPitch(entity, value) + var speed: Double + get() = getCameraSpeed(entity) + set(value) = setCameraSpeed(entity, value) + var sensitivity: Double + get() = getCameraSensitivity(entity) + set(value) = setCameraSensitivity(entity, value) + + override fun toString(): String { + return "Camera component of entity $entity \n" + + "eye: $eye\n" + + "target: $target\n" + + "up: $up\n " + + "aspect: $aspect \n" + + "fov_y: $fov_y \n" + + "znear: $znear \n" + + "zfar: $zfar \n" + + "yaw: $yaw \n" + + "pitch: $pitch" + + "speed: $speed" + + "sensitivity: $sensitivity" + } + + companion object : ComponentType<Camera> { + override fun get(entityId: EntityId): Camera? { + return if (cameraExistsForEntity(entityId)) Camera(entityId) else null + } + } +} + +expect fun Camera.getCameraEye(entity: EntityId): Vector3d +expect fun Camera.setCameraEye(entity: EntityId, value: Vector3d) +expect fun Camera.getCameraTarget(entity: EntityId): Vector3d +expect fun Camera.setCameraTarget(entity: EntityId, value: Vector3d) +expect fun Camera.getCameraUp(entity: EntityId): Vector3d +expect fun Camera.setCameraUp(entity: EntityId, value: Vector3d) +expect fun Camera.getCameraAspect(entity: EntityId): Double +expect fun Camera.getCameraFovY(entity: EntityId): Double +expect fun Camera.setCameraFovY(entity: EntityId, value: Double) +expect fun Camera.getCameraZNear(entity: EntityId): Double +expect fun Camera.setCameraZNear(entity: EntityId, value: Double) +expect fun Camera.getCameraZFar(entity: EntityId): Double +expect fun Camera.setCameraZFar(entity: EntityId, value: Double) +expect fun Camera.getCameraYaw(entity: EntityId): Double +expect fun Camera.setCameraYaw(entity: EntityId, value: Double) +expect fun Camera.getCameraPitch(entity: EntityId): Double +expect fun Camera.setCameraPitch(entity: EntityId, value: Double) +expect fun Camera.getCameraSpeed(entity: EntityId): Double +expect fun Camera.setCameraSpeed(entity: EntityId, value: Double) +expect fun Camera.getCameraSensitivity(entity: EntityId): Double +expect fun Camera.setCameraSensitivity(entity: EntityId, value: Double) + +expect fun cameraExistsForEntity(entity: EntityId): Boolean @@ -0,0 +1,99 @@ +package com.dropbear.components + +import com.dropbear.EntityId +import com.dropbear.ecs.Component +import com.dropbear.ecs.ComponentType +import com.dropbear.math.Vector3d +import com.dropbear.math.Vector3f +import com.dropbear.math.Vector3i + +class CustomProperties(val id: EntityId): Component(id, "CustomProperties") { + /** + * Fetches the property of the ModelProperty component on the entity. + * + * @param T The type of the property to fetch. + * # Supported types + * - [kotlin.String] + * - [Long] + * - [Int] + * - [Double] + * - [Float] + * - [Boolean] + * - [Vector3d] + * - [Vector3f] + * - [Vector3i] + * @param key The key of the property to fetch. + * @return The property value, or null if the property does not exist. + * @throws IllegalArgumentException if the property type is not supported. + */ + inline fun <reified T> getProperty(key: String): T? { + return when (T::class) { + String::class -> getStringProperty(id.raw, key) as T? + Long::class -> getLongProperty(id.raw, key) as T? + Int::class -> getIntProperty(id.raw, key) as T? + Double::class -> getDoubleProperty(id.raw, key) as T? + + Float::class -> getFloatProperty(id.raw, key) as T? + Boolean::class -> getBoolProperty(id.raw, key) as T? + Vector3d::class -> getVec3Property(id.raw, key) as T? + Vector3f::class -> getVec3Property(id.raw, key)?.toFloat() as T? + Vector3i::class -> getVec3Property(id.raw, key)?.toInt() as T? + else -> throw IllegalArgumentException("Unsupported property type: ${T::class}") + } + } + + /** + * Sets a property of the ModelProperty component on the entity. + * + * @param key The key of the property to set. + * @param value The type of the property to set. + * # Supported types + * - [kotlin.String] + * - [Long] + * - [Int] + * - [Double] + * - [Float] + * - [Boolean] + * - [Vector3d] + * - [Vector3f] + * - [Vector3i] + * @throws IllegalArgumentException if the property type is not supported. + */ + fun setProperty(key: String, value: Any) { + when (value) { + is String -> setStringProperty(id.raw, key, value) + is Long -> setLongProperty(id.raw, key, value) + is Int -> setIntProperty(id.raw, key, value) + is Double -> setFloatProperty(id.raw, key, value) + is Float -> setFloatProperty(id.raw, key, value.toDouble()) + is Boolean -> setBoolProperty(id.raw, key, value) + is Vector3d -> setVec3Property(id.raw, key, value) + is Vector3f -> setVec3Property(id.raw ,key, value.toDouble()) + is Vector3i -> setVec3Property(id.raw, key, value.toDouble()) + else -> throw IllegalArgumentException("Unsupported property type: ${value::class}") + } + } + + companion object : ComponentType<CustomProperties> { + override fun get(entityId: EntityId): CustomProperties? { + return if (customPropertiesExistsForEntity(entityId)) CustomProperties(entityId) else null + } + } +} + +expect fun CustomProperties.getStringProperty(entityHandle: Long, label: String): String? +expect fun CustomProperties.getIntProperty(entityHandle: Long, label: String): Int? +expect fun CustomProperties.getLongProperty(entityHandle: Long, label: String): Long? +expect fun CustomProperties.getDoubleProperty(entityHandle: Long, label: String): Double? +expect fun CustomProperties.getFloatProperty(entityHandle: Long, label: String): Float? +expect fun CustomProperties.getBoolProperty(entityHandle: Long, label: String): Boolean? +expect fun CustomProperties.getVec3Property(entityHandle: Long, label: String): Vector3d? + +expect fun CustomProperties.setStringProperty(entityHandle: Long, label: String, value: String) +expect fun CustomProperties.setIntProperty(entityHandle: Long, label: String, value: Int) +expect fun CustomProperties.setLongProperty(entityHandle: Long, label: String, value: Long) +expect fun CustomProperties.setFloatProperty(entityHandle: Long, label: String, value: Double) +expect fun CustomProperties.setBoolProperty(entityHandle: Long, label: String, value: Boolean) +expect fun CustomProperties.setVec3Property(entityHandle: Long, label: String, value: Vector3d) + +expect fun customPropertiesExistsForEntity(entityId: EntityId): Boolean @@ -0,0 +1,60 @@ +package com.dropbear.components + +import com.dropbear.EntityId +import com.dropbear.ecs.Component +import com.dropbear.ecs.ComponentType +import com.dropbear.math.Transform + +/** + * A component that contains the local and world [Transform] of an entity. + */ +class EntityTransform(val id: EntityId): Component(id, "EntityTransform") { + var local: Transform + get() = getLocalTransform(id) + set(value) = setLocalTransform(id, value) + var world: Transform + get() = getWorldTransform(id) + set(value) = setWorldTransform(id, value) + + override fun toString(): String { + return "EntityTransform(id: $id, local=$local, world=$world)" + } + + /** + * Walks up the world hierarchy to find the transform of the parent, then multiply/add + * to create a propagated [Transform]. + */ + fun propagate(): Transform { + return propagateTransform(id) + } + + /** + * Merges the local and world transforms and return the merged [Transform] + */ + fun sync(): Transform { + val scaledPos = local.position * world.scale + val rotatedPos = world.rotation * scaledPos + val finalPos = world.position + rotatedPos + val finalRot = world.rotation * local.rotation + val finalScale = world.scale * local.scale + return Transform(finalPos, finalRot, finalScale) + } + + companion object : ComponentType<EntityTransform> { + override fun get(entityId: EntityId): EntityTransform? { + return if (entityTransformExistsForEntity(entityId)) { + EntityTransform(entityId) + } else { + null + } + } + } +} + +expect fun EntityTransform.getLocalTransform(entityId: EntityId): Transform +expect fun EntityTransform.setLocalTransform(entityId: EntityId, transform: Transform) +expect fun EntityTransform.getWorldTransform(entityId: EntityId): Transform +expect fun EntityTransform.setWorldTransform(entityId: EntityId, transform: Transform) +expect fun EntityTransform.propagateTransform(entityId: EntityId): Transform + +expect fun entityTransformExistsForEntity(entityId: EntityId): Boolean @@ -0,0 +1,64 @@ +package com.dropbear.components + +import com.dropbear.EntityId +import com.dropbear.asset.ModelHandle +import com.dropbear.asset.TextureHandle +import com.dropbear.ecs.Component +import com.dropbear.ecs.ComponentType + +class MeshRenderer(val id: EntityId) : Component(id, "MeshRenderer") { + + /** + * The active model currently assigned to this entity. + * Setting this to null removes the model. + * + * Usage: + * ``` + * val handle = renderer.model + * renderer.model = newHandle + * ``` + */ + var model: ModelHandle? + get() { + return getModel(id) + } + set(value) { + setModel(id, value) + } + + /** + * A list of all active Texture handles currently applied to the model. + */ + val textures: List<TextureHandle>? + get() = getAllTextureIds(id) + + /** + * Fetches the texture assigned to a specific material slot. + * Returns null if the material doesn't exist or has no texture. + */ + fun getTexture(materialName: String): TextureHandle? { + val rawId = getTexture(id, materialName) + return if (rawId == 0L) null else TextureHandle(rawId) + } + + /** + * Overrides the texture for a specific material on the active model. + */ + fun setTextureOverride(materialName: String, textureHandle: TextureHandle) { + setTextureOverride(id, materialName, textureHandle.raw()) + } + + companion object : ComponentType<MeshRenderer> { + override fun get(entityId: EntityId): MeshRenderer? { + return if (meshRendererExistsForEntity(entityId)) MeshRenderer(entityId) else null + } + } +} + +expect fun MeshRenderer.getModel(id: EntityId): ModelHandle? +expect fun MeshRenderer.setModel(id: EntityId, model: ModelHandle?) +expect fun MeshRenderer.getAllTextureIds(id: EntityId): List<TextureHandle>? +expect fun MeshRenderer.getTexture(id: EntityId, materialName: String): Long +expect fun MeshRenderer.setTextureOverride(id: EntityId, materialName: String, textureHandle: Long) + +expect fun meshRendererExistsForEntity(entityId: EntityId): Boolean @@ -1,23 +1,28 @@ package com.dropbear.input import com.dropbear.ffi.NativeEngine -import com.dropbear.math.Vector2D +import com.dropbear.math.Vector2d /** * Information about a specific gamepad for that time in frame. */ class Gamepad( val id: Long, - val leftStickPosition: Vector2D, - val rightStickPosition: Vector2D, ) { + val leftStickPosition: Vector2d + get() = getLeftStickPosition(id) + val rightStickPosition: Vector2d + get() = getRightStickPosition(id) + fun isButtonPressed(button: GamepadButton): Boolean { return isGamepadButtonPressed(id, button) } override fun toString(): String { - return "Gamepad $id @ ($leftStickPosition ; $rightStickPosition)" + return "Gamepad(id=$id)" } } -expect fun Gamepad.isGamepadButtonPressed(id: Long, button: GamepadButton): Boolean +expect fun Gamepad.isGamepadButtonPressed(id: Long, button: GamepadButton): Boolean +expect fun Gamepad.getLeftStickPosition(id: Long): Vector2d +expect fun Gamepad.getRightStickPosition(id: Long): Vector2d @@ -1,8 +1,6 @@ package com.dropbear.input -import com.dropbear.DropbearEngine -import com.dropbear.ffi.NativeEngine -import com.dropbear.math.Vector2D +import com.dropbear.math.Vector2d /** * The current state of the input system. @@ -16,12 +14,12 @@ import com.dropbear.math.Vector2D expect class InputState() { fun printInputState() fun isKeyPressed(key: KeyCode): Boolean - fun getMousePosition(): Vector2D + fun getMousePosition(): Vector2d fun isMouseButtonPressed(button: MouseButton): Boolean - fun getMouseDelta(): Vector2D + fun getMouseDelta(): Vector2d fun isCursorLocked(): Boolean fun setCursorLocked(locked: Boolean) - fun getLastMousePos(): Vector2D + fun getLastMousePos(): Vector2d fun isCursorHidden(): Boolean fun setCursorHidden(hidden: Boolean) fun getConnectedGamepads(): List<Gamepad> @@ -1,18 +1,12 @@ package com.dropbear.math import kotlin.jvm.JvmField -import kotlin.math.PI -import kotlin.math.acos -import kotlin.math.asin -import kotlin.math.atan2 -import kotlin.math.cos -import kotlin.math.max -import kotlin.math.min -import kotlin.math.sin -import kotlin.math.sqrt - -typealias QuaternionD = Quaternion<Double> +import kotlin.jvm.JvmStatic +/** + * Generic Quaternion wrapper. + * WARNING: Uses boxing. Prefer [Quaterniond]/[Quaternionf] for performance. + */ class Quaternion<T: Number>( @JvmField var x: T, @JvmField var y: T, @@ -20,322 +14,34 @@ class Quaternion<T: Number>( @JvmField var w: T ) { companion object { - fun identity(): QuaternionD { - return Quaternion(0.0, 0.0, 0.0, 1.0) - } - - fun fromEulerAngles(pitch: Double, yaw: Double, roll: Double): QuaternionD { - val halfPitch = pitch * 0.5 - val halfYaw = yaw * 0.5 - val halfRoll = roll * 0.5 - val sp = sin(halfPitch) - val cp = cos(halfPitch) - val sy = sin(halfYaw) - val cy = cos(halfYaw) - val sr = sin(halfRoll) - val cr = cos(halfRoll) - - return Quaternion( - x = cy * sr * cp - sy * cr * sp, - y = sy * cr * cp + cy * sr * sp, - z = sy * sr * cp - cy * cr * sp, - w = cy * cr * cp + sy * sr * sp - ) - } - - fun fromAxisAngle(axis: Vector3<Double>, angleRadians: Double): QuaternionD { - val normalizedAxis = axis.normalizedCopy() - val halfAngle = angleRadians * 0.5 - val sinHalf = sin(halfAngle) - return Quaternion( - normalizedAxis.x * sinHalf, - normalizedAxis.y * sinHalf, - normalizedAxis.z * sinHalf, - cos(halfAngle) - ) - } - - fun rotateX(angleRadians: Double): QuaternionD { - return fromAxisAngle(Vector3D(1.0, 0.0, 0.0), angleRadians) - } - - fun rotateY(angleRadians: Double): QuaternionD { - return fromAxisAngle(Vector3D(0.0, 1.0, 0.0), angleRadians) - } - - fun rotateZ(angleRadians: Double): QuaternionD { - return fromAxisAngle(Vector3D(0.0, 0.0, 1.0), angleRadians) - } - - fun fromToRotation(from: Vector3<Double>, to: Vector3<Double>): QuaternionD { - val start = from.normalizedCopy() - val end = to.normalizedCopy() - val dot = (start.x * end.x) + (start.y * end.y) + (start.z * end.z) - if (dot >= 1.0 - 1e-6) { - return identity() - } - if (dot <= -1.0 + 1e-6) { - val orthogonal = if (kotlin.math.abs(start.x) < 0.9) { - Vector3D(1.0, 0.0, 0.0) - } else { - Vector3D(0.0, 1.0, 0.0) - } - val axis = start.cross(orthogonal).normalizedCopy() - return fromAxisAngle(axis, PI) - } - val axis = start.cross(end) - val angle = acos(dot.coerceIn(-1.0, 1.0)) - return fromAxisAngle(axis, angle) - } - } - - fun <T : Number> rotateX(angleRadians: T): Quaternion<T> { - val halfAngle = angleRadians.toDouble() * 0.5 - @Suppress("UNCHECKED_CAST") - return Quaternion(sin(halfAngle), 0.0, 0.0, cos(halfAngle)) as Quaternion<T> - } - - fun <T: Number> rotateY(angleRadians: T): Quaternion<T> { - val halfAngle = angleRadians.toDouble() * 0.5 - @Suppress("UNCHECKED_CAST") - return Quaternion(0.0, sin(halfAngle), 0.0, cos(halfAngle)) as Quaternion<T> - } - - fun <T: Number> rotateZ(angleRadians: T): Quaternion<T> { - val halfAngle = angleRadians.toDouble() * 0.5 - @Suppress("UNCHECKED_CAST") - return Quaternion(0.0, 0.0, sin(halfAngle), cos(halfAngle)) as Quaternion<T> - } - - fun asDoubleQuaternion(): QuaternionD { - return Quaternion(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble()) - } - - fun conjugate(): QuaternionD { - return Quaternion(-x.toDouble(), -y.toDouble(), -z.toDouble(), w.toDouble()) - } - - fun dot(other: Quaternion<*>): Double { - return x.toDouble() * other.x.toDouble() + - y.toDouble() * other.y.toDouble() + - z.toDouble() * other.z.toDouble() + - w.toDouble() * other.w.toDouble() - } - - fun lengthSquared(): Double { - return dot(this) - } - - fun length(): Double { - return sqrt(lengthSquared()) - } - - fun isNormalized(epsilon: Double = 1e-6): Boolean { - return kotlin.math.abs(length() - 1.0) <= epsilon - } - - fun normalized(): QuaternionD { - val len = length() - if (len == 0.0) { - return identity() - } - val invLen = 1.0 / len - return Quaternion( - x.toDouble() * invLen, - y.toDouble() * invLen, - z.toDouble() * invLen, - w.toDouble() * invLen - ) - } - - fun normalizeInPlace(): Quaternion<T> { - val normalized = normalized() - @Suppress("UNCHECKED_CAST") - x = normalized.x as T - @Suppress("UNCHECKED_CAST") - y = normalized.y as T - @Suppress("UNCHECKED_CAST") - z = normalized.z as T - @Suppress("UNCHECKED_CAST") - w = normalized.w as T - return this - } - - operator fun <R: Number> plus(other: Quaternion<R>): QuaternionD { - return Quaternion( - x.toDouble() + other.x.toDouble(), - y.toDouble() + other.y.toDouble(), - z.toDouble() + other.z.toDouble(), - w.toDouble() + other.w.toDouble() - ) - } - - operator fun <R: Number> minus(other: Quaternion<R>): QuaternionD { - return Quaternion( - x.toDouble() - other.x.toDouble(), - y.toDouble() - other.y.toDouble(), - z.toDouble() - other.z.toDouble(), - w.toDouble() - other.w.toDouble() - ) - } - - operator fun unaryMinus(): QuaternionD { - return Quaternion(-x.toDouble(), -y.toDouble(), -z.toDouble(), -w.toDouble()) - } - - operator fun times(scalar: Number): QuaternionD { - val value = scalar.toDouble() - return Quaternion( - x.toDouble() * value, - y.toDouble() * value, - z.toDouble() * value, - w.toDouble() * value - ) - } - - operator fun div(scalar: Number): QuaternionD { - val value = scalar.toDouble() - require(value != 0.0) { "Cannot divide Quaternion by zero." } - val inv = 1.0 / value - return Quaternion( - x.toDouble() * inv, - y.toDouble() * inv, - z.toDouble() * inv, - w.toDouble() * inv - ) - } - - operator fun <R: Number> times(other: Quaternion<R>): QuaternionD { - val ax = x.toDouble() - val ay = y.toDouble() - val az = z.toDouble() - val aw = w.toDouble() - val bx = other.x.toDouble() - val by = other.y.toDouble() - val bz = other.z.toDouble() - val bw = other.w.toDouble() - return Quaternion( - aw * bx + ax * bw + ay * bz - az * by, - aw * by - ax * bz + ay * bw + az * bx, - aw * bz + ax * by - ay * bx + az * bw, - aw * bw - ax * bx - ay * by - az * bz - ) - } - - fun inverse(): QuaternionD { - val lenSq = lengthSquared() - if (lenSq == 0.0) { - return identity() - } - val conjugate = conjugate() - val inv = 1.0 / lenSq - return Quaternion( - conjugate.x * inv, - conjugate.y * inv, - conjugate.z * inv, - conjugate.w * inv - ) - } + @JvmStatic + fun identity(): Quaternion<Double> = Quaternion(0.0, 0.0, 0.0, 1.0) - fun rotate(vector: Vector3<T>): Vector3<Double> { - val doubleVector = vector.asDoubleVector() - val vectorQuat = Quaternion(doubleVector.x, doubleVector.y, doubleVector.z, 0.0) - val rotated = (this * vectorQuat) * conjugate() - return Vector3(rotated.x, rotated.y, rotated.z) - } - - operator fun times(vector: Vector3<T>): Vector3<Double> { - return rotate(vector) - } - - fun nlerp(other: Quaternion<*>, t: Double): QuaternionD { - val alpha = t.coerceIn(0.0, 1.0) - val inverse = 1.0 - alpha - return Quaternion( - x.toDouble() * inverse + other.x.toDouble() * alpha, - y.toDouble() * inverse + other.y.toDouble() * alpha, - z.toDouble() * inverse + other.z.toDouble() * alpha, - w.toDouble() * inverse + other.w.toDouble() * alpha - ).normalized() - } - - fun slerp(other: Quaternion<*>, t: Double): QuaternionD { - val alpha = t.coerceIn(0.0, 1.0) - var q1 = normalized() - var q2 = Quaternion( - other.x.toDouble(), - other.y.toDouble(), - other.z.toDouble(), - other.w.toDouble() - ).normalized() - - var dot = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w - if (dot < 0.0) { - dot = -dot - q2 = Quaternion(-q2.x, -q2.y, -q2.z, -q2.w) - } - - dot = min(1.0, max(-1.0, dot)) - - if (dot > 0.9995) { - return Quaternion( - q1.x + alpha * (q2.x - q1.x), - q1.y + alpha * (q2.y - q1.y), - q1.z + alpha * (q2.z - q1.z), - q1.w + alpha * (q2.w - q1.w) - ).normalized() + @JvmStatic + fun fromEulerAngles(pitch: Double, yaw: Double, roll: Double): Quaternion<Double> { + return Quaterniond.fromEulerAngles(pitch, yaw, roll).toGeneric() } - - val theta0 = acos(dot) - val sinTheta0 = sin(theta0) - val theta = theta0 * alpha - val sinTheta = sin(theta) - val s0 = cos(theta) - dot * sinTheta / sinTheta0 - val s1 = sinTheta / sinTheta0 - - return Quaternion( - q1.x * s0 + q2.x * s1, - q1.y * s0 + q2.y * s1, - q1.z * s0 + q2.z * s1, - q1.w * s0 + q2.w * s1 - ).normalized() } - fun toEulerAngles(): Vector3D { - val q = normalized() - val xx = q.x * q.x - val yy = q.y * q.y - val zz = q.z * q.z - - val sinPitch = 2.0 * (q.w * q.x - q.y * q.z) - val pitch = asin(max(-1.0, min(1.0, sinPitch))) - - val sinYaw = 2.0 * (q.w * q.y + q.z * q.x) - val cosYaw = 1.0 - 2.0 * (xx + zz) - val yaw = atan2(sinYaw, cosYaw) + fun asQuaterniond() = Quaterniond(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble()) + fun asQuaternionf() = Quaternionf(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat()) - val sinRoll = 2.0 * (q.w * q.z + q.x * q.y) - val cosRoll = 1.0 - 2.0 * (yy + xx) - val roll = atan2(sinRoll, cosRoll) + fun normalize(): Quaternion<Double> = asQuaterniond().normalize().toGeneric() + fun inverse(): Quaternion<Double> = asQuaterniond().inverse().toGeneric() - return Vector3D(pitch, yaw, roll) - } - - fun toAxisAngle(): Pair<Vector3D, Double> { - val q = normalized() - val angle = 2.0 * acos(q.w) - val sinHalfAngle = sqrt(1.0 - q.w * q.w) - if (sinHalfAngle < 1e-6) { - return Vector3D(1.0, 0.0, 0.0) to angle - } - return Vector3D(q.x / sinHalfAngle, q.y / sinHalfAngle, q.z / sinHalfAngle) to angle - } + override fun toString() = "Quaternion($x, $y, $z, $w)" - fun toVector4(): Vector4<Double> { - return Vector4(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble()) + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Quaternion<*>) return false + return x == other.x && y == other.y && z == other.z && w == other.w } - override fun toString(): String { - return "Quaternion(x=$x, y=$y, z=$z, w=$w)" + override fun hashCode(): Int { + var result = x.hashCode() + result = 31 * result + y.hashCode() + result = 31 * result + z.hashCode() + result = 31 * result + w.hashCode() + return result } } @@ -0,0 +1,183 @@ +package com.dropbear.math + +import kotlin.jvm.JvmField +import kotlin.jvm.JvmStatic +import kotlin.math.* + +class Quaterniond( + @JvmField var x: Double, + @JvmField var y: Double, + @JvmField var z: Double, + @JvmField var w: Double +) { + companion object { + @JvmStatic fun identity() = Quaterniond(0.0, 0.0, 0.0, 1.0) + + @JvmStatic + fun fromEulerAngles(pitch: Double, yaw: Double, roll: Double): Quaterniond { + val halfPitch = pitch * 0.5 + val halfYaw = yaw * 0.5 + val halfRoll = roll * 0.5 + val sp = sin(halfPitch) + val cp = cos(halfPitch) + val sy = sin(halfYaw) + val cy = cos(halfYaw) + val sr = sin(halfRoll) + val cr = cos(halfRoll) + + return Quaterniond( + x = cy * sr * cp - sy * cr * sp, + y = sy * cr * cp + cy * sr * sp, + z = sy * sr * cp - cy * cr * sp, + w = cy * cr * cp + sy * sr * sp + ) + } + + @JvmStatic + fun fromAxisAngle(axis: Vector3d, angleRadians: Double): Quaterniond { + val normalizedAxis = axis.normalize() + val halfAngle = angleRadians * 0.5 + val sinHalf = sin(halfAngle) + return Quaterniond( + normalizedAxis.x * sinHalf, + normalizedAxis.y * sinHalf, + normalizedAxis.z * sinHalf, + cos(halfAngle) + ) + } + + @JvmStatic fun rotateX(angle: Double) = fromAxisAngle(Vector3d(1.0, 0.0, 0.0), angle) + @JvmStatic fun rotateY(angle: Double) = fromAxisAngle(Vector3d(0.0, 1.0, 0.0), angle) + @JvmStatic fun rotateZ(angle: Double) = fromAxisAngle(Vector3d(0.0, 0.0, 1.0), angle) + + @JvmStatic + fun fromToRotation(from: Vector3d, to: Vector3d): Quaterniond { + val start = from.normalize() + val end = to.normalize() + val dot = start.dot(end) + + if (dot >= 1.0 - 1e-6) return identity() + if (dot <= -1.0 + 1e-6) { + val orthogonal = if (abs(start.x) < 0.9) Vector3d(1.0, 0.0, 0.0) else Vector3d(0.0, 1.0, 0.0) + val axis = start.cross(orthogonal).normalize() + return fromAxisAngle(axis, PI) + } + val axis = start.cross(end) + val angle = acos(dot.coerceIn(-1.0, 1.0)) + return fromAxisAngle(axis, angle) + } + + private fun copySign(magnitude: Double, sign: Double): Double { + val absMag = abs(magnitude) + return if (sign < 0.0) -absMag else absMag + } + } + + operator fun plus(other: Quaterniond) = Quaterniond(x + other.x, y + other.y, z + other.z, w + other.w) + operator fun minus(other: Quaterniond) = Quaterniond(x - other.x, y - other.y, z - other.z, w - other.w) + operator fun unaryMinus() = Quaterniond(-x, -y, -z, -w) + + operator fun times(scalar: Double) = Quaterniond(x * scalar, y * scalar, z * scalar, w * scalar) + operator fun div(scalar: Double) = Quaterniond(x / scalar, y / scalar, z / scalar, w / scalar) + + /** + * Quaternion Multiplication (Composition). + * Represents applying rotation `other`, then rotation `this`. + */ + operator fun times(other: Quaterniond): Quaterniond { + return Quaterniond( + w * other.x + x * other.w + y * other.z - z * other.y, + w * other.y - x * other.z + y * other.w + z * other.x, + w * other.z + x * other.y - y * other.x + z * other.w, + w * other.w - x * other.x - y * other.y - z * other.z + ) + } + + /** + * Rotates a vector by this quaternion. + */ + operator fun times(vector: Vector3d): Vector3d { + val qVec = Vector3d(x, y, z) + val uv = qVec.cross(vector) + val uuv = qVec.cross(uv) + return vector + ((uv * w) + uuv) * 2.0 + } + + fun dot(other: Quaterniond) = x * other.x + y * other.y + z * other.z + w * other.w + fun lengthSquared() = x * x + y * y + z * z + w * w + fun length() = sqrt(lengthSquared()) + + fun normalize(): Quaterniond { + val len = length() + return if (len == 0.0) identity() else this / len + } + + fun inverse(): Quaterniond { + val lenSq = lengthSquared() + if (lenSq == 0.0) return identity() + val inv = 1.0 / lenSq + return Quaterniond(-x * inv, -y * inv, -z * inv, w * inv) + } + + fun conjugate() = Quaterniond(-x, -y, -z, w) + + fun slerp(other: Quaterniond, t: Double): Quaterniond { + val alpha = t.coerceIn(0.0, 1.0) + var q1 = this.normalize() + var q2 = other.normalize() + + var dot = q1.dot(q2) + + if (dot < 0.0) { + dot = -dot + q2 = -q2 + } + + if (dot > 0.9995) { + return (q1 + (q2 - q1) * alpha).normalize() + } + + val theta0 = acos(dot) + val theta = theta0 * alpha + val sinTheta = sin(theta) + val sinTheta0 = sin(theta0) + + val s0 = cos(theta) - dot * sinTheta / sinTheta0 + val s1 = sinTheta / sinTheta0 + + return (q1 * s0) + (q2 * s1) + } + + fun toEulerAngles(): Vector3d { + val sinr_cosp = 2.0 * (w * z + x * y) + val cosr_cosp = 1.0 - 2.0 * (y * y + z * z) + val roll = atan2(sinr_cosp, cosr_cosp) + + val sinp = 2.0 * (w * x - y * z) + val pitch: Double + if (abs(sinp) >= 1.0) { + pitch = copySign(PI / 2, sinp) + } else { + pitch = asin(sinp) + } + + val siny_cosp = 2.0 * (w * y + z * x) + val cosy_cosp = 1.0 - 2.0 * (x * x + y * y) + val yaw = atan2(siny_cosp, cosy_cosp) + + return Vector3d(pitch, yaw, roll) + } + + fun toFloat() = Quaternionf(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat()) + fun toGeneric() = Quaternion(x, y, z, w) + + override fun toString() = "Quaterniond($x, $y, $z, $w)" + override fun equals(other: Any?) = other is Quaterniond && x == other.x && y == other.y && z == other.z && w == other.w + override fun hashCode(): Int { + var result = x.hashCode() + result = 31 * result + y.hashCode() + result = 31 * result + z.hashCode() + result = 31 * result + w.hashCode() + return result + } +} @@ -0,0 +1,122 @@ +package com.dropbear.math + +import kotlin.jvm.JvmField +import kotlin.jvm.JvmStatic +import kotlin.math.* + +class Quaternionf( + @JvmField var x: Float, + @JvmField var y: Float, + @JvmField var z: Float, + @JvmField var w: Float +) { + companion object { + @JvmStatic fun identity() = Quaternionf(0f, 0f, 0f, 1f) + + @JvmStatic + fun fromEulerAngles(pitch: Float, yaw: Float, roll: Float): Quaternionf { + val halfPitch = pitch * 0.5f + val halfYaw = yaw * 0.5f + val halfRoll = roll * 0.5f + val sp = sin(halfPitch) + val cp = cos(halfPitch) + val sy = sin(halfYaw) + val cy = cos(halfYaw) + val sr = sin(halfRoll) + val cr = cos(halfRoll) + + return Quaternionf( + x = cy * sr * cp - sy * cr * sp, + y = sy * cr * cp + cy * sr * sp, + z = sy * sr * cp - cy * cr * sp, + w = cy * cr * cp + sy * sr * sp + ) + } + + @JvmStatic + fun fromAxisAngle(axis: Vector3f, angleRadians: Float): Quaternionf { + val normalizedAxis = axis.normalize() + val halfAngle = angleRadians * 0.5f + val sinHalf = sin(halfAngle) + return Quaternionf( + normalizedAxis.x * sinHalf, + normalizedAxis.y * sinHalf, + normalizedAxis.z * sinHalf, + cos(halfAngle) + ) + } + + @JvmStatic fun rotateX(angle: Float) = fromAxisAngle(Vector3f(1f, 0f, 0f), angle) + @JvmStatic fun rotateY(angle: Float) = fromAxisAngle(Vector3f(0f, 1f, 0f), angle) + @JvmStatic fun rotateZ(angle: Float) = fromAxisAngle(Vector3f(0f, 0f, 1f), angle) + + private fun copySign(magnitude: Float, sign: Float): Float { + val absMag = abs(magnitude) + return if (sign < 0f) -absMag else absMag + } + } + + operator fun plus(other: Quaternionf) = Quaternionf(x + other.x, y + other.y, z + other.z, w + other.w) + operator fun minus(other: Quaternionf) = Quaternionf(x - other.x, y - other.y, z - other.z, w - other.w) + operator fun unaryMinus() = Quaternionf(-x, -y, -z, -w) + + operator fun times(scalar: Float) = Quaternionf(x * scalar, y * scalar, z * scalar, w * scalar) + operator fun div(scalar: Float) = Quaternionf(x / scalar, y / scalar, z / scalar, w / scalar) + + operator fun times(other: Quaternionf): Quaternionf { + return Quaternionf( + w * other.x + x * other.w + y * other.z - z * other.y, + w * other.y - x * other.z + y * other.w + z * other.x, + w * other.z + x * other.y - y * other.x + z * other.w, + w * other.w - x * other.x - y * other.y - z * other.z + ) + } + + operator fun times(vector: Vector3f): Vector3f { + val qVec = Vector3f(x, y, z) + val uv = qVec.cross(vector) + val uuv = qVec.cross(uv) + return vector + ((uv * w) + uuv) * 2f + } + + fun dot(other: Quaternionf) = x * other.x + y * other.y + z * other.z + w * other.w + fun lengthSquared() = x * x + y * y + z * z + w * w + fun length() = sqrt(lengthSquared()) + + fun normalize(): Quaternionf { + val len = length() + return if (len == 0f) identity() else this / len + } + + fun inverse(): Quaternionf { + val lenSq = lengthSquared() + if (lenSq == 0f) return identity() + val inv = 1.0f / lenSq + return Quaternionf(-x * inv, -y * inv, -z * inv, w * inv) + } + + fun conjugate() = Quaternionf(-x, -y, -z, w) + + fun toDouble() = Quaterniond(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble()) + + fun toEulerAngles(): Vector3f { + val sinr_cosp = 2f * (w * z + x * y) + val cosr_cosp = 1f - 2f * (y * y + z * z) + val roll = atan2(sinr_cosp, cosr_cosp) + + val sinp = 2f * (w * x - y * z) + val pitch = if (abs(sinp) >= 1f) { + copySign(PI.toFloat() / 2f, sinp) + } else { + asin(sinp) + } + + val siny_cosp = 2f * (w * y + z * x) + val cosy_cosp = 1f - 2f * (x * x + y * y) + val yaw = atan2(siny_cosp, cosy_cosp) + + return Vector3f(pitch, yaw, roll) + } + + override fun toString() = "Quaternionf($x, $y, $z, $w)" +} @@ -5,9 +5,9 @@ package com.dropbear.math * attached to an entity. */ class Transform( - var position: Vector3D, - var rotation: QuaternionD, - var scale: Vector3D + var position: Vector3d, + var rotation: Quaterniond, + var scale: Vector3d ) { /** * Specific constructor for the individual raw primitive values. @@ -18,9 +18,9 @@ class Transform( rx: Double, ry: Double, rz: Double, rw: Double, sx: Double, sy: Double, sz: Double) : this( - Vector3D(px, py, pz), - QuaternionD(rx, ry, rz, rw), - Vector3D(sx, sy, sz) + Vector3d(px, py, pz), + Quaterniond(rx, ry, rz, rw), + Vector3d(sx, sy, sz) ) override fun toString(): String { @@ -1,24 +0,0 @@ -package com.dropbear.math - -/** - * Abstract class all Vectors inherit. - */ -abstract class Vector<T: Number, SELF: Vector<T, SELF>> { - abstract fun normalize(): SELF - - abstract operator fun plus(other: SELF): SELF - abstract operator fun plus(scalar: T): SELF - - abstract operator fun minus(other: SELF): SELF - abstract operator fun minus(scalar: T): SELF - - abstract operator fun times(other: SELF): SELF - abstract operator fun times(scalar: T): SELF - - abstract operator fun div(other: SELF): SELF - abstract operator fun div(scalar: T): SELF - - abstract fun length(): Double - - abstract fun copy(): SELF -} @@ -1,180 +1,32 @@ package com.dropbear.math import kotlin.jvm.JvmField -import kotlin.math.sqrt +import kotlin.jvm.JvmStatic /** - * A class for holding a vector of `2` values of the same type. + * A Generic Vector2. + * WARNING: Uses boxing. Prefer [Vector2d]/[Vector2f]/[Vector2i] for performance. */ -class Vector2<T: Number>( +class Vector2<T : Number>( @JvmField var x: T, - @JvmField var y: T, -) : Vector<T, Vector2<T>>() { + @JvmField var y: T +) { companion object { - /** - * Creates a new [com.dropbear.math.Vector2] of type `T` with one value. - */ - fun <T: Number> uniform(value: T): Vector2<T> { - return Vector2(value, value) - } - - /** - * Creates a [com.dropbear.math.Vector2] of type [Double] filled with only zeroes - */ - fun zero(): Vector2<Double> { - return Vector2(0.0, 0.0) - } - } - - fun asDoubleVector(): Vector2<Double> { - return Vector2(this.x.toDouble(), this.y.toDouble()) - } - - override fun normalize(): Vector2<T> { - val length = length() - if (length > 0.0) { - val invLength = 1.0 / length - @Suppress("UNCHECKED_CAST") - x = (x.toDouble() * invLength) as T - @Suppress("UNCHECKED_CAST") - y = (y.toDouble() * invLength) as T - } - return this - } - - override operator fun plus(other: Vector2<T>): Vector2<T> { - @Suppress("UNCHECKED_CAST") - return Vector2( - x.toDouble() + other.x.toDouble(), - y.toDouble() + other.y.toDouble() - ) as Vector2<T> - } - - override operator fun plus(scalar: T): Vector2<T> { - @Suppress("UNCHECKED_CAST") - return Vector2( - x.toDouble() + scalar.toDouble(), - y.toDouble() + scalar.toDouble() - ) as Vector2<T> - } - - override operator fun minus(other: Vector2<T>): Vector2<T> { - @Suppress("UNCHECKED_CAST") - return Vector2( - x.toDouble() - other.x.toDouble(), - y.toDouble() - other.y.toDouble() - ) as Vector2<T> - } - - override operator fun minus(scalar: T): Vector2<T> { - @Suppress("UNCHECKED_CAST") - return Vector2( - x.toDouble() - scalar.toDouble(), - y.toDouble() - scalar.toDouble() - ) as Vector2<T> - } - - override operator fun times(other: Vector2<T>): Vector2<T> { - @Suppress("UNCHECKED_CAST") - return Vector2( - x.toDouble() * other.x.toDouble(), - y.toDouble() * other.y.toDouble() - ) as Vector2<T> - } - - override operator fun times(scalar: T): Vector2<T> { - @Suppress("UNCHECKED_CAST") - return Vector2( - x.toDouble() * scalar.toDouble(), - y.toDouble() * scalar.toDouble() - ) as Vector2<T> - } - - override operator fun div(other: Vector2<T>): Vector2<T> { - @Suppress("UNCHECKED_CAST") - return Vector2( - x.toDouble() / other.x.toDouble(), - y.toDouble() / other.y.toDouble() - ) as Vector2<T> - } - - override operator fun div(scalar: T): Vector2<T> { - @Suppress("UNCHECKED_CAST") - return Vector2( - x.toDouble() / scalar.toDouble(), - y.toDouble() / scalar.toDouble(), - ) as Vector2<T> - } - - fun lengthSquared(): Double { - val dx = x.toDouble() - val dy = y.toDouble() - return dx * dx + dy * dy - } - - fun dot(other: Vector2<T>): Double { - return x.toDouble() * other.x.toDouble() + y.toDouble() * other.y.toDouble() - } - - fun distanceTo(other: Vector2<T>): Double { - val dx = x.toDouble() - other.x.toDouble() - val dy = y.toDouble() - other.y.toDouble() - return sqrt(dx * dx + dy * dy) - } - - fun normalizedCopy(): Vector2<Double> { - val length = length() - if (length == 0.0) { - return zero() - } - val invLength = 1.0 / length - return Vector2( - x.toDouble() * invLength, - y.toDouble() * invLength - ) - } - - fun lerp(target: Vector2<T>, alpha: Double): Vector2<Double> { - val inverse = 1.0 - alpha - return Vector2( - x.toDouble() * inverse + target.x.toDouble() * alpha, - y.toDouble() * inverse + target.y.toDouble() * alpha - ) - } - - operator fun unaryMinus(): Vector2<T> { - @Suppress("UNCHECKED_CAST") - return Vector2(-x.toDouble(), -y.toDouble()) as Vector2<T> - } - - fun toVector3(z: T): Vector3<T> { - return Vector3(x, y, z) + @JvmStatic + fun fromDoubles(x: Double, y: Double): Vector2<Double> = Vector2(x, y) } - fun toVector4(z: T, w: T): Vector4<T> { - return Vector4(x, y, z, w) - } - - operator fun component1(): T = x - operator fun component2(): T = y + fun asVector2d(): Vector2d = Vector2d(x.toDouble(), y.toDouble()) + fun asVector2f(): Vector2f = Vector2f(x.toFloat(), y.toFloat()) + fun asVector2i(): Vector2i = Vector2i(x.toInt(), y.toInt()) - /** - * Returns the magnitude/length of the vector - * - * ## Math - * `sqrt(x^2 + y^2)` - */ - override fun length(): Double { - return sqrt(x.toDouble() * x.toDouble() + y.toDouble() * y.toDouble()) - } - - override fun copy(): Vector2<T> { - return Vector2(x, y) - } + override fun toString() = "Vector2($x, $y)" - override fun toString(): String { - return "Vector2(x=$x, y=$y)" + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Vector2<*>) return false + return x == other.x && y == other.y } -} -typealias Vector2D = Vector2<Double> + override fun hashCode() = 31 * x.hashCode() + y.hashCode() +} @@ -0,0 +1,62 @@ +package com.dropbear.math + +import kotlin.math.sqrt +import kotlin.jvm.JvmField +import kotlin.jvm.JvmStatic + +/** + * A class for holding a vector of `2` double values. + */ +class Vector2d( + @JvmField var x: Double, + @JvmField var y: Double +) { + companion object { + @JvmStatic fun zero() = Vector2d(0.0, 0.0) + @JvmStatic fun one() = Vector2d(1.0, 1.0) + } + + operator fun plus(other: Vector2d) = Vector2d(x + other.x, y + other.y) + operator fun plus(scalar: Double) = Vector2d(x + scalar, y + scalar) + + operator fun minus(other: Vector2d) = Vector2d(x - other.x, y - other.y) + operator fun minus(scalar: Double) = Vector2d(x - scalar, y - scalar) + + operator fun times(other: Vector2d) = Vector2d(x * other.x, y * other.y) + operator fun times(scalar: Double) = Vector2d(x * scalar, y * scalar) + + operator fun div(other: Vector2d) = Vector2d(x / other.x, y / other.y) + operator fun div(scalar: Double) = Vector2d(x / scalar, y / scalar) + + operator fun unaryMinus() = Vector2d(-x, -y) + + fun length() = sqrt(x * x + y * y) + fun lengthSquared() = x * x + y * y + + fun dot(other: Vector2d) = x * other.x + y * other.y + + fun distanceTo(other: Vector2d): Double { + val dx = x - other.x + val dy = y - other.y + return sqrt(dx * dx + dy * dy) + } + + fun normalize(): Vector2d { + val l = length() + return if (l != 0.0) this / l else zero() + } + + fun lerp(target: Vector2d, alpha: Double): Vector2d { + val inv = 1.0 - alpha + return Vector2d(x * inv + target.x * alpha, y * inv + target.y * alpha) + } + + fun toFloat() = Vector2f(x.toFloat(), y.toFloat()) + fun toInt() = Vector2i(x.toInt(), y.toInt()) + + fun toGeneric() = Vector2(x, y) + + override fun toString() = "Vector2d($x, $y)" + override fun equals(other: Any?) = other is Vector2d && x == other.x && y == other.y + override fun hashCode() = 31 * x.hashCode() + y.hashCode() +} @@ -0,0 +1,46 @@ +package com.dropbear.math + +import kotlin.math.sqrt +import kotlin.jvm.JvmField +import kotlin.jvm.JvmStatic + +/** + * A class for holding a vector of `2` float values. + */ +class Vector2f( + @JvmField var x: Float, + @JvmField var y: Float +) { + companion object { + @JvmStatic + fun zero() = Vector2f(0f, 0f) + } + + operator fun plus(other: Vector2f) = Vector2f(x + other.x, y + other.y) + operator fun plus(scalar: Float) = Vector2f(x + scalar, y + scalar) + + operator fun minus(other: Vector2f) = Vector2f(x - other.x, y - other.y) + operator fun minus(scalar: Float) = Vector2f(x - scalar, y - scalar) + + operator fun times(other: Vector2f) = Vector2f(x * other.x, y * other.y) + operator fun times(scalar: Float) = Vector2f(x * scalar, y * scalar) + + operator fun div(other: Vector2f) = Vector2f(x / other.x, y / other.y) + operator fun div(scalar: Float) = Vector2f(x / scalar, y / scalar) + + operator fun unaryMinus() = Vector2f(-x, -y) + + fun length(): Float = sqrt(x * x + y * y) + fun lengthSquared(): Float = x * x + y * y + + fun normalize(): Vector2f { + val l = length() + return if (l != 0f) Vector2f(x / l, y / l) else zero() + } + + // --- Conversions --- + fun toDouble() = Vector2d(x.toDouble(), y.toDouble()) + fun toInt() = Vector2i(x.toInt(), y.toInt()) + + override fun toString() = "Vector2f($x, $y)" +} @@ -0,0 +1,32 @@ +package com.dropbear.math + +import kotlin.math.sqrt +import kotlin.jvm.JvmField +import kotlin.jvm.JvmStatic + +/** + * A class for holding a vector of `2` integer values. + */ +class Vector2i( + @JvmField var x: Int, + @JvmField var y: Int +) { + companion object { + @JvmStatic + fun zero() = Vector2i(0, 0) + } + + operator fun plus(other: Vector2i) = Vector2i(x + other.x, y + other.y) + operator fun minus(other: Vector2i) = Vector2i(x - other.x, y - other.y) + + operator fun times(scalar: Int) = Vector2i(x * scalar, y * scalar) + + operator fun div(scalar: Int) = Vector2i(x / scalar, y / scalar) + + fun length(): Double = sqrt((x * x + y * y).toDouble()) + + fun toFloat() = Vector2f(x.toFloat(), y.toFloat()) + fun toDouble() = Vector2d(x.toDouble(), y.toDouble()) + + override fun toString() = "Vector2i($x, $y)" +} @@ -1,227 +1,41 @@ package com.dropbear.math import kotlin.jvm.JvmField -import kotlin.math.sqrt +import kotlin.jvm.JvmStatic /** - * A class for holding a vector of `3` values of the same type. + * A Generic Vector3. + * WARNING: Uses boxing. Prefer [Vector3d]/[Vector3f]/[Vector3i] for performance. */ -class Vector3<T: Number>( +class Vector3<T : Number>( @JvmField var x: T, @JvmField var y: T, - @JvmField var z: T, -) : Vector<T, Vector3<T>>() { + @JvmField var z: T +) { companion object { - /** - * Creates a new [com.dropbear.math.Vector3] of type `T` with one value. - */ - fun <T: Number> uniform(value: T): Vector3<T> { - return Vector3(value, value, value) - } + @JvmStatic + fun fromDoubles(x: Double, y: Double, z: Double): Vector3<Double> = Vector3(x, y, z) - /** - * Creates a [com.dropbear.math.Vector3] of type [Double] filled with only zeroes - */ - fun zero(): Vector3<Double> { - return Vector3(0.0, 0.0, 0.0) - } - - fun x(): Vector3D { - return Vector3D(1.0, 0.0, 0.0) - } - - fun y(): Vector3D { - return Vector3D(0.0, 1.0, 0.0) - } - - fun z(): Vector3D { - return Vector3D(0.0, 0.0, 1.0) - } - } - - /** - * Returns the [Vector3] to a [Vector3D] (Vector3 of type `Double`) - */ - fun asDoubleVector(): Vector3<Double> { - return Vector3(this.x.toDouble(), this.y.toDouble(), this.z.toDouble()) - } - - override fun normalize(): Vector3<T> { - val length = length() - if (length > 0.0) { - val invLength = 1.0 / length - @Suppress("UNCHECKED_CAST") - x = (x.toDouble() * invLength) as T - @Suppress("UNCHECKED_CAST") - y = (y.toDouble() * invLength) as T - @Suppress("UNCHECKED_CAST") - z = (z.toDouble() * invLength) as T - } - return this - } - - override operator fun plus(other: Vector3<T>): Vector3<T> { - @Suppress("UNCHECKED_CAST") - return Vector3( - x.toDouble() + other.x.toDouble(), - y.toDouble() + other.y.toDouble(), - z.toDouble() + other.z.toDouble() - ) as Vector3<T> - } - - override operator fun plus(scalar: T): Vector3<T> { - @Suppress("UNCHECKED_CAST") - return Vector3( - x.toDouble() + scalar.toDouble(), - y.toDouble() + scalar.toDouble(), - z.toDouble() + scalar.toDouble() - ) as Vector3<T> + @JvmStatic + fun zero(): Vector3<Double> = Vector3(0.0, 0.0, 0.0) } - override operator fun minus(other: Vector3<T>): Vector3<T> { - @Suppress("UNCHECKED_CAST") - return Vector3( - x.toDouble() - other.x.toDouble(), - y.toDouble() - other.y.toDouble(), - z.toDouble() - other.z.toDouble() - ) as Vector3<T> - } - - override operator fun minus(scalar: T): Vector3<T> { - @Suppress("UNCHECKED_CAST") - return Vector3( - x.toDouble() - scalar.toDouble(), - y.toDouble() - scalar.toDouble(), - z.toDouble() - scalar.toDouble() - ) as Vector3<T> - } + fun asVector3d(): Vector3d = Vector3d(x.toDouble(), y.toDouble(), z.toDouble()) + fun asVector3f(): Vector3f = Vector3f(x.toFloat(), y.toFloat(), z.toFloat()) + fun asVector3i(): Vector3i = Vector3i(x.toInt(), y.toInt(), z.toInt()) - override operator fun times(other: Vector3<T>): Vector3<T> { - @Suppress("UNCHECKED_CAST") - return Vector3( - x.toDouble() * other.x.toDouble(), - y.toDouble() * other.y.toDouble(), - z.toDouble() * other.z.toDouble() - ) as Vector3<T> - } - - override operator fun times(scalar: T): Vector3<T> { - @Suppress("UNCHECKED_CAST") - return Vector3( - x.toDouble() * scalar.toDouble(), - y.toDouble() * scalar.toDouble(), - z.toDouble() * scalar.toDouble() - ) as Vector3<T> - } + override fun toString() = "Vector3($x, $y, $z)" - override operator fun div(other: Vector3<T>): Vector3<T> { - @Suppress("UNCHECKED_CAST") - return Vector3( - x.toDouble() / other.x.toDouble(), - y.toDouble() / other.y.toDouble(), - z.toDouble() / other.z.toDouble() - ) as Vector3<T> + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Vector3<*>) return false + return x == other.x && y == other.y && z == other.z } - override operator fun div(scalar: T): Vector3<T> { - @Suppress("UNCHECKED_CAST") - return Vector3( - x.toDouble() / scalar.toDouble(), - y.toDouble() / scalar.toDouble(), - z.toDouble() / scalar.toDouble() - ) as Vector3<T> + override fun hashCode(): Int { + var result = x.hashCode() + result = 31 * result + y.hashCode() + result = 31 * result + z.hashCode() + return result } - - fun lengthSquared(): Double { - val dx = x.toDouble() - val dy = y.toDouble() - val dz = z.toDouble() - return dx * dx + dy * dy + dz * dz - } - - fun dot(other: Vector3<T>): Double { - return x.toDouble() * other.x.toDouble() + - y.toDouble() * other.y.toDouble() + - z.toDouble() * other.z.toDouble() - } - - fun cross(other: Vector3<T>): Vector3<Double> { - val ax = x.toDouble() - val ay = y.toDouble() - val az = z.toDouble() - val bx = other.x.toDouble() - val by = other.y.toDouble() - val bz = other.z.toDouble() - return Vector3( - ay * bz - az * by, - az * bx - ax * bz, - ax * by - ay * bx - ) - } - - fun distanceTo(other: Vector3<T>): Double { - val dx = x.toDouble() - other.x.toDouble() - val dy = y.toDouble() - other.y.toDouble() - val dz = z.toDouble() - other.z.toDouble() - return sqrt(dx * dx + dy * dy + dz * dz) - } - - fun normalizedCopy(): Vector3<Double> { - val length = length() - if (length == 0.0) { - return zero() - } - val invLength = 1.0 / length - return Vector3( - x.toDouble() * invLength, - y.toDouble() * invLength, - z.toDouble() * invLength - ) - } - - fun lerp(target: Vector3<T>, alpha: Double): Vector3<Double> { - val inverse = 1.0 - alpha - return Vector3( - x.toDouble() * inverse + target.x.toDouble() * alpha, - y.toDouble() * inverse + target.y.toDouble() * alpha, - z.toDouble() * inverse + target.z.toDouble() * alpha - ) - } - - operator fun unaryMinus(): Vector3<T> { - @Suppress("UNCHECKED_CAST") - return Vector3(-x.toDouble(), -y.toDouble(), -z.toDouble()) as Vector3<T> - } - - fun toVector2(): Vector2<T> { - return Vector2(x, y) - } - - fun toVector4(w: T): Vector4<T> { - return Vector4(x, y, z, w) - } - - operator fun component1(): T = x - operator fun component2(): T = y - operator fun component3(): T = z - - /** - * Returns the magnitude/length of the vector - * - * ## Math - * `sqrt(x^2 + y^2 + z^2)` - */ - override fun length(): Double { - return sqrt(x.toDouble() * x.toDouble() + y.toDouble() * y.toDouble() + z.toDouble() * z.toDouble()) - } - - override fun copy(): Vector3<T> { - return Vector3(x, y, z) - } - - override fun toString(): String { - return "Vector3(x=$x, y=$y, z=$z)" - } -} - -typealias Vector3D = Vector3<Double> +} @@ -0,0 +1,87 @@ +package com.dropbear.math + +import kotlin.math.sqrt +import kotlin.jvm.JvmField +import kotlin.jvm.JvmStatic + +class Vector3d( + @JvmField var x: Double, + @JvmField var y: Double, + @JvmField var z: Double +) { + companion object { + @JvmStatic fun zero() = Vector3d(0.0, 0.0, 0.0) + @JvmStatic fun one() = Vector3d(1.0, 1.0, 1.0) + + @JvmStatic fun right() = Vector3d(1.0, 0.0, 0.0) // X + @JvmStatic fun up() = Vector3d(0.0, 1.0, 0.0) // Y + @JvmStatic fun forward() = Vector3d(0.0, 0.0, 1.0) // Z + } + + operator fun plus(other: Vector3d) = Vector3d(x + other.x, y + other.y, z + other.z) + operator fun plus(scalar: Double) = Vector3d(x + scalar, y + scalar, z + scalar) + + operator fun minus(other: Vector3d) = Vector3d(x - other.x, y - other.y, z - other.z) + operator fun minus(scalar: Double) = Vector3d(x - scalar, y - scalar, z - scalar) + + operator fun times(other: Vector3d) = Vector3d(x * other.x, y * other.y, z * other.z) + operator fun times(scalar: Double) = Vector3d(x * scalar, y * scalar, z * scalar) + + operator fun div(other: Vector3d) = Vector3d(x / other.x, y / other.y, z / other.z) + operator fun div(scalar: Double) = Vector3d(x / scalar, y / scalar, z / scalar) + + operator fun unaryMinus() = Vector3d(-x, -y, -z) + + fun length() = sqrt(x * x + y * y + z * z) + fun lengthSquared() = x * x + y * y + z * z + + fun dot(other: Vector3d) = x * other.x + y * other.y + z * other.z + + /** + * Calculates the Cross Product. + * Result is perpendicular to both this vector and the other. + */ + fun cross(other: Vector3d): Vector3d { + return Vector3d( + y * other.z - z * other.y, + z * other.x - x * other.z, + x * other.y - y * other.x + ) + } + + fun distanceTo(other: Vector3d): Double { + val dx = x - other.x + val dy = y - other.y + val dz = z - other.z + return sqrt(dx * dx + dy * dy + dz * dz) + } + + fun normalize(): Vector3d { + val l = length() + return if (l != 0.0) this / l else zero() + } + + fun lerp(target: Vector3d, alpha: Double): Vector3d { + val inv = 1.0 - alpha + return Vector3d( + x * inv + target.x * alpha, + y * inv + target.y * alpha, + z * inv + target.z * alpha + ) + } + + fun toFloat() = Vector3f(x.toFloat(), y.toFloat(), z.toFloat()) + fun toInt() = Vector3i(x.toInt(), y.toInt(), z.toInt()) + fun toVector2d() = Vector2d(x, y) + + fun toGeneric() = Vector3(x, y, z) + + override fun toString() = "Vector3d($x, $y, $z)" + override fun equals(other: Any?) = other is Vector3d && x == other.x && y == other.y && z == other.z + override fun hashCode(): Int { + var result = x.hashCode() + result = 31 * result + y.hashCode() + result = 31 * result + z.hashCode() + return result + } +} @@ -0,0 +1,54 @@ +package com.dropbear.math + +import kotlin.math.sqrt +import kotlin.jvm.JvmField +import kotlin.jvm.JvmStatic + +class Vector3f( + @JvmField var x: Float, + @JvmField var y: Float, + @JvmField var z: Float +) { + companion object { + @JvmStatic + fun zero() = Vector3f(0f, 0f, 0f) + } + + operator fun plus(other: Vector3f) = Vector3f(x + other.x, y + other.y, z + other.z) + operator fun plus(scalar: Float) = Vector3f(x + scalar, y + scalar, z + scalar) + + operator fun minus(other: Vector3f) = Vector3f(x - other.x, y - other.y, z - other.z) + operator fun minus(scalar: Float) = Vector3f(x - scalar, y - scalar, z - scalar) + + operator fun times(other: Vector3f) = Vector3f(x * other.x, y * other.y, z * other.z) + operator fun times(scalar: Float) = Vector3f(x * scalar, y * scalar, z * scalar) + + operator fun div(other: Vector3f) = Vector3f(x / other.x, y / other.y, z / other.z) + operator fun div(scalar: Float) = Vector3f(x / scalar, y / scalar, z / scalar) + + operator fun unaryMinus() = Vector3f(-x, -y, -z) + + fun length(): Float = sqrt(x * x + y * y + z * z) + fun lengthSquared(): Float = x * x + y * y + z * z + + fun dot(other: Vector3f) = x * other.x + y * other.y + z * other.z + + fun cross(other: Vector3f): Vector3f { + return Vector3f( + y * other.z - z * other.y, + z * other.x - x * other.z, + x * other.y - y * other.x + ) + } + + fun normalize(): Vector3f { + val l = length() + return if (l != 0f) Vector3f(x / l, y / l, z / l) else zero() + } + + fun toDouble() = Vector3d(x.toDouble(), y.toDouble(), z.toDouble()) + fun toInt() = Vector3i(x.toInt(), y.toInt(), z.toInt()) + fun toVector2f() = Vector2f(x, y) + + override fun toString() = "Vector3f($x, $y, $z)" +} @@ -0,0 +1,28 @@ +package com.dropbear.math + +import kotlin.math.sqrt +import kotlin.jvm.JvmField +import kotlin.jvm.JvmStatic + +class Vector3i( + @JvmField var x: Int, + @JvmField var y: Int, + @JvmField var z: Int +) { + companion object { + @JvmStatic + fun zero() = Vector3i(0, 0, 0) + } + + operator fun plus(other: Vector3i) = Vector3i(x + other.x, y + other.y, z + other.z) + operator fun minus(other: Vector3i) = Vector3i(x - other.x, y - other.y, z - other.z) + operator fun times(scalar: Int) = Vector3i(x * scalar, y * scalar, z * scalar) + operator fun div(scalar: Int) = Vector3i(x / scalar, y / scalar, z / scalar) + + fun length(): Double = sqrt((x * x + y * y + z * z).toDouble()) + + fun toFloat() = Vector3f(x.toFloat(), y.toFloat(), z.toFloat()) + fun toDouble() = Vector3d(x.toDouble(), y.toDouble(), z.toDouble()) + + override fun toString() = "Vector3i($x, $y, $z)" +} @@ -1,228 +1,48 @@ package com.dropbear.math import kotlin.jvm.JvmField -import kotlin.math.sqrt +import kotlin.jvm.JvmStatic /** - * A class for holding a vector of `4` values of the same type. + * A Generic Vector4. + * WARNING: Uses boxing. Prefer [Vector4d]/[Vector4f]/[Vector4i] for performance. */ -class Vector4<T: Number>( +class Vector4<T : Number>( @JvmField var x: T, @JvmField var y: T, @JvmField var z: T, - @JvmField var w: T, -) : Vector<T, Vector4<T>>() { + @JvmField var w: T +) { companion object { - /** - * Creates a new [com.dropbear.math.Vector4] of type `T` with one value. - */ - fun <T: Number> uniform(value: T): Vector4<T> { - return Vector4(value, value, value, value) - } + @JvmStatic + fun fromDoubles(x: Double, y: Double, z: Double, w: Double): Vector4<Double> = Vector4(x, y, z, w) - /** - * Creates a [com.dropbear.math.Vector4] of type [Double] filled with only zeroes - */ - fun zero(): Vector4<Double> { - return Vector4(0.0, 0.0, 0.0, 0.0) - } - - fun x(): Vector4D { - return Vector4D(1.0, 0.0, 0.0, 0.0) - } - - fun y(): Vector4D { - return Vector4D(0.0, 1.0, 0.0, 0.0) - } - - fun z(): Vector4D { - return Vector4D(0.0, 0.0, 1.0, 0.0) - } - - fun w(): Vector4D { - return Vector4D(0.0, 0.0, 0.0, 1.0) - } - } - - fun asDoubleVector(): Vector4<Double> { - return Vector4(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble()) - } - - override fun normalize(): Vector4<T> { - val length = length() - if (length > 0.0) { - val invLength = 1.0 / length - @Suppress("UNCHECKED_CAST") - x = (x.toDouble() * invLength) as T - @Suppress("UNCHECKED_CAST") - y = (y.toDouble() * invLength) as T - @Suppress("UNCHECKED_CAST") - z = (z.toDouble() * invLength) as T - @Suppress("UNCHECKED_CAST") - w = (w.toDouble() * invLength) as T - } - return this - } - - override operator fun plus(other: Vector4<T>): Vector4<T> { - @Suppress("UNCHECKED_CAST") - return Vector4( - x.toDouble() + other.x.toDouble(), - y.toDouble() + other.y.toDouble(), - z.toDouble() + other.z.toDouble(), - w.toDouble() + other.w.toDouble() - ) as Vector4<T> + @JvmStatic + fun zero(): Vector4<Double> = Vector4(0.0, 0.0, 0.0, 0.0) } - override operator fun plus(scalar: T): Vector4<T> { - val value = scalar.toDouble() - @Suppress("UNCHECKED_CAST") - return Vector4( - x.toDouble() + value, - y.toDouble() + value, - z.toDouble() + value, - w.toDouble() + value - ) as Vector4<T> - } - - override operator fun minus(other: Vector4<T>): Vector4<T> { - @Suppress("UNCHECKED_CAST") - return Vector4( - x.toDouble() - other.x.toDouble(), - y.toDouble() - other.y.toDouble(), - z.toDouble() - other.z.toDouble(), - w.toDouble() - other.w.toDouble() - ) as Vector4<T> - } - - override operator fun minus(scalar: T): Vector4<T> { - val value = scalar.toDouble() - @Suppress("UNCHECKED_CAST") - return Vector4( - x.toDouble() - value, - y.toDouble() - value, - z.toDouble() - value, - w.toDouble() - value - ) as Vector4<T> - } + fun asVector4d(): Vector4d = Vector4d(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble()) + fun asVector4f(): Vector4f = Vector4f(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat()) + fun asVector4i(): Vector4i = Vector4i(x.toInt(), y.toInt(), z.toInt(), w.toInt()) - override operator fun times(other: Vector4<T>): Vector4<T> { - @Suppress("UNCHECKED_CAST") - return Vector4( - x.toDouble() * other.x.toDouble(), - y.toDouble() * other.y.toDouble(), - z.toDouble() * other.z.toDouble(), - w.toDouble() * other.w.toDouble() - ) as Vector4<T> - } + operator fun component1() = x + operator fun component2() = y + operator fun component3() = z + operator fun component4() = w - override operator fun times(scalar: T): Vector4<T> { - val value = scalar.toDouble() - @Suppress("UNCHECKED_CAST") - return Vector4( - x.toDouble() * value, - y.toDouble() * value, - z.toDouble() * value, - w.toDouble() * value - ) as Vector4<T> - } + override fun toString() = "Vector4($x, $y, $z, $w)" - override operator fun div(other: Vector4<T>): Vector4<T> { - @Suppress("UNCHECKED_CAST") - return Vector4( - x.toDouble() / other.x.toDouble(), - y.toDouble() / other.y.toDouble(), - z.toDouble() / other.z.toDouble(), - w.toDouble() / other.w.toDouble() - ) as Vector4<T> + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Vector4<*>) return false + return x == other.x && y == other.y && z == other.z && w == other.w } - override operator fun div(scalar: T): Vector4<T> { - val value = scalar.toDouble() - @Suppress("UNCHECKED_CAST") - return Vector4( - x.toDouble() / value, - y.toDouble() / value, - z.toDouble() / value, - w.toDouble() / value - ) as Vector4<T> + override fun hashCode(): Int { + var result = x.hashCode() + result = 31 * result + y.hashCode() + result = 31 * result + z.hashCode() + result = 31 * result + w.hashCode() + return result } - - fun lengthSquared(): Double { - val dx = x.toDouble() - val dy = y.toDouble() - val dz = z.toDouble() - val dw = w.toDouble() - return dx * dx + dy * dy + dz * dz + dw * dw - } - - fun dot(other: Vector4<T>): Double { - return x.toDouble() * other.x.toDouble() + - y.toDouble() * other.y.toDouble() + - z.toDouble() * other.z.toDouble() + - w.toDouble() * other.w.toDouble() - } - - fun distanceTo(other: Vector4<T>): Double { - val dx = x.toDouble() - other.x.toDouble() - val dy = y.toDouble() - other.y.toDouble() - val dz = z.toDouble() - other.z.toDouble() - val dw = w.toDouble() - other.w.toDouble() - return sqrt(dx * dx + dy * dy + dz * dz + dw * dw) - } - - fun normalizedCopy(): Vector4<Double> { - val length = length() - if (length == 0.0) { - return zero() - } - val invLength = 1.0 / length - return Vector4( - x.toDouble() * invLength, - y.toDouble() * invLength, - z.toDouble() * invLength, - w.toDouble() * invLength - ) - } - - fun lerp(target: Vector4<T>, alpha: Double): Vector4<Double> { - val inverse = 1.0 - alpha - return Vector4( - x.toDouble() * inverse + target.x.toDouble() * alpha, - y.toDouble() * inverse + target.y.toDouble() * alpha, - z.toDouble() * inverse + target.z.toDouble() * alpha, - w.toDouble() * inverse + target.w.toDouble() * alpha - ) - } - - operator fun unaryMinus(): Vector4<T> { - @Suppress("UNCHECKED_CAST") - return Vector4(-x.toDouble(), -y.toDouble(), -z.toDouble(), -w.toDouble()) as Vector4<T> - } - - fun toVector3(): Vector3<T> { - return Vector3(x, y, z) - } - - operator fun component1(): T = x - operator fun component2(): T = y - operator fun component3(): T = z - operator fun component4(): T = w - - /** - * Returns the magnitude/length of the vector - */ - override fun length(): Double { - return sqrt(lengthSquared()) - } - - override fun copy(): Vector4<T> { - return Vector4(x, y, z, w) - } - - override fun toString(): String { - return "Vector4(x=$x, y=$y, z=$z, w=$w)" - } -} - -typealias Vector4D = Vector4<Double> +} @@ -0,0 +1,81 @@ +package com.dropbear.math + +import kotlin.math.sqrt +import kotlin.jvm.JvmField +import kotlin.jvm.JvmStatic + +class Vector4d( + @JvmField var x: Double, + @JvmField var y: Double, + @JvmField var z: Double, + @JvmField var w: Double +) { + companion object { + @JvmStatic fun zero() = Vector4d(0.0, 0.0, 0.0, 0.0) + @JvmStatic fun one() = Vector4d(1.0, 1.0, 1.0, 1.0) + } + + operator fun plus(other: Vector4d) = Vector4d(x + other.x, y + other.y, z + other.z, w + other.w) + operator fun plus(scalar: Double) = Vector4d(x + scalar, y + scalar, z + scalar, w + scalar) + + operator fun minus(other: Vector4d) = Vector4d(x - other.x, y - other.y, z - other.z, w - other.w) + operator fun minus(scalar: Double) = Vector4d(x - scalar, y - scalar, z - scalar, w - scalar) + + operator fun times(other: Vector4d) = Vector4d(x * other.x, y * other.y, z * other.z, w * other.w) + operator fun times(scalar: Double) = Vector4d(x * scalar, y * scalar, z * scalar, w * scalar) + + operator fun div(other: Vector4d) = Vector4d(x / other.x, y / other.y, z / other.z, w / other.w) + operator fun div(scalar: Double) = Vector4d(x / scalar, y / scalar, z / scalar, w / scalar) + + operator fun unaryMinus() = Vector4d(-x, -y, -z, -w) + + fun length() = sqrt(x * x + y * y + z * z + w * w) + fun lengthSquared() = x * x + y * y + z * z + w * w + + fun dot(other: Vector4d) = x * other.x + y * other.y + z * other.z + w * other.w + + fun distanceTo(other: Vector4d): Double { + val dx = x - other.x + val dy = y - other.y + val dz = z - other.z + val dw = w - other.w + return sqrt(dx * dx + dy * dy + dz * dz + dw * dw) + } + + fun normalize(): Vector4d { + val l = length() + return if (l != 0.0) this / l else zero() + } + + fun lerp(target: Vector4d, alpha: Double): Vector4d { + val inv = 1.0 - alpha + return Vector4d( + x * inv + target.x * alpha, + y * inv + target.y * alpha, + z * inv + target.z * alpha, + w * inv + target.w * alpha + ) + } + + fun toFloat() = Vector4f(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat()) + fun toInt() = Vector4i(x.toInt(), y.toInt(), z.toInt(), w.toInt()) + fun toVector3d() = Vector3d(x, y, z) + fun toVector2d() = Vector2d(x, y) + + operator fun component1() = x + operator fun component2() = y + operator fun component3() = z + operator fun component4() = w + + fun toGeneric() = Vector4(x, y, z, w) + + override fun toString() = "Vector4d($x, $y, $z, $w)" + override fun equals(other: Any?) = other is Vector4d && x == other.x && y == other.y && z == other.z && w == other.w + override fun hashCode(): Int { + var result = x.hashCode() + result = 31 * result + y.hashCode() + result = 31 * result + z.hashCode() + result = 31 * result + w.hashCode() + return result + } +} @@ -0,0 +1,52 @@ +package com.dropbear.math + +import kotlin.math.sqrt +import kotlin.jvm.JvmField +import kotlin.jvm.JvmStatic + +class Vector4f( + @JvmField var x: Float, + @JvmField var y: Float, + @JvmField var z: Float, + @JvmField var w: Float +) { + companion object { + @JvmStatic + fun zero() = Vector4f(0f, 0f, 0f, 0f) + } + + operator fun plus(other: Vector4f) = Vector4f(x + other.x, y + other.y, z + other.z, w + other.w) + operator fun plus(scalar: Float) = Vector4f(x + scalar, y + scalar, z + scalar, w + scalar) + + operator fun minus(other: Vector4f) = Vector4f(x - other.x, y - other.y, z - other.z, w - other.w) + operator fun minus(scalar: Float) = Vector4f(x - scalar, y - scalar, z - scalar, w - scalar) + + operator fun times(other: Vector4f) = Vector4f(x * other.x, y * other.y, z * other.z, w * other.w) + operator fun times(scalar: Float) = Vector4f(x * scalar, y * scalar, z * scalar, w * scalar) + + operator fun div(other: Vector4f) = Vector4f(x / other.x, y / other.y, z / other.z, w / other.w) + operator fun div(scalar: Float) = Vector4f(x / scalar, y / scalar, z / scalar, w / scalar) + + operator fun unaryMinus() = Vector4f(-x, -y, -z, -w) + + fun length(): Float = sqrt(x * x + y * y + z * z + w * w) + fun lengthSquared(): Float = x * x + y * y + z * z + w * w + + fun dot(other: Vector4f) = x * other.x + y * other.y + z * other.z + w * other.w + + fun normalize(): Vector4f { + val l = length() + return if (l != 0f) Vector4f(x / l, y / l, z / l, w / l) else zero() + } + + fun toDouble() = Vector4d(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble()) + fun toInt() = Vector4i(x.toInt(), y.toInt(), z.toInt(), w.toInt()) + fun toVector3f() = Vector3f(x, y, z) + + operator fun component1() = x + operator fun component2() = y + operator fun component3() = z + operator fun component4() = w + + override fun toString() = "Vector4f($x, $y, $z, $w)" +} @@ -0,0 +1,35 @@ +package com.dropbear.math + +import kotlin.math.sqrt +import kotlin.jvm.JvmField +import kotlin.jvm.JvmStatic + +class Vector4i( + @JvmField var x: Int, + @JvmField var y: Int, + @JvmField var z: Int, + @JvmField var w: Int +) { + companion object { + @JvmStatic + fun zero() = Vector4i(0, 0, 0, 0) + } + + operator fun plus(other: Vector4i) = Vector4i(x + other.x, y + other.y, z + other.z, w + other.w) + operator fun minus(other: Vector4i) = Vector4i(x - other.x, y - other.y, z - other.z, w - other.w) + + operator fun times(scalar: Int) = Vector4i(x * scalar, y * scalar, z * scalar, w * scalar) + operator fun div(scalar: Int) = Vector4i(x / scalar, y / scalar, z / scalar, w / scalar) + + fun length(): Double = sqrt((x * x + y * y + z * z + w * w).toDouble()) + + fun toFloat() = Vector4f(x.toFloat(), y.toFloat(), z.toFloat(), w.toFloat()) + fun toDouble() = Vector4d(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble()) + + operator fun component1() = x + operator fun component2() = y + operator fun component3() = z + operator fun component4() = w + + override fun toString() = "Vector4i($x, $y, $z, $w)" +} @@ -1,7 +1,7 @@ package com.dropbear.physics import com.dropbear.EntityId -import com.dropbear.math.Vector3D +import com.dropbear.math.Vector3d class Collider( internal val index: Index, @@ -23,10 +23,10 @@ class Collider( var isSensor: Boolean get() = getColliderIsSensor(this) set(value) = setColliderIsSensor(this, value) - var translation: Vector3D + var translation: Vector3d get() = getColliderTranslation(this) set(value) = setColliderTranslation(this, value) - var rotation: Vector3D + var rotation: Vector3d get() = getColliderRotation(this) set(value) = setColliderRotation(this, value) var mass: Double @@ -44,9 +44,9 @@ expect fun Collider.getColliderRestitution(collider: Collider): Double expect fun Collider.setColliderRestitution(collider: Collider, restitution: Double) expect fun Collider.getColliderIsSensor(collider: Collider): Boolean expect fun Collider.setColliderIsSensor(collider: Collider, isSensor: Boolean) -expect fun Collider.getColliderTranslation(collider: Collider): Vector3D -expect fun Collider.setColliderTranslation(collider: Collider, translation: Vector3D) -expect fun Collider.getColliderRotation(collider: Collider): Vector3D -expect fun Collider.setColliderRotation(collider: Collider, rotation: Vector3D) +expect fun Collider.getColliderTranslation(collider: Collider): Vector3d +expect fun Collider.setColliderTranslation(collider: Collider, translation: Vector3d) +expect fun Collider.getColliderRotation(collider: Collider): Vector3d +expect fun Collider.setColliderRotation(collider: Collider, rotation: Vector3d) expect fun Collider.getColliderMass(collider: Collider): Double expect fun Collider.setColliderMass(collider: Collider, mass: Double) @@ -1,13 +1,13 @@ package com.dropbear.physics -import com.dropbear.math.Vector3D +import com.dropbear.math.Vector3d sealed class ColliderShape { /** * Box shape with half-extents (half-width, half-height, half-depth). */ - data class Box(val halfExtents: Vector3D) : ColliderShape() + data class Box(val halfExtents: Vector3d) : ColliderShape() /** * Sphere shape with radius. @@ -3,7 +3,7 @@ package com.dropbear.physics import com.dropbear.ecs.Component import com.dropbear.EntityId import com.dropbear.ecs.ComponentType -import com.dropbear.math.Vector3D +import com.dropbear.math.Vector3d class RigidBody( internal val index: Index, @@ -21,10 +21,10 @@ class RigidBody( var ccdEnabled: Boolean get() = getRigidbodyCcdEnabled(this) set(value) = setRigidbodyCcdEnabled(this, value) - var linearVelocity: Vector3D + var linearVelocity: Vector3d get() = getRigidbodyLinearVelocity(this) set(value) = setRigidbodyLinearVelocity(this, value) - var angularVelocity: Vector3D + var angularVelocity: Vector3d get() = getRigidbodyAngularVelocity(this) set(value) = setRigidbodyAngularVelocity(this, value) var linearDamping: Double @@ -48,7 +48,7 @@ class RigidBody( * * Typically used for jumping or explosions. */ - fun applyImpulse(impulse: Vector3D) { + fun applyImpulse(impulse: Vector3d) { applyImpulse(impulse.x, impulse.y, impulse.z) } @@ -66,7 +66,7 @@ class RigidBody( * * Typically used for spinning objects. */ - fun applyTorqueImpulse(impulse: Vector3D) { + fun applyTorqueImpulse(impulse: Vector3d) { applyTorqueImpulse(impulse.x, impulse.y, impulse.z) } @@ -95,10 +95,10 @@ expect fun RigidBody.getRigidbodyCanSleep(rigidBody: RigidBody): Boolean expect fun RigidBody.setRigidbodyCanSleep(rigidBody: RigidBody, canSleep: Boolean) expect fun RigidBody.getRigidbodyCcdEnabled(rigidBody: RigidBody): Boolean expect fun RigidBody.setRigidbodyCcdEnabled(rigidBody: RigidBody, ccdEnabled: Boolean) -expect fun RigidBody.getRigidbodyLinearVelocity(rigidBody: RigidBody): Vector3D -expect fun RigidBody.setRigidbodyLinearVelocity(rigidBody: RigidBody, linearVelocity: Vector3D) -expect fun RigidBody.getRigidbodyAngularVelocity(rigidBody: RigidBody): Vector3D -expect fun RigidBody.setRigidbodyAngularVelocity(rigidBody: RigidBody, angularVelocity: Vector3D) +expect fun RigidBody.getRigidbodyLinearVelocity(rigidBody: RigidBody): Vector3d +expect fun RigidBody.setRigidbodyLinearVelocity(rigidBody: RigidBody, linearVelocity: Vector3d) +expect fun RigidBody.getRigidbodyAngularVelocity(rigidBody: RigidBody): Vector3d +expect fun RigidBody.setRigidbodyAngularVelocity(rigidBody: RigidBody, angularVelocity: Vector3d) expect fun RigidBody.getRigidbodyLinearDamping(rigidBody: RigidBody): Double expect fun RigidBody.setRigidbodyLinearDamping(rigidBody: RigidBody, linearDamping: Double) expect fun RigidBody.getRigidbodyAngularDamping(rigidBody: RigidBody): Double @@ -8,7 +8,9 @@ import com.dropbear.ffi.NativeEngine /** * A handle that allows you to check the state of an async scene load. */ -class SceneLoadHandle(val id: Long, val sceneName: String) { +class SceneLoadHandle(val id: Long) { + val sceneName: String + get() = getSceneLoadHandleSceneName(id) /** * Switches the scene to the requested scene. * @@ -63,6 +65,7 @@ class SceneLoadHandle(val id: Long, val sceneName: String) { } } -expect fun SceneLoadHandle.switchToSceneAsync(): SceneLoadHandle +expect fun SceneLoadHandle.getSceneLoadHandleSceneName(id: Long): String +expect fun SceneLoadHandle.switchToSceneAsync() expect fun SceneLoadHandle.getSceneLoadProgress(): Progress expect fun SceneLoadHandle.getSceneLoadStatus(): SceneLoadStatus @@ -35,15 +35,8 @@ class SceneManager() { fun switchToSceneImmediate(sceneName: String) { return switchToSceneImmediateNative(sceneName) } - - /** - * Fetches the current scene that is currently being rendered. - */ - fun getCurrentScene(): SceneMetadata { - TODO("Not implemented yet...") - } } expect fun SceneManager.loadSceneAsyncNative(sceneName: String): SceneLoadHandle? -expect fun SceneManager.loadSceneAsyncNative(sceneName: String, loading_scene: String): SceneLoadHandle? +expect fun SceneManager.loadSceneAsyncNative(sceneName: String, loadingScene: String): SceneLoadHandle? expect fun SceneManager.switchToSceneImmediateNative(sceneName: String) @@ -1,81 +0,0 @@ -package com.dropbear - -import com.dropbear.math.Vector3D - -actual fun Camera.getCameraEye(entity: EntityId): Vector3D { - TODO("Not yet implemented") -} - -actual fun Camera.setCameraEye(entity: EntityId, value: Vector3D) { -} - -actual fun Camera.getCameraTarget(entity: EntityId): Vector3D { - TODO("Not yet implemented") -} - -actual fun Camera.setCameraTarget(entity: EntityId, value: Vector3D) { -} - -actual fun Camera.getCameraUp(entity: EntityId): Vector3D { - TODO("Not yet implemented") -} - -actual fun Camera.setCameraUp(entity: EntityId, value: Vector3D) { -} - -actual fun Camera.getCameraAspect(entity: EntityId): Double { - TODO("Not yet implemented") -} - -actual fun Camera.getCameraFovY(entity: EntityId): Double { - TODO("Not yet implemented") -} - -actual fun Camera.setCameraFovY(entity: EntityId, value: Double) { -} - -actual fun Camera.getCameraZNear(entity: EntityId): Double { - TODO("Not yet implemented") -} - -actual fun Camera.setCameraZNear(entity: EntityId, value: Double) { -} - -actual fun Camera.getCameraZFar(entity: EntityId): Double { - TODO("Not yet implemented") -} - -actual fun Camera.setCameraZFar(entity: EntityId, value: Double) { -} - -actual fun Camera.getCameraYaw(entity: EntityId): Double { - TODO("Not yet implemented") -} - -actual fun Camera.setCameraYaw(entity: EntityId, value: Double) { -} - -actual fun Camera.getCameraPitch(entity: EntityId): Double { - TODO("Not yet implemented") -} - -actual fun Camera.setCameraPitch(entity: EntityId, value: Double) { -} - -actual fun Camera.getCameraSpeed(entity: EntityId): Double { - TODO("Not yet implemented") -} - -actual fun Camera.setCameraSpeed(entity: EntityId, value: Double) { -} - -actual fun Camera.getCameraSensitivity(entity: EntityId): Double { - TODO("Not yet implemented") -} - -actual fun Camera.setCameraSensitivity(entity: EntityId, value: Double) { -} - -actual fun cameraExistsForEntity(entity: EntityId): Boolean { - TODO("Not yet implemented") -} @@ -1,93 +0,0 @@ -package com.dropbear - -actual fun CustomProperties.getStringProperty( - entityHandle: Long, - label: String -): String? { - TODO("Not yet implemented") -} - -actual fun CustomProperties.getIntProperty(entityHandle: Long, label: String): Int? { - TODO("Not yet implemented") -} - -actual fun CustomProperties.getLongProperty( - entityHandle: Long, - label: String -): Long? { - TODO("Not yet implemented") -} - -actual fun CustomProperties.getDoubleProperty( - entityHandle: Long, - label: String -): Double? { - TODO("Not yet implemented") -} - -actual fun CustomProperties.getFloatProperty( - entityHandle: Long, - label: String -): Float? { - TODO("Not yet implemented") -} - -actual fun CustomProperties.getBoolProperty( - entityHandle: Long, - label: String -): Boolean? { - TODO("Not yet implemented") -} - -actual fun CustomProperties.getVec3Property( - entityHandle: Long, - label: String -): FloatArray? { - TODO("Not yet implemented") -} - -actual fun CustomProperties.setStringProperty( - entityHandle: Long, - label: String, - value: String -) { -} - -actual fun CustomProperties.setIntProperty( - entityHandle: Long, - label: String, - value: Int -) { -} - -actual fun CustomProperties.setLongProperty( - entityHandle: Long, - label: String, - value: Long -) { -} - -actual fun CustomProperties.setFloatProperty( - entityHandle: Long, - label: String, - value: Double -) { -} - -actual fun CustomProperties.setBoolProperty( - entityHandle: Long, - label: String, - value: Boolean -) { -} - -actual fun CustomProperties.setVec3Property( - entityHandle: Long, - label: String, - value: FloatArray -) { -} - -actual fun customPropertiesExistsForEntity(entityId: EntityId): Boolean { - TODO("Not yet implemented") -} @@ -1,16 +1,15 @@ package com.dropbear -actual fun getEntity(label: String): Long? { - TODO("Not yet implemented") -} +import com.dropbear.components.Camera -actual fun getCamera(label: String): Camera? { - TODO("Not yet implemented") +actual fun getEntity(label: String): Long? { + return DropbearEngineNative.getEntity(DropbearEngine.native.worldHandle, label) } actual fun getAsset(eucaURI: String): Long? { - TODO("Not yet implemented") + return DropbearEngineNative.getAsset(DropbearEngine.native.worldHandle, eucaURI) } actual fun quit() { + DropbearEngineNative.quit(DropbearEngine.native.commandBufferHandle) } @@ -0,0 +1,11 @@ +package com.dropbear; + +public class DropbearEngineNative { + static { + new EucalyptusCoreLoader().ensureLoaded(); + } + + public static native Long getEntity(long worldPtr, String label); + public static native Long getAsset(long worldPtr, String label); + public static native void quit(long commandBufferPtr); +} @@ -1,12 +0,0 @@ -package com.dropbear; - -/// Interface for dynamic library loading, allowing for custom components not within the dropbear component -/// library. -public interface DynamicLibraryLoader { - /// Ensures that the library is loaded before accessing - /// any of the JNI static functions. - void ensureLoaded(); - - /// Forces the library to have a loaded boolean variable. - boolean isLoaded(); -} @@ -0,0 +1,7 @@ +package com.dropbear; + +public class EntityRefNative { + static { + new EucalyptusCoreLoader().ensureLoaded(); + } +} @@ -1,31 +0,0 @@ -package com.dropbear - -import com.dropbear.math.Transform - -actual fun EntityTransform.getLocalTransform(entityId: EntityId): Transform { - TODO("Not yet implemented") -} - -actual fun EntityTransform.setLocalTransform( - entityId: EntityId, - transform: Transform -) { -} - -actual fun EntityTransform.getWorldTransform(entityId: EntityId): Transform { - TODO("Not yet implemented") -} - -actual fun EntityTransform.setWorldTransform( - entityId: EntityId, - transform: Transform -) { -} - -actual fun EntityTransform.propagateTransform(entityId: EntityId): Transform { - TODO("Not yet implemented") -} - -actual fun entityTransformExistsForEntity(entityId: EntityId): Boolean { - TODO("Not yet implemented") -} @@ -1,5 +1,7 @@ package com.dropbear; +import com.dropbear.ffi.DynamicLibraryLoader; + import java.lang.System; public class EucalyptusCoreLoader implements DynamicLibraryLoader { @@ -1,37 +0,0 @@ -package com.dropbear - -import com.dropbear.asset.ModelHandle -import com.dropbear.asset.TextureHandle - -actual fun MeshRenderer.getModel(id: EntityId): ModelHandle? { - TODO("Not yet implemented") -} - -actual fun MeshRenderer.setModel(id: EntityId, model: ModelHandle?) { -} - -actual fun MeshRenderer.getAllTextureIds(id: EntityId): List<TextureHandle>? { - TODO("Not yet implemented") -} - -actual fun MeshRenderer.getMaterialNames(id: EntityId): List<String> { - TODO("Not yet implemented") -} - -actual fun MeshRenderer.setMaterialNames(id: EntityId, names: Array<String>) { -} - -actual fun MeshRenderer.getTexture(id: EntityId, materialName: String): Long { - TODO("Not yet implemented") -} - -actual fun MeshRenderer.setTextureOverride( - id: EntityId, - materialName: String, - textureHandle: Long -) { -} - -actual fun meshRendererExistsForEntity(entityId: EntityId): Boolean { - TODO("Not yet implemented") -} @@ -1,9 +1,11 @@ package com.dropbear.asset -actual fun AssetHandle.asTextureHandle(): TextureHandle? { - TODO("Not yet implemented") -} +import com.dropbear.DropbearEngine actual fun isModelHandle(id: Long): Boolean { - TODO("Not yet implemented") + return AssetHandleNative.isModelHandle(DropbearEngine.native.assetHandle, id) +} + +actual fun isTextureHandle(id: Long): Boolean { + return AssetHandleNative.isTextureHandle(DropbearEngine.native.assetHandle, id) } @@ -0,0 +1,12 @@ +package com.dropbear.asset; + +import com.dropbear.EucalyptusCoreLoader; + +public class AssetHandleNative { + static { + new EucalyptusCoreLoader().ensureLoaded(); + } + + public static native boolean isModelHandle(long assetRegistryHandle, long handle); + public static native boolean isTextureHandle(long assetRegistryHandle, long handle); +} @@ -1,5 +1,7 @@ package com.dropbear.asset +import com.dropbear.DropbearEngine + actual fun TextureHandle.getTextureName(id: Long): String? { - TODO("Not yet implemented") + return TextureHandleNative.getTextureName(DropbearEngine.native.assetHandle, id) } @@ -0,0 +1,11 @@ +package com.dropbear.asset; + +import com.dropbear.EucalyptusCoreLoader; + +public class TextureHandleNative { + static { + new EucalyptusCoreLoader().ensureLoaded(); + } + + public static native String getTextureName(long assetRegistryHandle, long handle); +} @@ -0,0 +1,96 @@ +package com.dropbear.components + +import com.dropbear.DropbearEngine +import com.dropbear.EntityId +import com.dropbear.math.Vector3d + +actual fun Camera.getCameraEye(entity: EntityId): Vector3d { + return CameraNative.getCameraEye(DropbearEngine.native.worldHandle, entity.raw) + ?: Vector3d.zero() +} + +actual fun Camera.setCameraEye(entity: EntityId, value: Vector3d) { + CameraNative.setCameraEye(DropbearEngine.native.worldHandle, entity.raw, value) +} + +actual fun Camera.getCameraTarget(entity: EntityId): Vector3d { + return CameraNative.getCameraTarget(DropbearEngine.native.worldHandle, entity.raw) + ?: Vector3d.zero() +} + +actual fun Camera.setCameraTarget(entity: EntityId, value: Vector3d) { + CameraNative.setCameraTarget(DropbearEngine.native.worldHandle, entity.raw, value) +} + +actual fun Camera.getCameraUp(entity: EntityId): Vector3d { + return CameraNative.getCameraUp(DropbearEngine.native.worldHandle, entity.raw) + ?: Vector3d.up() +} + +actual fun Camera.setCameraUp(entity: EntityId, value: Vector3d) { + CameraNative.setCameraUp(DropbearEngine.native.worldHandle, entity.raw, value) +} + +actual fun Camera.getCameraAspect(entity: EntityId): Double { + return CameraNative.getCameraAspect(DropbearEngine.native.worldHandle, entity.raw) +} + +actual fun Camera.getCameraFovY(entity: EntityId): Double { + return CameraNative.getCameraFovY(DropbearEngine.native.worldHandle, entity.raw) +} + +actual fun Camera.setCameraFovY(entity: EntityId, value: Double) { + CameraNative.setCameraFovY(DropbearEngine.native.worldHandle, entity.raw, value) +} + +actual fun Camera.getCameraZNear(entity: EntityId): Double { + return CameraNative.getCameraZNear(DropbearEngine.native.worldHandle, entity.raw) +} + +actual fun Camera.setCameraZNear(entity: EntityId, value: Double) { + CameraNative.setCameraZNear(DropbearEngine.native.worldHandle, entity.raw, value) +} + +actual fun Camera.getCameraZFar(entity: EntityId): Double { + return CameraNative.getCameraZFar(DropbearEngine.native.worldHandle, entity.raw) +} + +actual fun Camera.setCameraZFar(entity: EntityId, value: Double) { + CameraNative.setCameraZFar(DropbearEngine.native.worldHandle, entity.raw, value) +} + +actual fun Camera.getCameraYaw(entity: EntityId): Double { + return CameraNative.getCameraYaw(DropbearEngine.native.worldHandle, entity.raw) +} + +actual fun Camera.setCameraYaw(entity: EntityId, value: Double) { + CameraNative.setCameraYaw(DropbearEngine.native.worldHandle, entity.raw, value) +} + +actual fun Camera.getCameraPitch(entity: EntityId): Double { + return CameraNative.getCameraPitch(DropbearEngine.native.worldHandle, entity.raw) +} + +actual fun Camera.setCameraPitch(entity: EntityId, value: Double) { + CameraNative.setCameraPitch(DropbearEngine.native.worldHandle, entity.raw, value) +} + +actual fun Camera.getCameraSpeed(entity: EntityId): Double { + return CameraNative.getCameraSpeed(DropbearEngine.native.worldHandle, entity.raw) +} + +actual fun Camera.setCameraSpeed(entity: EntityId, value: Double) { + CameraNative.setCameraSpeed(DropbearEngine.native.worldHandle, entity.raw, value) +} + +actual fun Camera.getCameraSensitivity(entity: EntityId): Double { + return CameraNative.getCameraSensitivity(DropbearEngine.native.worldHandle, entity.raw) +} + +actual fun Camera.setCameraSensitivity(entity: EntityId, value: Double) { + CameraNative.setCameraSensitivity(DropbearEngine.native.worldHandle, entity.raw, value) +} + +actual fun cameraExistsForEntity(entity: EntityId): Boolean { + return CameraNative.cameraExistsForEntity(DropbearEngine.native.worldHandle, entity.raw) +} @@ -0,0 +1,44 @@ +package com.dropbear.components; + +import com.dropbear.EucalyptusCoreLoader; +import com.dropbear.math.Vector3d; + +public class CameraNative { + static { + new EucalyptusCoreLoader().ensureLoaded(); + } + + public static native boolean cameraExistsForEntity(long worldHandle, long entityId); + + public static native Vector3d getCameraEye(long worldHandle, long entityId); + public static native void setCameraEye(long worldHandle, long entityId, Vector3d value); + + public static native Vector3d getCameraTarget(long worldHandle, long entityId); + public static native void setCameraTarget(long worldHandle, long entityId, Vector3d value); + + public static native Vector3d getCameraUp(long worldHandle, long entityId); + public static native void setCameraUp(long worldHandle, long entityId, Vector3d value); + + public static native double getCameraAspect(long worldHandle, long entityId); + + public static native double getCameraFovY(long worldHandle, long entityId); + public static native void setCameraFovY(long worldHandle, long entityId, double value); + + public static native double getCameraZNear(long worldHandle, long entityId); + public static native void setCameraZNear(long worldHandle, long entityId, double value); + + public static native double getCameraZFar(long worldHandle, long entityId); + public static native void setCameraZFar(long worldHandle, long entityId, double value); + + public static native double getCameraYaw(long worldHandle, long entityId); + public static native void setCameraYaw(long worldHandle, long entityId, double value); + + public static native double getCameraPitch(long worldHandle, long entityId); + public static native void setCameraPitch(long worldHandle, long entityId, double value); + + public static native double getCameraSpeed(long worldHandle, long entityId); + public static native void setCameraSpeed(long worldHandle, long entityId, double value); + + public static native double getCameraSensitivity(long worldHandle, long entityId); + public static native void setCameraSensitivity(long worldHandle, long entityId, double value); +} @@ -0,0 +1,103 @@ +package com.dropbear.components + +import com.dropbear.DropbearEngine +import com.dropbear.EntityId +import com.dropbear.math.Vector3d + +actual fun CustomProperties.getStringProperty( + entityHandle: Long, + label: String +): String? { + return CustomPropertiesNative.getStringProperty(DropbearEngine.native.worldHandle, entityHandle, label) +} + +actual fun CustomProperties.getIntProperty(entityHandle: Long, label: String): Int? { + return CustomPropertiesNative.getIntProperty(DropbearEngine.native.worldHandle, entityHandle, label) +} + +actual fun CustomProperties.getLongProperty( + entityHandle: Long, + label: String +): Long? { + return CustomPropertiesNative.getLongProperty(DropbearEngine.native.worldHandle, entityHandle, label) +} + +actual fun CustomProperties.getDoubleProperty( + entityHandle: Long, + label: String +): Double? { + return CustomPropertiesNative.getDoubleProperty(DropbearEngine.native.worldHandle, entityHandle, label) +} + +actual fun CustomProperties.getFloatProperty( + entityHandle: Long, + label: String +): Float? { + return CustomPropertiesNative.getFloatProperty(DropbearEngine.native.worldHandle, entityHandle, label) +} + +actual fun CustomProperties.getBoolProperty( + entityHandle: Long, + label: String +): Boolean? { + return CustomPropertiesNative.getBoolProperty(DropbearEngine.native.worldHandle, entityHandle, label) +} + +actual fun CustomProperties.getVec3Property( + entityHandle: Long, + label: String +): Vector3d? { + return CustomPropertiesNative.getVec3Property(DropbearEngine.native.worldHandle, entityHandle, label) +} + +actual fun CustomProperties.setStringProperty( + entityHandle: Long, + label: String, + value: String +) { + CustomPropertiesNative.setStringProperty(DropbearEngine.native.worldHandle, entityHandle, label, value) +} + +actual fun CustomProperties.setIntProperty( + entityHandle: Long, + label: String, + value: Int +) { + CustomPropertiesNative.setIntProperty(DropbearEngine.native.worldHandle, entityHandle, label, value) +} + +actual fun CustomProperties.setLongProperty( + entityHandle: Long, + label: String, + value: Long +) { + CustomPropertiesNative.setLongProperty(DropbearEngine.native.worldHandle, entityHandle, label, value) +} + +actual fun CustomProperties.setFloatProperty( + entityHandle: Long, + label: String, + value: Double +) { + CustomPropertiesNative.setFloatProperty(DropbearEngine.native.worldHandle, entityHandle, label, value) +} + +actual fun CustomProperties.setBoolProperty( + entityHandle: Long, + label: String, + value: Boolean +) { + CustomPropertiesNative.setBoolProperty(DropbearEngine.native.worldHandle, entityHandle, label, value) +} + +actual fun CustomProperties.setVec3Property( + entityHandle: Long, + label: String, + value: Vector3d +) { + CustomPropertiesNative.setVec3Property(DropbearEngine.native.worldHandle, entityHandle, label, value) +} + +actual fun customPropertiesExistsForEntity(entityId: EntityId): Boolean { + return CustomPropertiesNative.customPropertiesExistsForEntity(DropbearEngine.native.worldHandle, entityId.raw) +} @@ -0,0 +1,27 @@ +package com.dropbear.components; + +import com.dropbear.EucalyptusCoreLoader; +import com.dropbear.math.Vector3d; + +public class CustomPropertiesNative { + static { + new EucalyptusCoreLoader().ensureLoaded(); + } + + public static native boolean customPropertiesExistsForEntity(long worldHandle, long entityId); + + public static native String getStringProperty(long worldHandle, long entityId, String label); + public static native Integer getIntProperty(long worldHandle, long entityId, String label); + public static native Long getLongProperty(long worldHandle, long entityId, String label); + public static native Double getDoubleProperty(long worldHandle, long entityId, String label); + public static native Float getFloatProperty(long worldHandle, long entityId, String label); + public static native Boolean getBoolProperty(long worldHandle, long entityId, String label); + public static native Vector3d getVec3Property(long worldHandle, long entityId, String label); + + public static native void setStringProperty(long worldHandle, long entityId, String label, String value); + public static native void setIntProperty(long worldHandle, long entityId, String label, int value); + public static native void setLongProperty(long worldHandle, long entityId, String label, long value); + public static native void setFloatProperty(long worldHandle, long entityId, String label, double value); + public static native void setBoolProperty(long worldHandle, long entityId, String label, boolean value); + public static native void setVec3Property(long worldHandle, long entityId, String label, Vector3d value); +} @@ -0,0 +1,43 @@ +package com.dropbear.components + +import com.dropbear.DropbearEngine +import com.dropbear.EntityId +import com.dropbear.math.Transform + +actual fun entityTransformExistsForEntity(entityId: EntityId): Boolean { + return EntityTransformNative.entityTransformExistsForEntity(DropbearEngine.native.worldHandle, entityId.raw) +} + +actual fun EntityTransform.getLocalTransform(entityId: EntityId): Transform { + return EntityTransformNative.getLocalTransform(DropbearEngine.native.worldHandle, entityId.raw) +} + +actual fun EntityTransform.setLocalTransform( + entityId: EntityId, + transform: Transform +) { + EntityTransformNative.setLocalTransform( + DropbearEngine.native.worldHandle, + entityId.raw, + transform + ) +} + +actual fun EntityTransform.getWorldTransform(entityId: EntityId): Transform { + return EntityTransformNative.getWorldTransform(DropbearEngine.native.worldHandle, entityId.raw) +} + +actual fun EntityTransform.setWorldTransform( + entityId: EntityId, + transform: Transform +) { + EntityTransformNative.setWorldTransform( + DropbearEngine.native.worldHandle, + entityId.raw, + transform + ) +} + +actual fun EntityTransform.propagateTransform(entityId: EntityId): Transform { + return EntityTransformNative.propagateTransform(DropbearEngine.native.worldHandle, entityId.raw) +} @@ -0,0 +1,18 @@ +package com.dropbear.components; + +import com.dropbear.EucalyptusCoreLoader; +import com.dropbear.math.Transform; + +public class EntityTransformNative { + static { + new EucalyptusCoreLoader().ensureLoaded(); + } + + public static native boolean entityTransformExistsForEntity(long worldPtr, long entityId); + + public static native Transform getLocalTransform(long worldPtr, long entityId); + public static native void setLocalTransform(long worldPtr, long entityId, Transform transform); + public static native Transform getWorldTransform(long worldPtr, long entityId); + public static native void setWorldTransform(long worldPtr, long entityId, Transform transform); + public static native Transform propagateTransform(long worldPtr, long entityId); +} @@ -0,0 +1,60 @@ +package com.dropbear.components + +import com.dropbear.DropbearEngine +import com.dropbear.EntityId +import com.dropbear.asset.ModelHandle +import com.dropbear.asset.TextureHandle + +actual fun MeshRenderer.getModel(id: EntityId): ModelHandle? { + return ModelHandle(MeshRendererNative.getModel(DropbearEngine.native.worldHandle, id.raw)) +} + +actual fun MeshRenderer.setModel(id: EntityId, model: ModelHandle?) { + if (model == null) { + MeshRendererNative.setModel(DropbearEngine.native.worldHandle, id.raw, 0L) + return + } + + return MeshRendererNative.setModel( + DropbearEngine.native.worldHandle, + id.raw, + model.raw() + ) +} + +actual fun MeshRenderer.getAllTextureIds(id: EntityId): List<TextureHandle>? { + val textureHandles = MeshRendererNative.getAllTextureIds( + DropbearEngine.native.worldHandle, + id.raw + ) ?: return null + + return textureHandles.map { TextureHandle(it) } +} + +actual fun MeshRenderer.getTexture(id: EntityId, materialName: String): Long { + return MeshRendererNative.getTexture( + DropbearEngine.native.worldHandle, + id.raw, + materialName + ) +} + +actual fun MeshRenderer.setTextureOverride( + id: EntityId, + materialName: String, + textureHandle: Long +) { + return MeshRendererNative.setTextureOverride( + DropbearEngine.native.worldHandle, + id.raw, + materialName, + textureHandle + ) +} + +actual fun meshRendererExistsForEntity(entityId: EntityId): Boolean { + return MeshRendererNative.meshRendererExistsForEntity( + DropbearEngine.native.worldHandle, + entityId.raw + ) +} @@ -0,0 +1,17 @@ +package com.dropbear.components; + +import com.dropbear.EucalyptusCoreLoader; + +public class MeshRendererNative { + static { + new EucalyptusCoreLoader().ensureLoaded(); + } + + public static native boolean meshRendererExistsForEntity(long worldHandle, long entityId); + + public static native long getModel(long worldHandle, long entityId); + public static native void setModel(long worldHandle, long entityId, long modelHandle); + public static native long[] getAllTextureIds(long worldHandle, long entityId); + public static native long getTexture(long worldHandle, long entityId, String materialName); + public static native void setTextureOverride(long worldHandle, long entityId, String materialName, long textureHandle); +} @@ -0,0 +1,12 @@ +package com.dropbear.ffi; + +/// Interface for dynamic library loading, allowing for custom components not within the dropbear component +/// library. +public interface DynamicLibraryLoader { + /// Ensures that the library is loaded before accessing + /// any of the JNI static functions. + void ensureLoaded(); + + /// Forces the library to have a loaded boolean variable. + boolean isLoaded(); +} @@ -1,8 +1,35 @@ package com.dropbear.input +import com.dropbear.DropbearEngine +import com.dropbear.math.Vector2d + actual fun Gamepad.isGamepadButtonPressed( id: Long, button: GamepadButton ): Boolean { - TODO("Not yet implemented") + return GamepadNative.isGamepadButtonPressed( + DropbearEngine.native.inputHandle, + id, + button.ordinal + ) +} + +@Suppress("UNCHECKED_CAST") +actual fun Gamepad.getLeftStickPosition(id: Long): Vector2d { + val result = GamepadNative.getLeftStickPosition( + DropbearEngine.native.inputHandle, + id + ) + + return result ?: Vector2d.zero() +} + +@Suppress("UNCHECKED_CAST") +actual fun Gamepad.getRightStickPosition(id: Long): Vector2d { + val result = GamepadNative.getRightStickPosition( + DropbearEngine.native.inputHandle, + id + ) + + return result ?: Vector2d.zero() } @@ -0,0 +1,15 @@ +package com.dropbear.input; + +import com.dropbear.EucalyptusCoreLoader; +import com.dropbear.math.Vector2; +import com.dropbear.math.Vector2d; + +public class GamepadNative { + static { + new EucalyptusCoreLoader().ensureLoaded(); + } + + public static native boolean isGamepadButtonPressed(long inputStateHandle, long gamepad, int gamepadButton); + public static native Vector2d getLeftStickPosition(long inputStateHandle, long gamepad); + public static native Vector2d getRightStickPosition(long inputStateHandle, long gamepad); +} @@ -1,46 +1,51 @@ package com.dropbear.input -import com.dropbear.math.Vector2D +import com.dropbear.DropbearEngine +import com.dropbear.math.Vector2d actual class InputState actual constructor() { actual fun printInputState() { + return InputStateNative.printInputState(DropbearEngine.native.inputHandle) } actual fun isKeyPressed(key: KeyCode): Boolean { - TODO("Not yet implemented") + return InputStateNative.isKeyPressed(DropbearEngine.native.inputHandle, key.ordinal) } - actual fun getMousePosition(): Vector2D { - TODO("Not yet implemented") + actual fun getMousePosition(): Vector2d { + return InputStateNative.getMousePosition(DropbearEngine.native.inputHandle) } actual fun isMouseButtonPressed(button: MouseButton): Boolean { - TODO("Not yet implemented") + return InputStateNative.isMouseButtonPressed(DropbearEngine.native.inputHandle, button) } - actual fun getMouseDelta(): Vector2D { - TODO("Not yet implemented") + actual fun getMouseDelta(): Vector2d { + return InputStateNative.getMouseDelta(DropbearEngine.native.inputHandle) } actual fun isCursorLocked(): Boolean { - TODO("Not yet implemented") + return InputStateNative.isCursorLocked(DropbearEngine.native.inputHandle) } actual fun setCursorLocked(locked: Boolean) { + return InputStateNative.setCursorLocked(DropbearEngine.native.commandBufferHandle, DropbearEngine.native.inputHandle, locked) } - actual fun getLastMousePos(): Vector2D { - TODO("Not yet implemented") + actual fun getLastMousePos(): Vector2d { + return InputStateNative.getLastMousePos(DropbearEngine.native.inputHandle) } actual fun isCursorHidden(): Boolean { - TODO("Not yet implemented") + return InputStateNative.isCursorHidden(DropbearEngine.native.inputHandle) } actual fun setCursorHidden(hidden: Boolean) { + return InputStateNative.setCursorHidden(DropbearEngine.native.commandBufferHandle, DropbearEngine.native.inputHandle, hidden) } actual fun getConnectedGamepads(): List<Gamepad> { - TODO("Not yet implemented") + val result = InputStateNative.getConnectedGamepads(DropbearEngine.native.inputHandle) + return result.map { Gamepad(it) }.toList() } } @@ -0,0 +1,22 @@ +package com.dropbear.input; + +import com.dropbear.EucalyptusCoreLoader; +import com.dropbear.math.Vector2d; + +public class InputStateNative { + static { + new EucalyptusCoreLoader().ensureLoaded(); + } + + public static native void printInputState(long inputStateHandle); + public static native boolean isKeyPressed(long inputStateHandle, int keyCode); + public static native Vector2d getMousePosition(long inputStateHandle); + public static native boolean isMouseButtonPressed(long inputStateHandle, MouseButton mouseButton); + public static native Vector2d getMouseDelta(long inputStateHandle); + public static native boolean isCursorLocked(long inputStateHandle); + public static native void setCursorLocked(long commandBufferPtr, long inputStateHandle, boolean locked); + public static native Vector2d getLastMousePos(long inputStateHandle); + public static native boolean isCursorHidden(long inputStateHandle); + public static native void setCursorHidden(long commandBufferPtr, long inputStateHandle, boolean hidden); + public static native long[] getConnectedGamepads(long inputStateHandle); +} @@ -1,80 +1,91 @@ package com.dropbear.physics -import com.dropbear.math.Vector3D +import com.dropbear.DropbearEngine +import com.dropbear.math.Vector3d actual fun Collider.getColliderShape(collider: Collider): ColliderShape { - TODO("Not yet implemented") + return ColliderNative.getColliderShape(DropbearEngine.native.physicsEngineHandle, this) } actual fun Collider.setColliderShape( collider: Collider, shape: ColliderShape ) { + ColliderNative.setColliderShape(DropbearEngine.native.physicsEngineHandle, this, shape) +} + +actual fun Collider.getColliderDensity(collider: Collider): Double { + return ColliderNative.getColliderDensity(DropbearEngine.native.physicsEngineHandle, this) } actual fun Collider.setColliderDensity( collider: Collider, density: Double ) { + ColliderNative.setColliderDensity(DropbearEngine.native.physicsEngineHandle, this, density) } actual fun Collider.getColliderFriction(collider: Collider): Double { - TODO("Not yet implemented") + return ColliderNative.getColliderFriction(DropbearEngine.native.physicsEngineHandle, this) } actual fun Collider.setColliderFriction( collider: Collider, friction: Double ) { + ColliderNative.setColliderFriction(DropbearEngine.native.physicsEngineHandle, this, friction) } actual fun Collider.getColliderRestitution(collider: Collider): Double { - TODO("Not yet implemented") + return ColliderNative.getColliderRestitution(DropbearEngine.native.physicsEngineHandle, this) } actual fun Collider.setColliderRestitution( collider: Collider, restitution: Double ) { + ColliderNative.setColliderRestitution(DropbearEngine.native.physicsEngineHandle, this, restitution) } actual fun Collider.getColliderIsSensor(collider: Collider): Boolean { - TODO("Not yet implemented") + return ColliderNative.getColliderIsSensor(DropbearEngine.native.physicsEngineHandle, this) } actual fun Collider.setColliderIsSensor( collider: Collider, isSensor: Boolean ) { + ColliderNative.setColliderIsSensor(DropbearEngine.native.physicsEngineHandle, this, isSensor) } -actual fun Collider.getColliderTranslation(collider: Collider): Vector3D { - TODO("Not yet implemented") +actual fun Collider.getColliderTranslation(collider: Collider): Vector3d { + return ColliderNative.getColliderTranslation(DropbearEngine.native.physicsEngineHandle, this) + ?: Vector3d.zero() } actual fun Collider.setColliderTranslation( collider: Collider, - translation: Vector3D + translation: Vector3d ) { + ColliderNative.setColliderTranslation(DropbearEngine.native.physicsEngineHandle, this, translation) +} + +actual fun Collider.getColliderRotation(collider: Collider): Vector3d { + return ColliderNative.getColliderRotation(DropbearEngine.native.physicsEngineHandle, this) + ?: Vector3d.zero() } actual fun Collider.setColliderRotation( collider: Collider, - rotation: Vector3D + rotation: Vector3d ) { -} - -actual fun Collider.getColliderRotation(collider: Collider): Vector3D { - TODO("Not yet implemented") + ColliderNative.setColliderRotation(DropbearEngine.native.physicsEngineHandle, this, rotation) } actual fun Collider.getColliderMass(collider: Collider): Double { - TODO("Not yet implemented") + return ColliderNative.getColliderMass(DropbearEngine.native.physicsEngineHandle, this) } actual fun Collider.setColliderMass(collider: Collider, mass: Double) { -} - -actual fun Collider.getColliderDensity(collider: Collider): Double { - TODO("Not yet implemented") + ColliderNative.setColliderMass(DropbearEngine.native.physicsEngineHandle, this, mass) } @@ -1,11 +1,12 @@ package com.dropbear.physics +import com.dropbear.DropbearEngine import com.dropbear.EntityId actual fun ColliderGroup.getColliderGroupColliders(colliderGroup: ColliderGroup): List<Collider> { - TODO("Not yet implemented") + return ColliderGroupNative.getColliderGroupColliders(DropbearEngine.native.physicsEngineHandle, colliderGroup).toList() } actual fun colliderGroupExistsForEntity(entityId: EntityId): Boolean { - TODO("Not yet implemented") + return ColliderGroupNative.colliderGroupExistsForEntity(DropbearEngine.native.worldHandle, entityId.raw) } @@ -0,0 +1,12 @@ +package com.dropbear.physics; + +import com.dropbear.EucalyptusCoreLoader; + +public class ColliderGroupNative { + static { + new EucalyptusCoreLoader().ensureLoaded(); + } + + public static native Collider[] getColliderGroupColliders(long physicsPtr, ColliderGroup colliderGroup); + public static native boolean colliderGroupExistsForEntity(long worldPtr, long entityId); +} @@ -0,0 +1,34 @@ +package com.dropbear.physics; + +import com.dropbear.EucalyptusCoreLoader; +import com.dropbear.math.Vector3d; + +public class ColliderNative { + static { + new EucalyptusCoreLoader().ensureLoaded(); + } + + public static native ColliderShape getColliderShape(long physicsPtr, Collider collider); + public static native void setColliderShape(long physicsPtr, Collider collider, ColliderShape shape); + + public static native double getColliderDensity(long physicsPtr, Collider collider); + public static native void setColliderDensity(long physicsPtr, Collider collider, double density); + + public static native double getColliderFriction(long physicsPtr, Collider collider); + public static native void setColliderFriction(long physicsPtr, Collider collider, double friction); + + public static native double getColliderRestitution(long physicsPtr, Collider collider); + public static native void setColliderRestitution(long physicsPtr, Collider collider, double restitution); + + public static native double getColliderMass(long physicsPtr, Collider collider); + public static native void setColliderMass(long physicsPtr, Collider collider, double mass); + + public static native boolean getColliderIsSensor(long physicsPtr, Collider collider); + public static native void setColliderIsSensor(long physicsPtr, Collider collider, boolean isSensor); + + public static native Vector3d getColliderTranslation(long physicsPtr, Collider collider); + public static native void setColliderTranslation(long physicsPtr, Collider collider, Vector3d translation); + + public static native Vector3d getColliderRotation(long physicsPtr, Collider collider); + public static native void setColliderRotation(long physicsPtr, Collider collider, Vector3d rotation); +} @@ -1,110 +1,133 @@ package com.dropbear.physics +import com.dropbear.DropbearEngine import com.dropbear.EntityId -import com.dropbear.math.Vector3D +import com.dropbear.math.Vector3d actual fun RigidBody.getRigidbodyMode(rigidBody: RigidBody): RigidBodyMode { - TODO("Not yet implemented") + val result = RigidBodyNative.getRigidBodyMode(DropbearEngine.native.physicsEngineHandle, this) + return RigidBodyMode.entries[result] } actual fun RigidBody.setRigidbodyMode( rigidBody: RigidBody, mode: RigidBodyMode ) { + RigidBodyNative.setRigidBodyMode(DropbearEngine.native.physicsEngineHandle, this, mode.ordinal) } actual fun RigidBody.getRigidbodyGravityScale(rigidBody: RigidBody): Double { - TODO("Not yet implemented") + return RigidBodyNative.getRigidBodyGravityScale(DropbearEngine.native.physicsEngineHandle, this) } actual fun RigidBody.setRigidbodyGravityScale( rigidBody: RigidBody, gravityScale: Double ) { + RigidBodyNative.setRigidBodyGravityScale(DropbearEngine.native.physicsEngineHandle, this, gravityScale) } actual fun RigidBody.getRigidbodyCanSleep(rigidBody: RigidBody): Boolean { - TODO("Not yet implemented") + return RigidBodyNative.getRigidBodyCanSleep(DropbearEngine.native.physicsEngineHandle, this) } actual fun RigidBody.setRigidbodyCanSleep( rigidBody: RigidBody, canSleep: Boolean ) { + RigidBodyNative.setRigidBodyCanSleep(DropbearEngine.native.physicsEngineHandle, this, canSleep) } actual fun RigidBody.getRigidbodyCcdEnabled(rigidBody: RigidBody): Boolean { - TODO("Not yet implemented") + return RigidBodyNative.getRigidBodyCcdEnabled(DropbearEngine.native.physicsEngineHandle, this) } actual fun RigidBody.setRigidbodyCcdEnabled( rigidBody: RigidBody, ccdEnabled: Boolean ) { + RigidBodyNative.setRigidBodyCcdEnabled(DropbearEngine.native.physicsEngineHandle, this, ccdEnabled) } -actual fun RigidBody.getRigidbodyLinearVelocity(rigidBody: RigidBody): Vector3D { - TODO("Not yet implemented") +actual fun RigidBody.getRigidbodyLinearVelocity(rigidBody: RigidBody): Vector3d { + return RigidBodyNative.getRigidBodyLinearVelocity(DropbearEngine.native.physicsEngineHandle, this) + ?: Vector3d.zero() } actual fun RigidBody.setRigidbodyLinearVelocity( rigidBody: RigidBody, - linearVelocity: Vector3D + linearVelocity: Vector3d ) { + RigidBodyNative.setRigidBodyLinearVelocity(DropbearEngine.native.physicsEngineHandle, this, linearVelocity) } -actual fun RigidBody.getRigidbodyAngularVelocity(rigidBody: RigidBody): Vector3D { - TODO("Not yet implemented") +actual fun RigidBody.getRigidbodyAngularVelocity(rigidBody: RigidBody): Vector3d { + return RigidBodyNative.getRigidBodyAngularVelocity(DropbearEngine.native.physicsEngineHandle, this) + ?: Vector3d.zero() } actual fun RigidBody.setRigidbodyAngularVelocity( rigidBody: RigidBody, - angularVelocity: Vector3D + angularVelocity: Vector3d ) { + RigidBodyNative.setRigidBodyAngularVelocity(DropbearEngine.native.physicsEngineHandle, this, angularVelocity) } actual fun RigidBody.getRigidbodyLinearDamping(rigidBody: RigidBody): Double { - TODO("Not yet implemented") + return RigidBodyNative.getRigidBodyLinearDamping(DropbearEngine.native.physicsEngineHandle, this) +} + +actual fun RigidBody.setRigidbodyLinearDamping( + rigidBody: RigidBody, + linearDamping: Double +) { + RigidBodyNative.setRigidBodyLinearDamping(DropbearEngine.native.physicsEngineHandle, this, linearDamping) } actual fun RigidBody.getRigidbodyAngularDamping(rigidBody: RigidBody): Double { - TODO("Not yet implemented") + return RigidBodyNative.getRigidBodyAngularDamping(DropbearEngine.native.physicsEngineHandle, this) } actual fun RigidBody.setRigidbodyAngularDamping( rigidBody: RigidBody, angularDamping: Double ) { + RigidBodyNative.setRigidBodyAngularDamping(DropbearEngine.native.physicsEngineHandle, this, angularDamping) } actual fun RigidBody.getRigidbodyLockTranslation(rigidBody: RigidBody): AxisLock { - TODO("Not yet implemented") + return RigidBodyNative.getRigidBodyLockTranslation(DropbearEngine.native.physicsEngineHandle, this) } actual fun RigidBody.setRigidbodyLockTranslation( rigidBody: RigidBody, lockTranslation: AxisLock ) { + RigidBodyNative.setRigidBodyLockTranslation(DropbearEngine.native.physicsEngineHandle, this, lockTranslation) } actual fun RigidBody.getRigidbodyLockRotation(rigidBody: RigidBody): AxisLock { - TODO("Not yet implemented") + return RigidBodyNative.getRigidBodyLockRotation(DropbearEngine.native.physicsEngineHandle, this) } actual fun RigidBody.setRigidbodyLockRotation( rigidBody: RigidBody, lockRotation: AxisLock ) { + RigidBodyNative.setRigidBodyLockRotation(DropbearEngine.native.physicsEngineHandle, this, lockRotation) } actual fun RigidBody.getRigidbodyChildren(rigidBody: RigidBody): List<EntityId> { - TODO("Not yet implemented") + val result = RigidBodyNative.getRigidBodyChildren(DropbearEngine.native.physicsEngineHandle, this) + return result.map { EntityId(it) } } actual fun RigidBody.setRigidbodyChildren( rigidBody: RigidBody, children: List<EntityId> ) { + val ids = children.map { it.raw }.toLongArray() + RigidBodyNative.setRigidBodyChildren(DropbearEngine.native.physicsEngineHandle, this, ids) } actual fun RigidBody.applyImpulse( @@ -113,6 +136,7 @@ actual fun RigidBody.applyImpulse( y: Double, z: Double ) { + RigidBodyNative.applyImpulse(DropbearEngine.native.physicsEngineHandle, this, x, y, z) } actual fun RigidBody.applyTorqueImpulse( @@ -121,15 +145,9 @@ actual fun RigidBody.applyTorqueImpulse( y: Double, z: Double ) { -} - -actual fun RigidBody. - setRigidbodyLinearDamping( - rigidBody: RigidBody, - linearDamping: Double -) { + RigidBodyNative.applyTorqueImpulse(DropbearEngine.native.physicsEngineHandle, this, x, y, z) } actual fun rigidBodyExistsForEntity(entityId: EntityId): Index? { - TODO("Not yet implemented") + return RigidBodyNative.rigidBodyExistsForEntity(DropbearEngine.native.physicsEngineHandle, entityId.raw) } @@ -0,0 +1,48 @@ +package com.dropbear.physics; + +import com.dropbear.EucalyptusCoreLoader; +import com.dropbear.math.Vector3d; + +public class RigidBodyNative { + static { + new EucalyptusCoreLoader().ensureLoaded(); + } + + public static native Index rigidBodyExistsForEntity(long physicsPtr, long entityId); + + public static native int getRigidBodyMode(long physicsPtr, RigidBody rigidBody); + public static native void setRigidBodyMode(long physicsPtr, RigidBody rigidBody, int mode); + + public static native double getRigidBodyGravityScale(long physicsPtr, RigidBody rigidBody); + public static native void setRigidBodyGravityScale(long physicsPtr, RigidBody rigidBody, double gravityScale); + + public static native double getRigidBodyLinearDamping(long physicsPtr, RigidBody rigidBody); + public static native void setRigidBodyLinearDamping(long physicsPtr, RigidBody rigidBody, double linearDamping); + + public static native double getRigidBodyAngularDamping(long physicsPtr, RigidBody rigidBody); + public static native void setRigidBodyAngularDamping(long physicsPtr, RigidBody rigidBody, double angularDamping); + + public static native boolean getRigidBodyCanSleep(long physicsPtr, RigidBody rigidBody); + public static native void setRigidBodyCanSleep(long physicsPtr, RigidBody rigidBody, boolean canSleep); + + public static native boolean getRigidBodyCcdEnabled(long physicsPtr, RigidBody rigidBody); + public static native void setRigidBodyCcdEnabled(long physicsPtr, RigidBody rigidBody, boolean ccdEnabled); + + public static native Vector3d getRigidBodyLinearVelocity(long physicsPtr, RigidBody rigidBody); + public static native void setRigidBodyLinearVelocity(long physicsPtr, RigidBody rigidBody, Vector3d linearVelocity); + + public static native Vector3d getRigidBodyAngularVelocity(long physicsPtr, RigidBody rigidBody); + public static native void setRigidBodyAngularVelocity(long physicsPtr, RigidBody rigidBody, Vector3d angularVelocity); + + public static native AxisLock getRigidBodyLockTranslation(long physicsPtr, RigidBody rigidBody); + public static native void setRigidBodyLockTranslation(long physicsPtr, RigidBody rigidBody, AxisLock lockTranslation); + + public static native AxisLock getRigidBodyLockRotation(long physicsPtr, RigidBody rigidBody); + public static native void setRigidBodyLockRotation(long physicsPtr, RigidBody rigidBody, AxisLock lockRotation); + + public static native long[] getRigidBodyChildren(long physicsPtr, RigidBody rigidBody); + public static native void setRigidBodyChildren(long physicsPtr, RigidBody rigidBody, long[] children); + + public static native void applyImpulse(long physicsPtr, RigidBody rigidBody, double x, double y, double z); + public static native void applyTorqueImpulse(long physicsPtr, RigidBody rigidBody, double x, double y, double z); +} @@ -1,15 +1,21 @@ package com.dropbear.scene +import com.dropbear.DropbearEngine import com.dropbear.utils.Progress -actual fun SceneLoadHandle.switchToSceneAsync(): SceneLoadHandle { - TODO("Not yet implemented") +actual fun SceneLoadHandle.getSceneLoadHandleSceneName(id: Long): String { + return SceneLoadHandleNative.getSceneLoadHandleSceneName(DropbearEngine.native.sceneLoaderHandle, id) +} + +actual fun SceneLoadHandle.switchToSceneAsync() { + return SceneLoadHandleNative.switchToSceneAsync(DropbearEngine.native.commandBufferHandle, this.id) } actual fun SceneLoadHandle.getSceneLoadProgress(): Progress { - TODO("Not yet implemented") + return SceneLoadHandleNative.getSceneLoadProgress(DropbearEngine.native.sceneLoaderHandle, this.id) } actual fun SceneLoadHandle.getSceneLoadStatus(): SceneLoadStatus { - TODO("Not yet implemented") + val result = SceneLoadHandleNative.getSceneLoadStatus(DropbearEngine.native.sceneLoaderHandle, this.id) + return SceneLoadStatus.entries[result] } @@ -0,0 +1,15 @@ +package com.dropbear.scene; + +import com.dropbear.EucalyptusCoreLoader; +import com.dropbear.utils.Progress; + +public class SceneLoadHandleNative { + static { + new EucalyptusCoreLoader().ensureLoaded(); + } + + public static native String getSceneLoadHandleSceneName(long sceneLoaderHandle, long sceneId); + public static native void switchToSceneAsync(long commandBufferPtr, long sceneId); + public static native Progress getSceneLoadProgress(long sceneLoaderHandle, long sceneId); + public static native int getSceneLoadStatus(long sceneLoaderHandle, long sceneId); +} @@ -1,15 +1,32 @@ package com.dropbear.scene +import com.dropbear.DropbearEngine + actual fun SceneManager.loadSceneAsyncNative(sceneName: String): SceneLoadHandle? { - TODO("Not yet implemented") + val result = SceneManagerNative.loadSceneAsyncNative( + DropbearEngine.native.commandBufferHandle, + DropbearEngine.native.sceneLoaderHandle, + sceneName + ) + return if (result != null) SceneLoadHandle(result) else null } actual fun SceneManager.loadSceneAsyncNative( sceneName: String, - loading_scene: String + loadingScene: String ): SceneLoadHandle? { - TODO("Not yet implemented") + val result = SceneManagerNative.loadSceneAsyncNative( + DropbearEngine.native.commandBufferHandle, + DropbearEngine.native.sceneLoaderHandle, + sceneName, + loadingScene + ) + return if (result != null) SceneLoadHandle(result) else null } actual fun SceneManager.switchToSceneImmediateNative(sceneName: String) { + SceneManagerNative.switchToSceneImmediateNative( + DropbearEngine.native.commandBufferHandle, + sceneName + ) } @@ -0,0 +1,13 @@ +package com.dropbear.scene; + +import com.dropbear.EucalyptusCoreLoader; + +public class SceneManagerNative { + static { + new EucalyptusCoreLoader().ensureLoaded(); + } + + public static native Long loadSceneAsyncNative(long commandBufferPtr, long sceneManagerHandle, String sceneName); + public static native Long loadSceneAsyncNative(long commandBufferPtr, long sceneManagerHandle, String sceneName, String loadingScene); + public static native void switchToSceneImmediateNative(long commandBufferPtr, String sceneName); +} @@ -1,81 +0,0 @@ -package com.dropbear - -import com.dropbear.math.Vector3D - -actual fun Camera.getCameraEye(entity: EntityId): Vector3D { - TODO("Not yet implemented") -} - -actual fun Camera.setCameraEye(entity: EntityId, value: Vector3D) { -} - -actual fun Camera.getCameraTarget(entity: EntityId): Vector3D { - TODO("Not yet implemented") -} - -actual fun Camera.setCameraTarget(entity: EntityId, value: Vector3D) { -} - -actual fun Camera.getCameraUp(entity: EntityId): Vector3D { - TODO("Not yet implemented") -} - -actual fun Camera.setCameraUp(entity: EntityId, value: Vector3D) { -} - -actual fun Camera.getCameraAspect(entity: EntityId): Double { - TODO("Not yet implemented") -} - -actual fun Camera.getCameraFovY(entity: EntityId): Double { - TODO("Not yet implemented") -} - -actual fun Camera.setCameraFovY(entity: EntityId, value: Double) { -} - -actual fun Camera.getCameraZNear(entity: EntityId): Double { - TODO("Not yet implemented") -} - -actual fun Camera.setCameraZNear(entity: EntityId, value: Double) { -} - -actual fun Camera.getCameraZFar(entity: EntityId): Double { - TODO("Not yet implemented") -} - -actual fun Camera.setCameraZFar(entity: EntityId, value: Double) { -} - -actual fun Camera.getCameraYaw(entity: EntityId): Double { - TODO("Not yet implemented") -} - -actual fun Camera.getCameraPitch(entity: EntityId): Double { - TODO("Not yet implemented") -} - -actual fun Camera.setCameraYaw(entity: EntityId, value: Double) { -} - -actual fun Camera.setCameraPitch(entity: EntityId, value: Double) { -} - -actual fun Camera.getCameraSpeed(entity: EntityId): Double { - TODO("Not yet implemented") -} - -actual fun Camera.setCameraSpeed(entity: EntityId, value: Double) { -} - -actual fun Camera.getCameraSensitivity(entity: EntityId): Double { - TODO("Not yet implemented") -} - -actual fun Camera.setCameraSensitivity(entity: EntityId, value: Double) { -} - -actual fun cameraExistsForEntity(entity: EntityId): Boolean { - TODO("Not yet implemented") -} @@ -1,93 +0,0 @@ -package com.dropbear - -actual fun CustomProperties.getStringProperty( - entityHandle: Long, - label: String -): String? { - TODO("Not yet implemented") -} - -actual fun CustomProperties.getIntProperty(entityHandle: Long, label: String): Int? { - TODO("Not yet implemented") -} - -actual fun CustomProperties.getLongProperty( - entityHandle: Long, - label: String -): Long? { - TODO("Not yet implemented") -} - -actual fun CustomProperties.getDoubleProperty( - entityHandle: Long, - label: String -): Double? { - TODO("Not yet implemented") -} - -actual fun CustomProperties.getFloatProperty( - entityHandle: Long, - label: String -): Float? { - TODO("Not yet implemented") -} - -actual fun CustomProperties.getBoolProperty( - entityHandle: Long, - label: String -): Boolean? { - TODO("Not yet implemented") -} - -actual fun CustomProperties.getVec3Property( - entityHandle: Long, - label: String -): FloatArray? { - TODO("Not yet implemented") -} - -actual fun CustomProperties.setStringProperty( - entityHandle: Long, - label: String, - value: String -) { -} - -actual fun CustomProperties.setIntProperty( - entityHandle: Long, - label: String, - value: Int -) { -} - -actual fun CustomProperties.setLongProperty( - entityHandle: Long, - label: String, - value: Long -) { -} - -actual fun CustomProperties.setFloatProperty( - entityHandle: Long, - label: String, - value: Double -) { -} - -actual fun CustomProperties.setBoolProperty( - entityHandle: Long, - label: String, - value: Boolean -) { -} - -actual fun CustomProperties.setVec3Property( - entityHandle: Long, - label: String, - value: FloatArray -) { -} - -actual fun customPropertiesExistsForEntity(entityId: EntityId): Boolean { - TODO("Not yet implemented") -} @@ -1,10 +1,8 @@ package com.dropbear -actual fun getEntity(label: String): Long? { - TODO("Not yet implemented") -} +import com.dropbear.components.Camera -actual fun getCamera(label: String): Camera? { +actual fun getEntity(label: String): Long? { TODO("Not yet implemented") } @@ -1,31 +0,0 @@ -package com.dropbear - -import com.dropbear.math.Transform - -actual fun EntityTransform.getLocalTransform(entityId: EntityId): Transform { - TODO("Not yet implemented") -} - -actual fun EntityTransform.setLocalTransform( - entityId: EntityId, - transform: Transform -) { -} - -actual fun EntityTransform.getWorldTransform(entityId: EntityId): Transform { - TODO("Not yet implemented") -} - -actual fun EntityTransform.setWorldTransform( - entityId: EntityId, - transform: Transform -) { -} - -actual fun EntityTransform.propagateTransform(entityId: EntityId): Transform { - TODO("Not yet implemented") -} - -actual fun entityTransformExistsForEntity(entityId: EntityId): Boolean { - TODO("Not yet implemented") -} @@ -1,37 +0,0 @@ -package com.dropbear - -import com.dropbear.asset.ModelHandle -import com.dropbear.asset.TextureHandle - -actual fun MeshRenderer.getModel(id: EntityId): ModelHandle? { - TODO("Not yet implemented") -} - -actual fun MeshRenderer.setModel(id: EntityId, model: ModelHandle?) { -} - -actual fun MeshRenderer.getAllTextureIds(id: EntityId): List<TextureHandle>? { - TODO("Not yet implemented") -} - -actual fun MeshRenderer.getMaterialNames(id: EntityId): List<String> { - TODO("Not yet implemented") -} - -actual fun MeshRenderer.setMaterialNames(id: EntityId, names: Array<String>) { -} - -actual fun MeshRenderer.getTexture(id: EntityId, materialName: String): Long { - TODO("Not yet implemented") -} - -actual fun MeshRenderer.setTextureOverride( - id: EntityId, - materialName: String, - textureHandle: Long -) { -} - -actual fun meshRendererExistsForEntity(entityId: EntityId): Boolean { - TODO("Not yet implemented") -} @@ -1,9 +1,9 @@ package com.dropbear.asset -actual fun AssetHandle.asTextureHandle(): TextureHandle? { +actual fun isModelHandle(id: Long): Boolean { TODO("Not yet implemented") } -actual fun isModelHandle(id: Long): Boolean { +actual fun isTextureHandle(id: Long): Boolean { TODO("Not yet implemented") } @@ -0,0 +1,82 @@ +package com.dropbear.components + +import com.dropbear.EntityId +import com.dropbear.math.Vector3d + +actual fun Camera.getCameraEye(entity: EntityId): Vector3d { + TODO("Not yet implemented") +} + +actual fun Camera.setCameraEye(entity: EntityId, value: Vector3d) { +} + +actual fun Camera.getCameraTarget(entity: EntityId): Vector3d { + TODO("Not yet implemented") +} + +actual fun Camera.setCameraTarget(entity: EntityId, value: Vector3d) { +} + +actual fun Camera.getCameraUp(entity: EntityId): Vector3d { + TODO("Not yet implemented") +} + +actual fun Camera.setCameraUp(entity: EntityId, value: Vector3d) { +} + +actual fun Camera.getCameraAspect(entity: EntityId): Double { + TODO("Not yet implemented") +} + +actual fun Camera.getCameraFovY(entity: EntityId): Double { + TODO("Not yet implemented") +} + +actual fun Camera.setCameraFovY(entity: EntityId, value: Double) { +} + +actual fun Camera.getCameraZNear(entity: EntityId): Double { + TODO("Not yet implemented") +} + +actual fun Camera.setCameraZNear(entity: EntityId, value: Double) { +} + +actual fun Camera.getCameraZFar(entity: EntityId): Double { + TODO("Not yet implemented") +} + +actual fun Camera.setCameraZFar(entity: EntityId, value: Double) { +} + +actual fun Camera.getCameraYaw(entity: EntityId): Double { + TODO("Not yet implemented") +} + +actual fun Camera.getCameraPitch(entity: EntityId): Double { + TODO("Not yet implemented") +} + +actual fun Camera.setCameraYaw(entity: EntityId, value: Double) { +} + +actual fun Camera.setCameraPitch(entity: EntityId, value: Double) { +} + +actual fun Camera.getCameraSpeed(entity: EntityId): Double { + TODO("Not yet implemented") +} + +actual fun Camera.setCameraSpeed(entity: EntityId, value: Double) { +} + +actual fun Camera.getCameraSensitivity(entity: EntityId): Double { + TODO("Not yet implemented") +} + +actual fun Camera.setCameraSensitivity(entity: EntityId, value: Double) { +} + +actual fun cameraExistsForEntity(entity: EntityId): Boolean { + TODO("Not yet implemented") +} @@ -0,0 +1,96 @@ +package com.dropbear.components + +import com.dropbear.EntityId +import com.dropbear.math.Vector3d + +actual fun CustomProperties.getStringProperty( + entityHandle: Long, + label: String +): String? { + TODO("Not yet implemented") +} + +actual fun CustomProperties.getIntProperty(entityHandle: Long, label: String): Int? { + TODO("Not yet implemented") +} + +actual fun CustomProperties.getLongProperty( + entityHandle: Long, + label: String +): Long? { + TODO("Not yet implemented") +} + +actual fun CustomProperties.getDoubleProperty( + entityHandle: Long, + label: String +): Double? { + TODO("Not yet implemented") +} + +actual fun CustomProperties.getFloatProperty( + entityHandle: Long, + label: String +): Float? { + TODO("Not yet implemented") +} + +actual fun CustomProperties.getBoolProperty( + entityHandle: Long, + label: String +): Boolean? { + TODO("Not yet implemented") +} + +actual fun CustomProperties.getVec3Property( + entityHandle: Long, + label: String +): Vector3d? { + TODO("Not yet implemented") +} + +actual fun CustomProperties.setStringProperty( + entityHandle: Long, + label: String, + value: String +) { +} + +actual fun CustomProperties.setIntProperty( + entityHandle: Long, + label: String, + value: Int +) { +} + +actual fun CustomProperties.setLongProperty( + entityHandle: Long, + label: String, + value: Long +) { +} + +actual fun CustomProperties.setFloatProperty( + entityHandle: Long, + label: String, + value: Double +) { +} + +actual fun CustomProperties.setBoolProperty( + entityHandle: Long, + label: String, + value: Boolean +) { +} + +actual fun CustomProperties.setVec3Property( + entityHandle: Long, + label: String, + value: Vector3d +) { +} + +actual fun customPropertiesExistsForEntity(entityId: EntityId): Boolean { + TODO("Not yet implemented") +} @@ -0,0 +1,32 @@ +package com.dropbear.components + +import com.dropbear.EntityId +import com.dropbear.math.Transform + +actual fun EntityTransform.getLocalTransform(entityId: EntityId): Transform { + TODO("Not yet implemented") +} + +actual fun EntityTransform.setLocalTransform( + entityId: EntityId, + transform: Transform +) { +} + +actual fun EntityTransform.getWorldTransform(entityId: EntityId): Transform { + TODO("Not yet implemented") +} + +actual fun EntityTransform.setWorldTransform( + entityId: EntityId, + transform: Transform +) { +} + +actual fun EntityTransform.propagateTransform(entityId: EntityId): Transform { + TODO("Not yet implemented") +} + +actual fun entityTransformExistsForEntity(entityId: EntityId): Boolean { + TODO("Not yet implemented") +} @@ -0,0 +1,31 @@ +package com.dropbear.components + +import com.dropbear.EntityId +import com.dropbear.asset.ModelHandle +import com.dropbear.asset.TextureHandle + +actual fun MeshRenderer.getModel(id: EntityId): ModelHandle? { + TODO("Not yet implemented") +} + +actual fun MeshRenderer.setModel(id: EntityId, model: ModelHandle?) { +} + +actual fun MeshRenderer.getAllTextureIds(id: EntityId): List<TextureHandle>? { + TODO("Not yet implemented") +} + +actual fun MeshRenderer.getTexture(id: EntityId, materialName: String): Long { + TODO("Not yet implemented") +} + +actual fun MeshRenderer.setTextureOverride( + id: EntityId, + materialName: String, + textureHandle: Long +) { +} + +actual fun meshRendererExistsForEntity(entityId: EntityId): Boolean { + TODO("Not yet implemented") +} @@ -1,8 +1,19 @@ package com.dropbear.input +import com.dropbear.math.Vector2d + actual fun Gamepad.isGamepadButtonPressed( id: Long, button: GamepadButton ): Boolean { TODO("Not yet implemented") -} +} + +actual fun Gamepad.getLeftStickPosition(id: Long): Vector2d { + TODO("Not yet implemented") +} + +actual fun Gamepad.getRightStickPosition(id: Long): Vector2d { + TODO("Not yet implemented") +} + @@ -1,6 +1,6 @@ package com.dropbear.input -import com.dropbear.math.Vector2D +import com.dropbear.math.Vector2d actual class InputState actual constructor() { actual fun printInputState() { @@ -10,7 +10,7 @@ actual class InputState actual constructor() { TODO("Not yet implemented") } - actual fun getMousePosition(): Vector2D { + actual fun getMousePosition(): Vector2d { TODO("Not yet implemented") } @@ -18,7 +18,7 @@ actual class InputState actual constructor() { TODO("Not yet implemented") } - actual fun getMouseDelta(): Vector2D { + actual fun getMouseDelta(): Vector2d { TODO("Not yet implemented") } @@ -29,7 +29,7 @@ actual class InputState actual constructor() { actual fun setCursorLocked(locked: Boolean) { } - actual fun getLastMousePos(): Vector2D { + actual fun getLastMousePos(): Vector2d { TODO("Not yet implemented") } @@ -1,6 +1,6 @@ package com.dropbear.physics -import com.dropbear.math.Vector3D +import com.dropbear.math.Vector3d actual fun Collider.getColliderShape(collider: Collider): ColliderShape { TODO("Not yet implemented") @@ -48,23 +48,23 @@ actual fun Collider.setColliderIsSensor( ) { } -actual fun Collider.getColliderTranslation(collider: Collider): Vector3D { +actual fun Collider.getColliderTranslation(collider: Collider): Vector3d { TODO("Not yet implemented") } actual fun Collider.setColliderTranslation( collider: Collider, - translation: Vector3D + translation: Vector3d ) { } -actual fun Collider.getColliderRotation(collider: Collider): Vector3D { +actual fun Collider.getColliderRotation(collider: Collider): Vector3d { TODO("Not yet implemented") } actual fun Collider.setColliderRotation( collider: Collider, - rotation: Vector3D + rotation: Vector3d ) { } @@ -77,4 +77,5 @@ actual fun Collider.setColliderMass(collider: Collider, mass: Double) { actual fun Collider.getColliderDensity(collider: Collider): Double { TODO("Not yet implemented") -} +} + @@ -1,7 +1,7 @@ package com.dropbear.physics import com.dropbear.EntityId -import com.dropbear.math.Vector3D +import com.dropbear.math.Vector3d actual fun RigidBody.setRigidbodyMode( rigidBody: RigidBody, @@ -43,7 +43,7 @@ actual fun RigidBody.setRigidbodyCcdEnabled( ) { } -actual fun RigidBody.getRigidbodyLinearVelocity(rigidBody: RigidBody): Vector3D { +actual fun RigidBody.getRigidbodyLinearVelocity(rigidBody: RigidBody): Vector3d { TODO("Not yet implemented") } @@ -55,17 +55,17 @@ actual fun RigidBody.setRigidbodyLinearDamping( actual fun RigidBody.setRigidbodyLinearVelocity( rigidBody: RigidBody, - linearVelocity: Vector3D + linearVelocity: Vector3d ) { } -actual fun RigidBody.getRigidbodyAngularVelocity(rigidBody: RigidBody): Vector3D { +actual fun RigidBody.getRigidbodyAngularVelocity(rigidBody: RigidBody): Vector3d { TODO("Not yet implemented") } actual fun RigidBody.setRigidbodyAngularVelocity( rigidBody: RigidBody, - angularVelocity: Vector3D + angularVelocity: Vector3d ) { } @@ -2,7 +2,7 @@ package com.dropbear.scene import com.dropbear.utils.Progress -actual fun SceneLoadHandle.switchToSceneAsync(): SceneLoadHandle { +actual fun SceneLoadHandle.switchToSceneAsync() { TODO("Not yet implemented") } @@ -12,4 +12,8 @@ actual fun SceneLoadHandle.getSceneLoadProgress(): Progress { actual fun SceneLoadHandle.getSceneLoadStatus(): SceneLoadStatus { TODO("Not yet implemented") +} + +actual fun SceneLoadHandle.getSceneLoadHandleSceneName(id: Long): String { + TODO("Not yet implemented") } @@ -6,7 +6,7 @@ actual fun SceneManager.loadSceneAsyncNative(sceneName: String): SceneLoadHandle actual fun SceneManager.loadSceneAsyncNative( sceneName: String, - loading_scene: String + loadingScene: String ): SceneLoadHandle? { TODO("Not yet implemented") }