diff --git a/INSTALL.md b/INSTALL.md index 1f06b02..34e7c4e 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -16,6 +16,7 @@ - [Dependencies](#dependencies) - [Pre-compiled klibs](#pre-compiled-klibs) - [Build It Yourself](#build-it-yourself) + - [What is resourcePath?](#what-is-resourcePath?) ## Compatibility @@ -56,4 +57,17 @@ implementation("com.prism-architect:KaylibKit-macosx64:1.0.4") implementation("com.prism-architect:KaylibKit-macosarm64:1.0.4") ``` -You're now done and ready to play with KaylibKit! \ No newline at end of file +You're now done and ready to play with KaylibKit! + +## What is resourcePath? +`resourcePath` was added because, well, Kotlin/Native doesn't play as nice as Java when it comes to handling resources in your Raylib application/game. So, what's the deal? It's a necessary feature that simply hands you the path to a folder called 'resources' that hangs out in the same spot as your app's executable. + +Let's say you're loading a texture; all you have to do is ensure that a folder named resources is in the same folder as your executable, alongside your asset added to the said folder 'resources'. + +Now simply call +```kotlin +loadTexture($resourcePath/myTexture.png) +``` +That is all. `resourcePath` simplifies it all for you. + +In the future we will plan to add ability to change the folder name as currently it's hardcoded to be named 'resources' \ No newline at end of file diff --git a/examples/core/core_3d_picking.kt b/examples/core/core_3d_picking.kt index c1e3adb..e988c0a 100644 --- a/examples/core/core_3d_picking.kt +++ b/examples/core/core_3d_picking.kt @@ -1,21 +1,20 @@ -import kaylib.kCamera.setCameraMode -import kaylib.kCamera.updateCamera -import kaylib.kCore.* -import kaylib.kCore.endDrawing -import kaylib.kEnums.CameraMode -import kaylib.kEnums.CameraProjection -import kaylib.kEnums.ConfigFlag -import kaylib.kEnums.MouseButton -import kaylib.kMath.kVector3 -import kaylib.kModels.* -import kaylib.kText.drawFPS -import kaylib.kText.drawText -import kaylib.kText.measureText -import kaylib.kTypes.kBoundingBox -import kaylib.kTypes.kCamera3D -import kaylib.kTypes.kRay -import kaylib.kTypes.kRayCollision +import kaylibkit.kCamera.updateCamera +import kaylibkit.kCore.* +import kaylibkit.kEnums.CameraMode +import kaylibkit.kEnums.CameraProjection +import kaylibkit.kEnums.ConfigFlag +import kaylibkit.kEnums.MouseButton +import kaylibkit.kMath.kVector3 +import kaylibkit.kModels.* +import kaylibkit.kText.drawFPS +import kaylibkit.kText.drawText +import kaylibkit.kText.measureText +import kaylibkit.kTypes.kBoundingBox +import kaylibkit.kTypes.kCamera3D +import kaylibkit.kTypes.kRay +import kaylibkit.kTypes.kRayCollision import kaylibc.* +import kotlinx.cinterop.memScoped const val SCREEN_WIDTH = 800 const val SCREEN_HEIGHT = 450 @@ -24,73 +23,94 @@ const val SCREEN_HEIGHT = 450 // Program main entry point //------------------------------------------------------------------------------------ fun main() { - setConfigFlags(ConfigFlag.VSYNC_HINT) // Turn VSYNC On - initWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "raylib [core] example - 3d picking") + memScoped { + setConfigFlags(ConfigFlag.VSYNC_HINT) // Turn VSYNC On + initWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "raylib [core] example - 3d picking") - val camera = kCamera3D(kVector3(10F, 10F, 10F), kVector3(), kVector3(0F, 1F, 0F), 45F, CameraProjection.PERSPECTIVE) + val camera = kCamera3D(position = kVector3(10F, 10F, 10F, allocator = this), target = kVector3(0F, 0F, 0F, allocator = this), up = kVector3(0F, 1F, 0F, allocator = this), fovy = 45F, projection = CameraProjection.PERSPECTIVE, allocator = this) - val cubePosition = kVector3(0F, 1F, 0F) - val cubeSize = kVector3(2F, 2F, 2F) + val cubePosition = kVector3(0F, 1F, 0F, allocator = this) + val cubeSize = kVector3(2F, 2F, 2F, allocator = this) - var ray = kRay() // Picking line ray - var collision = kRayCollision() + var ray = kRay(allocator = this, position = kVector3(allocator = this), direction = kVector3(allocator = this)) // Picking line ray + var collision = kRayCollision(allocator = this, point = kVector3(allocator = this), normal = kVector3(allocator = this)) - setCameraMode(camera, CameraMode.FREE) // Set a free camera mode - //-------------------------------------------------------------------------------------- + //-------------------------------------------------------------------------------------- - // Main game loop - while (!windowShouldClose) { // Detect window close button or ESC key - // Update - //---------------------------------------------------------------------------------- - updateCamera(camera) - - if (isMouseButtonPressed(MouseButton.LEFT)) { - if (!collision.hit) { - ray = getMouseRay(getMousePosition(), camera) - - // Check collision between ray and box - collision = getRayCollisionBox(ray, - kBoundingBox( - kVector3(cubePosition.x - cubeSize.x/2, cubePosition.y - cubeSize.y/2, cubePosition.z - cubeSize.z/2), - kVector3(cubePosition.x + cubeSize.x/2, cubePosition.y + cubeSize.y/2, cubePosition.z + cubeSize.z/2))) - } else { - collision.hit = false - } - } - //---------------------------------------------------------------------------------- - - drawing { - // Draw + // Main game loop + while (!windowShouldClose) { // Detect window close button or ESC key + // Update //---------------------------------------------------------------------------------- - clearBackground(rayWhite) + if (isCursorHidden()) { + updateCamera(camera, CameraMode.FIRST_PERSON) + } - mode3D(camera) { - if (collision.hit) { - drawCube(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, red) - drawCubeWires(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, maroon) + if (isMouseButtonPressed(MouseButton.LEFT)) { + if (!collision.hit) { + ray = getMouseRay(getMousePosition(allocator = this), camera = camera, allocator = this) - drawCubeWires(cubePosition, cubeSize.x + 0.2f, cubeSize.y + 0.2f, cubeSize.z + 0.2f, green) + // Check collision between ray and box + collision = getRayCollisionBox( + ray, + kBoundingBox( + kVector3( + cubePosition.x - cubeSize.x / 2, + cubePosition.y - cubeSize.y / 2, + cubePosition.z - cubeSize.z / 2, + allocator = this + ), + kVector3( + cubePosition.x + cubeSize.x / 2, + cubePosition.y + cubeSize.y / 2, + cubePosition.z + cubeSize.z / 2, + allocator = this + ), + allocator = this + ), allocator = this + ) } else { - drawCube(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, gray) - drawCubeWires(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, darkGray) + collision.hit = false + } + } + //---------------------------------------------------------------------------------- + + drawing { + // Draw + //---------------------------------------------------------------------------------- + clearBackground(rayWhite) + + mode3D(camera) { + if (collision.hit) { + drawCube(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, red) + drawCubeWires(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, maroon) + + drawCubeWires(cubePosition, cubeSize.x + 0.2f, cubeSize.y + 0.2f, cubeSize.z + 0.2f, green) + } else { + drawCube(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, gray) + drawCubeWires(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, darkGray) + } + + drawRay(ray, maroon) + drawGrid(10, 1F) } - drawRay(ray, maroon) - drawGrid(10, 1F) + drawText("Try selecting the box with mouse!", 240, 10, 20, darkGray) + + if (collision.hit) drawText( + "BOX SELECTED", + (SCREEN_WIDTH - measureText("BOX SELECTED", 30)) / 2, + (SCREEN_HEIGHT * .1F).toInt(), + 30, + green + ) + + drawFPS(10, 10) + //---------------------------------------------------------------------------------- } - - drawText("Try selecting the box with mouse!", 240, 10, 20, darkGray); - - if (collision.hit) drawText("BOX SELECTED", (SCREEN_WIDTH - measureText("BOX SELECTED", 30)) / 2, (SCREEN_HEIGHT * .1F).toInt(), 30, green) - - drawFPS(10, 10); - //---------------------------------------------------------------------------------- } + // De-Initialization + //-------------------------------------------------------------------------------------- + closeWindow() // Close window and OpenGL context + //-------------------------------------------------------------------------------------- } - // De-Initialization - //-------------------------------------------------------------------------------------- - closeWindow() // Close window and OpenGL context - //-------------------------------------------------------------------------------------- -} - - +} \ No newline at end of file diff --git a/examples/core/core_input_keys.kt b/examples/core/core_input_keys.kt index 8d79ea6..9eb64c0 100644 --- a/examples/core/core_input_keys.kt +++ b/examples/core/core_input_keys.kt @@ -5,6 +5,7 @@ import kaylibkit.kMath.kVector2 import kaylibkit.kShapes.drawCircle import kaylibkit.kText.drawText import kaylibc.* +import kotlinx.cinterop.memScoped const val SCREEN_WIDTH = 800 const val SCREEN_HEIGHT = 450 @@ -13,37 +14,48 @@ const val SCREEN_HEIGHT = 450 // Program main entry point //------------------------------------------------------------------------------------ fun main() { - setConfigFlags(ConfigFlag.VSYNC_HINT) // Turn VSYNC On - initWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "raylib [core] example - keyboard input") + memScoped { + setConfigFlags(ConfigFlag.VSYNC_HINT) // Turn VSYNC On + initWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "raylib [core] example - keyboard input") - val ballPosition = kVector2(SCREEN_WIDTH/2F, SCREEN_HEIGHT/2F) - //-------------------------------------------------------------------------------------- + val ballPosition = kVector2(SCREEN_WIDTH / 2F, SCREEN_HEIGHT / 2F, allocator = this) + //-------------------------------------------------------------------------------------- - // Main game loop - while (!windowShouldClose) { // Detect window close button or ESC key - // Update - //---------------------------------------------------------------------------------- - if (isKeyDown(KeyboardKey.RIGHT)) { ballPosition.x += 2 } - if (isKeyDown(KeyboardKey.LEFT)) { ballPosition.x -= 2 } - if (isKeyDown(KeyboardKey.UP)) { ballPosition.y -= 2 } - if (isKeyDown(KeyboardKey.DOWN)) { ballPosition.y += 2 } - //---------------------------------------------------------------------------------- - - drawing { - // Draw + // Main game loop + while (!windowShouldClose) { // Detect window close button or ESC key + // Update //---------------------------------------------------------------------------------- - clearBackground(rayWhite) - - drawText("move the ball with arrow keys", 10, 10, 20, darkGray) - - drawCircle(ballPosition, 50F, maroon) + if (isKeyDown(KeyboardKey.RIGHT)) { + ballPosition.x += 2 + } + if (isKeyDown(KeyboardKey.LEFT)) { + ballPosition.x -= 2 + } + if (isKeyDown(KeyboardKey.UP)) { + ballPosition.y -= 2 + } + if (isKeyDown(KeyboardKey.DOWN)) { + ballPosition.y += 2 + } //---------------------------------------------------------------------------------- + + drawing { + // Draw + //---------------------------------------------------------------------------------- + clearBackground(rayWhite) + + drawText("move the ball with arrow keys", 10, 10, 20, darkGray) + + drawCircle(ballPosition, 50F, maroon) + //---------------------------------------------------------------------------------- + } + } - + // De-Initialization + //-------------------------------------------------------------------------------------- + closeWindow() // Close window and OpenGL context + //-------------------------------------------------------------------------------------- } - // De-Initialization - //-------------------------------------------------------------------------------------- - closeWindow() // Close window and OpenGL context - //-------------------------------------------------------------------------------------- + } diff --git a/examples/core/core_input_mouse.kt b/examples/core/core_input_mouse.kt index 428d594..ed32e68 100644 --- a/examples/core/core_input_mouse.kt +++ b/examples/core/core_input_mouse.kt @@ -4,6 +4,7 @@ import kaylibkit.kEnums.MouseButton import kaylibkit.kShapes.drawCircle import kaylibkit.kText.drawText import kaylibc.* +import kotlinx.cinterop.memScoped const val SCREEN_WIDTH = 800 const val SCREEN_HEIGHT = 450 @@ -12,42 +13,44 @@ const val SCREEN_HEIGHT = 450 // Program main entry point //------------------------------------------------------------------------------------ fun main() { - setConfigFlags(ConfigFlag.VSYNC_HINT) // Turn VSYNC On - initWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "raylib [core] example - mouse input") + memScoped { + setConfigFlags(ConfigFlag.VSYNC_HINT) // Turn VSYNC On + initWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "raylib [core] example - mouse input") - var ballPosition: Vector2 - var ballColor = darkBlue - //-------------------------------------------------------------------------------------- + var ballPosition: Vector2 + var ballColor = darkBlue + //-------------------------------------------------------------------------------------- - // Main game loop - while (!windowShouldClose) { // Detect window close button or ESC key - // Update - //---------------------------------------------------------------------------------- - ballPosition = getMousePosition() - - if (isMouseButtonPressed(MouseButton.LEFT)) ballColor = maroon; - else if (isMouseButtonPressed(MouseButton.MIDDLE)) ballColor = lime; - else if (isMouseButtonPressed(MouseButton.RIGHT)) ballColor = darkBlue; - else if (isMouseButtonPressed(MouseButton.SIDE)) ballColor = purple; - else if (isMouseButtonPressed(MouseButton.EXTRA)) ballColor = yellow; - else if (isMouseButtonPressed(MouseButton.FORWARD)) ballColor = orange; - else if (isMouseButtonPressed(MouseButton.BACK)) ballColor = beige; - //---------------------------------------------------------------------------------- - - drawing { - // Draw + // Main game loop + while (!windowShouldClose) { // Detect window close button or ESC key + // Update //---------------------------------------------------------------------------------- - clearBackground(rayWhite) + ballPosition = getMousePosition(allocator = this) - drawText("move ball with mouse and click mouse button to change color", 10, 10, 20, darkGray) - - drawCircle(ballPosition, 50F, ballColor) + if (isMouseButtonPressed(MouseButton.LEFT)) ballColor = maroon + else if (isMouseButtonPressed(MouseButton.MIDDLE)) ballColor = lime + else if (isMouseButtonPressed(MouseButton.RIGHT)) ballColor = darkBlue + else if (isMouseButtonPressed(MouseButton.SIDE)) ballColor = purple + else if (isMouseButtonPressed(MouseButton.EXTRA)) ballColor = yellow + else if (isMouseButtonPressed(MouseButton.FORWARD)) ballColor = orange + else if (isMouseButtonPressed(MouseButton.BACK)) ballColor = beige //---------------------------------------------------------------------------------- + + drawing { + // Draw + //---------------------------------------------------------------------------------- + clearBackground(rayWhite) + + drawText("move ball with mouse and click mouse button to change color", 10, 10, 20, darkGray) + + drawCircle(ballPosition, 50F, ballColor) + //---------------------------------------------------------------------------------- + } } + // De-Initialization + //-------------------------------------------------------------------------------------- + closeWindow() // Close window and OpenGL context + //-------------------------------------------------------------------------------------- } } - // De-Initialization - //-------------------------------------------------------------------------------------- - closeWindow() // Close window and OpenGL context - //-------------------------------------------------------------------------------------- } diff --git a/examples/models/models_heightmap.kt b/examples/models/models_heightmap.kt index 0688ff6..03e9984 100644 --- a/examples/models/models_heightmap.kt +++ b/examples/models/models_heightmap.kt @@ -1,4 +1,3 @@ -import kaylibkit.kCamera.setCameraMode import kaylibkit.kCamera.updateCamera import kaylibkit.kCore.* import kaylibkit.kCore.closeWindow @@ -15,6 +14,7 @@ import kaylibkit.kTextures.* import kaylibkit.kTypes.kCamera3D import kaylibc.* import kotlinx.cinterop.get +import kotlinx.cinterop.memScoped const val SCREEN_WIDTH = 800 const val SCREEN_HEIGHT = 450 @@ -23,56 +23,64 @@ const val SCREEN_HEIGHT = 450 // Program main entry point //------------------------------------------------------------------------------------ fun main() { - setConfigFlags(ConfigFlag.VSYNC_HINT) // Turn VSYNC On - initWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "raylib [models] example - heightmap loading and drawing") - //-------------------------------------------------------------------------------------- + memScoped { + setConfigFlags(ConfigFlag.VSYNC_HINT) // Turn VSYNC On + initWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "raylib [models] example - heightmap loading and drawing") + //-------------------------------------------------------------------------------------- - val camera = kCamera3D(kVector3(18F, 18F, 18F), kVector3(0F, 0F, 0F), kVector3(0F, 1F, 0F), 45F, CameraProjection.PERSPECTIVE) + val camera = kCamera3D( + kVector3(18F, 18F, 18F, allocator = this), + kVector3(0F, 0F, 0F, allocator = this), + kVector3(0F, 1F, 0F, allocator = this), + 45F, + CameraProjection.PERSPECTIVE, + allocator = this + ) - val image = loadImage("resources/heightmap.png") // Load heightmap image (RAM) - val texture = loadTextureFromImage(image) // Convert image to texture (VRAM) + val image = loadImage("$resourcePath/heightmap.png", allocator = this) // Load heightmap image (RAM) + val texture = loadTextureFromImage(image, allocator = this) // Convert image to texture (VRAM) - val mesh = genMeshHeightmap(image, kVector3(16F, 8F, 16F)) // Generate heightmap mesh (RAM and VRAM) - val model = loadModelFromMesh(mesh) // Load model from generated mesh + val mesh = genMeshHeightmap(image, kVector3(16F, 8F, 16F, allocator = this), allocator = this) // Generate heightmap mesh (RAM and VRAM) + val model = loadModelFromMesh(mesh, allocator = this) // Load model from generated mesh - // Set map diffuse texture. NOTE that we have to use .get and check for nullability as its possible materials is null - model.materials?.get(0)?.maps?.get(MATERIAL_MAP_DIFFUSE)?.texture?.set(texture) // Also note that we have to use K/N function of .get to retrieve the data from the material - val mapPosition = kVector3(-8F, 0F, -8F) // Define model position + // Set map diffuse texture. NOTE that we have to use .get and check for nullability as its possible materials is null + model.materials?.get(0)?.maps?.get(MATERIAL_MAP_DIFFUSE)?.texture?.set(texture) // Also note that we have to use K/N function of .get to retrieve the data from the material + val mapPosition = kVector3(-8F, 0F, -8F, allocator = this) // Define model position - unloadImage(image) // Unload heightmap image from RAM, already uploaded to VRAM + unloadImage(image) // Unload heightmap image from RAM, already uploaded to VRAM - setCameraMode(camera, CameraMode.ORBITAL) // Set an orbital camera mode - - // Main game loop - while (!windowShouldClose) { // Detect window close button or ESC key - // Update - //---------------------------------------------------------------------------------- - updateCamera(camera) - //---------------------------------------------------------------------------------- - - drawing { - // Draw + // Main game loop + while (!windowShouldClose) { // Detect window close button or ESC key + // Update + //---------------------------------------------------------------------------------- + updateCamera(camera, CameraMode.ORBITAL) //---------------------------------------------------------------------------------- - clearBackground(rayWhite) - mode3D(camera) { - drawModel(model, mapPosition, 1F, red) - drawGrid(20, 1F) + drawing { + // Draw + //---------------------------------------------------------------------------------- + clearBackground(rayWhite) + + mode3D(camera) { + drawModel(model, mapPosition, 1F, red) + drawGrid(20, 1F) + } + + drawTexture(texture, SCREEN_WIDTH - texture.width - 20, 20, white) + drawRectangleLines(SCREEN_WIDTH - texture.width - 20, 20, texture.width, texture.height, green) + + drawFPS(10, 10) + //---------------------------------------------------------------------------------- } - - drawTexture(texture, SCREEN_WIDTH - texture.width - 20, 20, white) - drawRectangleLines(SCREEN_WIDTH - texture.width - 20, 20, texture.width, texture.height, green) - - drawFPS(10, 10) - //---------------------------------------------------------------------------------- } - } - // De-Initialization - //-------------------------------------------------------------------------------------- - unloadTexture(texture) // Texture unloading - unloadModel(model) // Unload model + // De-Initialization + //-------------------------------------------------------------------------------------- + unloadTexture(texture) // Texture unloading + unloadModel(model) // Unload model - closeWindow() // Close window and OpenGL context - //-------------------------------------------------------------------------------------- + closeWindow() // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + } } + diff --git a/examples/shapes/shapes_easings_box_anim.kt b/examples/shapes/shapes_easings_box_anim.kt index 721e80a..35e4e87 100644 --- a/examples/shapes/shapes_easings_box_anim.kt +++ b/examples/shapes/shapes_easings_box_anim.kt @@ -8,6 +8,7 @@ import kaylibkit.kShapes.kRectangle import kaylibkit.kText.drawText import kaylibkit.kUtils.fade import kaylibc.* +import kotlinx.cinterop.memScoped const val SCREEN_WIDTH = 800 const val SCREEN_HEIGHT = 450 @@ -16,97 +17,99 @@ const val SCREEN_HEIGHT = 450 // Program main entry point //------------------------------------------------------------------------------------ fun main() { - setConfigFlags(ConfigFlag.VSYNC_HINT) // Turn VSYNC On - initWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "raylib [shapes] example - easings box anim") + memScoped { + setConfigFlags(ConfigFlag.VSYNC_HINT) // Turn VSYNC On + initWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "raylib [shapes] example - easings box anim") - var rec: Rectangle = kRectangle(kVector2(getScreenWidth()/2F, -100F), 100F, 100F) - var rotation: Float = .0F - var alpha: Float = 1.0F + var rec: Rectangle = kRectangle(allocator = this, kVector2(getScreenWidth() / 2F, -100F, allocator = this), 100F, 100F) + var rotation: Float = .0F + var alpha: Float = 1.0F - var state: Int = 0 - var framesCounter: Int = 0 - //-------------------------------------------------------------------------------------- - // Main game loop - while (!windowShouldClose) { // Detect window close button or ESC key + var state: Int = 0 + var framesCounter: Int = 0 + //-------------------------------------------------------------------------------------- + // Main game loop + while (!windowShouldClose) { // Detect window close button or ESC key - // Update - //---------------------------------------------------------------------------------- - when (state) { - 0 -> { - framesCounter++ - - // NOTE: Remember that 3rd parameter of easing function refers to - // desired value variation, do not confuse it with expected final value! - rec.y = elasticOut(framesCounter.toFloat(), -100F, getScreenHeight() / 2.0F + 100, 120F) - if (framesCounter >= 120) { - framesCounter = 0 - state = 1 - } - } - - 1 -> { - framesCounter++ - rec.height = bounceOut(framesCounter.toFloat(), 100F, -90F, 120F) - rec.width = bounceOut(framesCounter.toFloat(), 100F, getScreenWidth().toFloat(), 120F) - if (framesCounter >= 120) { - framesCounter = 0 - state = 2 - } - } - - 2 -> { - framesCounter++ - rotation = quadOut(framesCounter.toFloat(), .0F, 270.0F, 240F) - if (framesCounter >= 240) { - framesCounter = 0 - state = 3 - } - } - - 3 -> { - framesCounter++ - rec.height = circOut(framesCounter.toFloat(), 10F, GetScreenWidth().toFloat(), 120F) - if (framesCounter >= 120) { - framesCounter = 0 - state = 4 - } - } - - 4 -> { - framesCounter++ - alpha = sineOut(framesCounter.toFloat(), 1.0F, -1.0F, 160F) - if (framesCounter >= 160) { - framesCounter = 0 - state = 5 - } - } - - else -> {} - } - - if (isKeyPressed(KeyboardKey.SPACE)) { - rec = kRectangle(kVector2(getScreenWidth()/2F, -100F), 100F, 100F) - rotation = .0F - alpha = 1.0F - state = 0 - framesCounter = 0 - } - //---------------------------------------------------------------------------------- - - drawing { - // Draw + // Update //---------------------------------------------------------------------------------- - clearBackground(rayWhite) + when (state) { + 0 -> { + framesCounter++ - drawRectangle(rec, kVector2(rec.width/2, rec.height/2), rotation, fade(black, alpha)) + // NOTE: Remember that 3rd parameter of easing function refers to + // desired value variation, do not confuse it with expected final value! + rec.y = elasticOut(framesCounter.toFloat(), -100F, getScreenHeight() / 2.0F + 100, 120F) + if (framesCounter >= 120) { + framesCounter = 0 + state = 1 + } + } - drawText("PRESS [SPACE] TO RESET BOX ANIMATION!", 10, getScreenHeight() - 25, 20, lightGray) + 1 -> { + framesCounter++ + rec.height = bounceOut(framesCounter.toFloat(), 100F, -90F, 120F) + rec.width = bounceOut(framesCounter.toFloat(), 100F, getScreenWidth().toFloat(), 120F) + if (framesCounter >= 120) { + framesCounter = 0 + state = 2 + } + } + + 2 -> { + framesCounter++ + rotation = quadOut(framesCounter.toFloat(), .0F, 270.0F, 240F) + if (framesCounter >= 240) { + framesCounter = 0 + state = 3 + } + } + + 3 -> { + framesCounter++ + rec.height = circOut(framesCounter.toFloat(), 10F, GetScreenWidth().toFloat(), 120F) + if (framesCounter >= 120) { + framesCounter = 0 + state = 4 + } + } + + 4 -> { + framesCounter++ + alpha = sineOut(framesCounter.toFloat(), 1.0F, -1.0F, 160F) + if (framesCounter >= 160) { + framesCounter = 0 + state = 5 + } + } + + else -> {} + } + + if (isKeyPressed(KeyboardKey.SPACE)) { + rec = kRectangle(allocator = this, kVector2(getScreenWidth() / 2F, -100F, allocator = this), 100F, 100F) + rotation = .0F + alpha = 1.0F + state = 0 + framesCounter = 0 + } //---------------------------------------------------------------------------------- + + drawing { + // Draw + //---------------------------------------------------------------------------------- + clearBackground(rayWhite) + + drawRectangle(rec, kVector2(rec.width / 2, rec.height / 2, allocator = this), rotation, fade(black, alpha, allocator = this)) + + drawText("PRESS [SPACE] TO RESET BOX ANIMATION!", 10, getScreenHeight() - 25, 20, lightGray) + //---------------------------------------------------------------------------------- + } } + // De-Initialization + //-------------------------------------------------------------------------------------- + + closeWindow() // Close window and OpenGL context + //-------------------------------------------------------------------------------------- } - // De-Initialization - //-------------------------------------------------------------------------------------- - - closeWindow() // Close window and OpenGL context - //-------------------------------------------------------------------------------------- -} \ No newline at end of file +} diff --git a/examples/textures/textures_bunnymark.kt b/examples/textures/textures_bunnymark.kt index a911c4a..15ce945 100644 --- a/examples/textures/textures_bunnymark.kt +++ b/examples/textures/textures_bunnymark.kt @@ -9,6 +9,7 @@ import kaylibkit.kTextures.loadTexture import kaylibkit.kTextures.unloadTexture import kaylibkit.kTypes.kColor import kaylibc.* +import kotlinx.cinterop.memScoped import kotlin.random.Random const val SCREEN_WIDTH: Int = 800 @@ -20,85 +21,86 @@ var MAX_BUNNIES = 500000 var MAX_BATCH_ELEMENTS = 8192 fun main() { - // Initialization - //-------------------------------------------------------------------------------------- - initWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "raylib [textures] example - bunnymark") - setTargetFPS(60) + memScoped { // Initialization + //-------------------------------------------------------------------------------------- + initWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "raylib [textures] example - bunnymark") + setTargetFPS(60) - // Load bunny texture - val texBunny = loadTexture("resources/wabbit_alpha.png") - val bunnies = Array(MAX_BUNNIES) { Bunny(kVector2(), kVector2(), kColor()) } - var bunniesCount = 0 // Bunnies counter - //-------------------------------------------------------------------------------------- + // Load bunny texture + val texBunny = loadTexture("$resourcePath/wabbit_alpha.png", allocator = this) + val bunnies = Array(MAX_BUNNIES) { Bunny(kVector2(allocator = this), kVector2(allocator = this), kColor(allocator = this)) } + var bunniesCount = 0 // Bunnies counter + //-------------------------------------------------------------------------------------- - // Main game loop - while (!windowShouldClose) { // Detect window close button or ESC key - // Update - //---------------------------------------------------------------------------------- - if (isMouseButtonDown(MouseButton.LEFT)) { - // Create more bunnies - repeat(100) { - if (bunniesCount < MAX_BUNNIES) { - bunnies[bunniesCount].position = getMousePosition() - bunnies[bunniesCount].speed.x = (Random.nextInt(-250, 250) / 60.0f) - bunnies[bunniesCount].speed.y = (Random.nextInt(-250, 250) / 60.0f) - bunnies[bunniesCount].color.apply { - this.r = getRandomValue(50, 240).toUByte() - this.g = getRandomValue(80, 240).toUByte() - this.b = getRandomValue(100, 200).toUByte() - this.a = 255U + // Main game loop + while (!windowShouldClose) { // Detect window close button or ESC key + // Update + //---------------------------------------------------------------------------------- + if (isMouseButtonDown(MouseButton.LEFT)) { + // Create more bunnies + repeat(100) { + if (bunniesCount < MAX_BUNNIES) { + bunnies[bunniesCount].position = getMousePosition(allocator = this) + bunnies[bunniesCount].speed.x = (Random.nextInt(-250, 250) / 60.0f) + bunnies[bunniesCount].speed.y = (Random.nextInt(-250, 250) / 60.0f) + bunnies[bunniesCount].color.apply { + this.r = getRandomValue(50, 240).toUByte() + this.g = getRandomValue(80, 240).toUByte() + this.b = getRandomValue(100, 200).toUByte() + this.a = 255U + } + bunniesCount++ } - bunniesCount++ } } - } - // Update bunnies - for (i in 0.. SCREEN_WIDTH || - bunnies[i].position.x + texBunny.width / 2.0 < 0 - ) { - bunnies[i].speed.x *= -1f - } - if (bunnies[i].position.y + texBunny.height / 2.0 > SCREEN_HEIGHT || - bunnies[i].position.y + texBunny.height / 2.0 - 40 < 0 - ) { - bunnies[i].speed.y *= -1f - } - } - //---------------------------------------------------------------------------------- - - drawing { - // Draw - //---------------------------------------------------------------------------------- - clearBackground(rayWhite) + // Update bunnies for (i in 0.. SCREEN_WIDTH || + bunnies[i].position.x + texBunny.width / 2.0 < 0 + ) { + bunnies[i].speed.x *= -1f + } + if (bunnies[i].position.y + texBunny.height / 2.0 > SCREEN_HEIGHT || + bunnies[i].position.y + texBunny.height / 2.0 - 40 < 0 + ) { + bunnies[i].speed.y *= -1f + } } - drawRectangle(0, 0, SCREEN_WIDTH, 40, black) - drawText("bunnies: $bunniesCount", 120, 10, 20, green) - drawText("batched draw calls: " + bunniesCount / MAX_BATCH_ELEMENTS, 320, 10, 20, maroon) - drawFPS(10, 10) //---------------------------------------------------------------------------------- - } - } - // De-Initialization - //-------------------------------------------------------------------------------------- - unloadTexture(texBunny) // Unload bunny texture - closeWindow() // Close window and OpenGL context - //-------------------------------------------------------------------------------------- + drawing { + // Draw + //---------------------------------------------------------------------------------- + clearBackground(rayWhite) + for (i in 0..?, platform.posix.va_list?) -> Unit>> +/** + * Returns the absolute path to the 'resources' folder located at the same location as your executable. + * + * This property provides the path to the 'resources' folder associated with your executable. + * Ensure that a folder named 'resources' is present in the same directory as your executable. + * + * @return The absolute path to the 'resources' folder, or null if it doesn't exist or cannot be determined. + */ +internal expect val resourcePath: String? /** * Set custom trace log diff --git a/src/commonMain/kotlin/kaylibkit/kMath/KVector2.kt b/src/commonMain/kotlin/kaylibkit/kMath/KVector2.kt index 1c44b17..80c2dc6 100644 --- a/src/commonMain/kotlin/kaylibkit/kMath/KVector2.kt +++ b/src/commonMain/kotlin/kaylibkit/kMath/KVector2.kt @@ -245,7 +245,7 @@ inline fun Vector2.lerp(v2: Vector2, amount: Float) : Vector2 { // * @return [Vector2] // */ //@OptIn(ExperimentalForeignApi::class) -//inline fun Vector2.invert(): Vector2 { return kVector2(1.0f / this.x, 1.0f / this.y) } +//inline fun Vector2.invert(): Vector2 { return memScoped { kVector2(1.0f / this@invert.x, 1.0f / this@invert.y, this) } } ///** // * Clamp the components of the [Vector2] between diff --git a/src/linuxMain/kotlin/kaylibkit/kCore/KCore.linux.kt b/src/linuxMain/kotlin/kaylibkit/kCore/KCore.linux.kt index f204d01..1c443b6 100644 --- a/src/linuxMain/kotlin/kaylibkit/kCore/KCore.linux.kt +++ b/src/linuxMain/kotlin/kaylibkit/kCore/KCore.linux.kt @@ -2,8 +2,42 @@ package kaylibkit.kCore import kaylibc.TraceLogCallback import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.refTo +import kotlinx.cinterop.toKString +import platform.posix.PATH_MAX +import platform.posix.getpid +import platform.posix.realpath @OptIn(ExperimentalForeignApi::class) actual fun setTraceLogCallbackInternal(callback: TraceLogCallback) { kaylibc.SetTraceLogCallback(callback) -} \ No newline at end of file +} + +@OptIn(ExperimentalForeignApi::class) +actual inline val resourcePath: String? + get() { + // Get the process ID (PID) of the current process + val pid = getpid() + + // Create a buffer to store the path + val buffer = ByteArray(PATH_MAX) + + // Build the path to the '/proc' directory for the process + val procPath = "/proc/$pid/exe" + + // Use the realpath function to get the canonicalised absolute pathname of the executable + if (realpath(procPath, buffer.refTo(0)) == null) { + // If realpath fails, return null to indicate that the resource path could not be determined + return null + } + + // Convert the buffer, which contains the absolute path, to a Kotlin string + val executablePath = buffer.toKString() + + // Find the last '/' character to extract the directory path + val lastSlashIndex = executablePath.lastIndexOf('/') + val executableDir = executablePath.substring(0, lastSlashIndex + 1) + + // Construct the resource path by appending "/resources" to the executable directory + return executableDir + "resources" + } \ No newline at end of file diff --git a/src/macosMain/kotlin/kaylibkit/kCore/KCore.macos.kt b/src/macosMain/kotlin/kaylibkit/kCore/KCore.macos.kt index 921be6b..a8ff8c5 100644 --- a/src/macosMain/kotlin/kaylibkit/kCore/KCore.macos.kt +++ b/src/macosMain/kotlin/kaylibkit/kCore/KCore.macos.kt @@ -1,8 +1,45 @@ package kaylibkit.kCore import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.convert +import kotlinx.cinterop.refTo +import kotlinx.cinterop.toKString +import platform.osx.proc_pidpath +import platform.posix.PATH_MAX +import platform.posix.getpid @OptIn(ExperimentalForeignApi::class) actual fun setTraceLogCallbackInternal(callback: TraceLogCallback) { kaylibc.SetTraceLogCallback(callback) -} \ No newline at end of file +} + +@OptIn(ExperimentalForeignApi::class) +actual inline val resourcePath: String? + get() { + // Get the process ID of the current running process. + val pid = getpid() + + // Create a buffer to store the path to the executable file. + val buffer = ByteArray(PATH_MAX) + + // Use the proc_pidpath function to obtain the path to the executable file. + // The result is the length of the path. + val pathLength = proc_pidpath(pid, buffer.refTo(0), buffer.size.convert()) + + // Check if the path length is less than or equal to zero, indicating an error. + if (pathLength <= 0) { + return null + } + // Convert the buffer to a Kotlin string to get the full path to the executable. + val executablePath = buffer.toKString() + + // Find the index of the last slash character ('/') in the executable path, + // which separates the directory from the executable file name. + val lastSlashIndex = executablePath.lastIndexOf('/') + + // Extract the directory portion of the executable path, including the trailing slash. + val executableDir = executablePath.substring(0, lastSlashIndex + 1) + + // Return the directory path of the executable file along with the "resources" subdirectory. + return executableDir + "resources" + } \ No newline at end of file diff --git a/src/mingwMain/kotlin/kaylibkit/kCore/KCore.mingw.kt b/src/mingwMain/kotlin/kaylibkit/kCore/KCore.mingw.kt index 921be6b..40373ad 100644 --- a/src/mingwMain/kotlin/kaylibkit/kCore/KCore.mingw.kt +++ b/src/mingwMain/kotlin/kaylibkit/kCore/KCore.mingw.kt @@ -5,4 +5,7 @@ import kotlinx.cinterop.ExperimentalForeignApi @OptIn(ExperimentalForeignApi::class) actual fun setTraceLogCallbackInternal(callback: TraceLogCallback) { kaylibc.SetTraceLogCallback(callback) -} \ No newline at end of file +} + +actual inline val resourcePath: String? + get() { return "Not yet implemented" } \ No newline at end of file