Add resourcePath. Update examples

This commit is contained in:
Kenta 2023-09-16 21:44:48 +01:00
parent 284e28ace9
commit 9a0ab8e7b6
13 changed files with 477 additions and 332 deletions

View file

@ -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!
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'

View file

@ -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
//--------------------------------------------------------------------------------------
}
}

View file

@ -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
//--------------------------------------------------------------------------------------
}

View file

@ -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
//--------------------------------------------------------------------------------------
}

View file

@ -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
//--------------------------------------------------------------------------------------
}
}

View file

@ -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
//--------------------------------------------------------------------------------------
}
}

View file

@ -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..<bunniesCount) {
bunnies[i].position.x += bunnies[i].speed.x
bunnies[i].position.y += bunnies[i].speed.y
if (bunnies[i].position.x + texBunny.width / 2.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..<bunniesCount) {
// NOTE: When internal batch buffer limit is reached (MAX_BATCH_ELEMENTS),
// a draw call is launched and buffer starts being filled again;
// before issuing a draw call, updated vertex data from internal CPU buffer is send to GPU...
// Process of sending data is costly, and it could happen that GPU data has not been completely
// processed for drawing while new data is tried to be sent (updating current in-use buffers)
// it could generate a stall and consequently a frame drop, limiting the number of drawn bunnies
drawTexture(
texBunny,
bunnies[i].position.x.toInt(),
bunnies[i].position.y.toInt(),
bunnies[i].color
)
bunnies[i].position.x += bunnies[i].speed.x
bunnies[i].position.y += bunnies[i].speed.y
if (bunnies[i].position.x + texBunny.width / 2.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..<bunniesCount) {
// NOTE: When internal batch buffer limit is reached (MAX_BATCH_ELEMENTS),
// a draw call is launched and buffer starts being filled again;
// before issuing a draw call, updated vertex data from internal CPU buffer is send to GPU...
// Process of sending data is costly, and it could happen that GPU data has not been completely
// processed for drawing while new data is tried to be sent (updating current in-use buffers)
// it could generate a stall and consequently a frame drop, limiting the number of drawn bunnies
drawTexture(
texBunny,
bunnies[i].position.x.toInt(),
bunnies[i].position.y.toInt(),
bunnies[i].color
)
}
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
//-------------------------------------------------------------------------------------- }
}
}

View file

@ -20,7 +20,7 @@ fun main() {
//--------------------------------------------------------------------------------------
// NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
val texture = loadTexture("resources/raylib_logo.png", allocator = this) // Texture loading
val texture = loadTexture("$resourcePath/raylib_logo.png", allocator = this) // Texture loading
// Main game loop
while (!windowShouldClose) { // Detect window close button or ESC key

View file

@ -847,6 +847,15 @@ inline fun setTraceLogLevel(logLevel: TraceLogLevel) {
@OptIn(ExperimentalForeignApi::class)
typealias TraceLogCallback = CPointer<CFunction<(Int, CPointer<ByteVar>?, 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

View file

@ -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

View file

@ -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)
}
}
@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"
}

View file

@ -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)
}
}
@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"
}

View file

@ -5,4 +5,7 @@ import kotlinx.cinterop.ExperimentalForeignApi
@OptIn(ExperimentalForeignApi::class)
actual fun setTraceLogCallbackInternal(callback: TraceLogCallback) {
kaylibc.SetTraceLogCallback(callback)
}
}
actual inline val resourcePath: String?
get() { return "Not yet implemented" }