Compare commits

..

5 Commits

Author SHA1 Message Date
493msi 9804e9f3f5 Minor fixes 2020-09-24 03:42:39 +02:00
493msi c3db492a6d Moved generic resolvers to a separate package 2020-09-24 03:42:39 +02:00
493msi 5952a26fee Code restructure and began documentation 2020-09-24 03:42:34 +02:00
493msi aa70f1bbe2 [PlutoCommandParser] Code cleanup 2020-09-24 03:41:52 +02:00
493msi c3bd358bed Readded PlutoCommandParser 2020-09-24 03:40:53 +02:00
542 changed files with 8651 additions and 24145 deletions

0
.gitattributes vendored Executable file → Normal file
View File

View File

@ -1,40 +0,0 @@
name: Gradle Package
on:
release:
types: [created]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Check out the repository and all submodules
uses: actions/checkout@v2
with:
submodules: recursive
- name: Set up JDK 17
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'temurin'
server-id: github
settings-path: ${{ github.workspace }}
- name: Set up Gradle
uses: gradle/gradle-build-action@v2
- name: Build and publish to Vega
run: |
chmod +x ./gradlew
./gradlew :plutoengine:publish --stacktrace --info -x test
./gradlew :plutoengine-ext:publish --stacktrace --info -x test
env:
ORG_GRADLE_PROJECT_signingKey: ${{ secrets.GPG_PRIVATE_KEY }}
ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.GPG_PASSWORD }}
ORG_GRADLE_PROJECT_vegaUsername: ${{ secrets.VEGA_USERNAME }}
ORG_GRADLE_PROJECT_vegaPassword: ${{ secrets.VEGA_PASSWORD }}

View File

@ -1,36 +0,0 @@
name: Gradle Test Build
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Check out the repository and all submodules
uses: actions/checkout@v2
with:
submodules: recursive
- name: Set up JDK 17
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'temurin'
server-id: github
settings-path: ${{ github.workspace }}
- name: Set up Gradle
uses: gradle/gradle-build-action@v2
- name: Build
run: |
chmod +x ./gradlew
./gradlew build --stacktrace --info -x test

8
.gitignore vendored Executable file → Normal file
View File

@ -1,17 +1,13 @@
/*/.settings
/.vscode
# Ignore Eclipse project files
/*/.project
/*/.classpath
/.project
/.settings
# Ignore IDEA project files
/.idea
/*/.idea
.idea
*.log
@ -23,7 +19,3 @@
# Ignore Gradle build output directory
/build
/*/build
/bin
/*/bin
/logs/

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "libra"]
path = libra
url = git@github.com:493msi/libra.git

2
LICENSE Executable file → Normal file
View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2019-2022 493msi
Copyright (c) 2019-2020 493msi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,35 +0,0 @@
SOFTWARE LICENSING
==================
While PlutoEngine is licensed under the MIT license, see
individual libraries and their license requirements.
MEDIA LICENSING
===============
This repository contains some first-party media files, such as audio,
fonts and images. See "Third party media within this repository" for
exceptions.
Unless specified otherwise:
This content may be freely used under the https://creativecommons.org/publicdomain/zero/1.0/ license
as long as it is used within an application based on PlutoEngine and does not misrepresent
PlutoEngine or any of the PlutoEngine authors and does not remove this restriction.
OR
This content may be freely used under the https://creativecommons.org/licenses/by-nd/4.0/ license
with no further restrictions.
OR
This content may be freely used under the https://creativecommons.org/licenses/by-sa/4.0/ license
with no further restrictions.
Third party media within this repository
========================================
file "engine-demo/jsr-clone/mods/tefek.srclone/default/sound/game_st.ogg":
"Safehouse" by Selulance
https://www.youtube.com/watch?v=-kNx6sqReFk
Licensed under https://creativecommons.org/licenses/by/3.0/

42
NEXT_RELEASE_DRAFT.md Normal file
View File

@ -0,0 +1,42 @@
## Features targeted for 20.2.0.0-alpha.2
* The stage subsystem
* A "stage", in this context, is a set of assets bound together
by programming logic, not necessarily a game level.
Stage switching and asset management are handled by the engine.
* Upon stage switch
1. Unload unused assets
2. Load new assets
* Provide multiple means of stage switching
* Three modes with the initial release
1. Instant switch
* Assets will be loaded and unloaded synchronously
* The stage switch will happen in one frame
2. Deferred switch
* The stage will continue running until all assets load
* Assets will load synchronously, but at a slower pace
to avoid frame stutter
3. Asynchronous switch
* Assets will be loaded in asynchronously, where applicable
* Falls back to deferred switching for synchronous loading,
such as OpenGL texture upload
* Automated asset loading
* All asset management will eventually be handled by `PlutoCore`
* This includes audio clips, textures, sprites
* Add a common interface for all assets
* Let the stage system handle audio playback
* This API should be as neutral as possible and avoid steering towards
game-only use
* The stage manager should be relatively low-overhead and allow multiple
instances
* Allow stages to be inherited from, creating a stack-like structure
* The initial minimal release of `[PlutoCommandParser]`
## Features targeted for 20.2.0.0-alpha.3
* `[PlutoLib]` Completely redo the ModLoader system
* The current implementation is a result of 5 years of feature creep
* Large scale API changes, however the general idea should stay the same
* Rethink the class loader system.
* `[PlutoAudio]` Integrate the Audio API with the Stage API
* Improve upon the support of thread-local Pluto instances
* The long term goal is to allow an unlimited amount of Pluto applications at any given time

95
README.md Executable file → Normal file
View File

@ -1,56 +1,7 @@
# plutoengine
![Build Status](https://github.com/493msi/plutoengine/workflows/Gradle%20Package/badge.svg)
![Maven Version](https://img.shields.io/github/v/tag/493msi/plutoengine?label=Latest%20Version)
My hobby game engine. This repository unifies all my previous Pluto repositories.
## How to use Pluto
**Quick start**
Download [the demo project](https://github.com/plutoengine/plutoengine-basic-demo) open it in IntelliJ IDEA.
**Gradle**
```groovy
repositories {
mavenCentral()
maven {
name = "Vega"
url = uri("https://vega.botdiril.com/releases")
}
}
dependencies {
implementation group: "org.plutoengine", name: "plutocore", version: "22.3.0.0-alpha.0"
}
```
**or for Gradle Kotlin DSL**
```kotlin
repositories {
mavenCentral()
maven {
name = "Vega"
url = uri("https://vega.botdiril.com/releases")
}
}
dependencies {
implementation("org.plutoengine", "plutocore", "22.3.0.0-alpha.0")
}
```
### Licensing
The code of PlutoEngine is licensed under the MIT license.
See [LICENSING_INFO](https://github.com/493msi/plutoengine/blob/master/LICENSING_INFO.txt) for further information.
### Versioning
All submodules share a version number for simplicity reasons.
@ -70,26 +21,42 @@ version numbers.*
## Usability status of submodules
Keep in mind PlutoEngine is in alpha and all features are tentative.
The following list simply provides an overview of how likely breaking changes are to occur.
### Safe submodules
* **PlutoCore** - Stable
* **PlutoSpritesheet** - Stable, some features are unfinished
* **PlutoDisplay** - Stable, collision API nowhere near completion
* **PlutoLib** - Mostly stable
* **PlutoRender** - Stable
* **PlutoRuntime** - Mostly stable
* **PlutoFramebuffer** - Stable
* **PlutoGUI** - Stable, awaiting a rewrite
* **PlutoLib** - Mostly stable, the module API still has some quirks
* **PlutoMesher** - Stable
* **PlutoShader** - Stable
* **PlutoSpriteSheet** - Stable, some features are unfinished
* **PlutoStatic** - Stable, collision API nowhere near completion
### Unstable submodules
* **PlutoAudio** - Very tentative, work in progress
* **PlutoGUI** - Recently rewritten, the API is highly unstable, work in progress
### Extensions
* **PlutoUSS2** - Stable
* **PlutoGameObject** - Stable
* **PlutoAudio** - Somewhat usable, unfinished
### Broken submodules, do NOT use
* **PlutoCommandParser** - Unfinished, broken, unusable
* **PlutoDB** - Broken, unusable
## Current priorities
See [issues](https://github.com/493msi/plutoengine/issues) for details.
### Very high priority
* Finish PlutoAudio
* Depends on the stage system
* The stage system and automated asset loading
* Rewrite the ModLoader
* Finish PlutoCommandParser
### High priority
* Streamline PlutoLib, remove bad APIs and improve code quality
### Normal priority
* Rewrite PlutoGUI
* The collision system for PlutoStatic
* Improve image loading capabilities, possibly rewrite PlutoLib#TPL
### Low priority
* Allow multiple running instances of Pluto
* Alternatively, if this deems too difficult to implement,
prohibit the creation of more than instance per VM to avoid issues
* A networking API

152
UPDATE_NOTES.md Executable file → Normal file
View File

@ -1,167 +1,23 @@
## 22.3.0.0-alpha.1
* `[PlutoComponent]` Removing components using a token should have the same semantics as removing individual components
* `[PlutoComponent]` Made the addition and removal of components hookable before mount events are fired
## 22.3.0.0-alpha.0
* `[SDK]` **Combined `PlutoFramebuffer`, `PlutoMesher`, `PlutoShader` and `PlutoTexture`
into `PlutoRender`**
* Unified the package structure
* `[SDK]` **Added the license text to all source files to conform with the MIT license requirements**
* `plutoengine-demos/jsr-clone` Added a proper license file for the music
## 22.2.0.0-alpha.2
* `[SDK]` The libraries now always reference natives for all architectures
* `[SDK]` Replaced `NEXT_RELEASE_DRAFT.md` with [an issue tracker](https://github.com/493msi/plutoengine/issues)
* `[PlutoAudio]` **Partial rewrite and support for managed sound effects**
* `plutoengine-demos/` **Added the `jsr-clone` demo**
* `[PlutoSpritesheet]` Renamed `TemporalSprite#getSideCount` to `getFrameCount`
## 22.2.0.0-alpha.1
* `[PlutoGUI]` **Added support for bitmap fonts**
* `[PlutoGUI]` Generalized the font renderer API
* `plutoengine-demos/` Removed third-party fonts
* `[PlutoRuntime]` The `ModLoader` component is now opaque,
pre-added mods are now specified when creating the token
* `[PlutoRuntime]` Added a linting annotation to `Logger#logf`
* `[PlutoRuntime]` Fixed a bug where creating relative resource paths
from URIs was not possible
* `[PlutoLib]` Fixed `toRGBA` in `HSB` and `HSBA`
* `[PlutoLib]` Added `BasicInterpolation`
* `[PlutoSpritesheet]` Added `recolor(IRGBA)` to `RectangleRenderer2D` and `Renderer2D`
* `[PlutoSpritesheet]` Added `TemporalSprite` and `OrientedSprite`
## 22.2.0.0-alpha.0
* `[PlutoComponent]` **Added support for dependencies and strengtened type checks**
* `[PlutoComponent]` *Removed* `IComponent` as it was redundant to `AbstractComponent`
* `[Pluto*]` *Removed* JSR 305 annotations in favor of JetBrains annotations
* `[Pluto*]` *Removed* the `ConstantExpression` annotation in favor of `Contract`
* `[PlutoRuntime]` *Moved* `ThreadSensitive` to `org.plutoengine.address`
* `[PlutoAudio]` Transformed into a PlutoLocalComponent
* `[PlutoAudio]` `IAudioStream` is now `AutoCloseable`
* `[PlutoCore]` `InputBus` is now tied to a specific `Display` instead of searching for one in the Local
* `[PlutoCore]` Separated `Mouse` and `Keyboard` from `InputBus` into child components
* `[PlutoCore]` Added an `init()` method that gets called before entering the main loop
## 22.1.0.0-alpha.1
* `plutoengine-demos/basic-application` Made the gradient in the fragment font shader rotatable
## 22.1.0.0-alpha.0
* `[PlutoMesher]` **Partial rewrite**
* *Removed* `VecArray`
* Reduced pointless abstraction
* Creation and destruction no longer logged
* `[PlutoGUI]` **Complete rewrite of the GUI library**
* `[Pluto*]` **Unified the cleanup methods of all OpenGL object classes to `close`**
* `[PlutoLib]` New dependency: `joml-primitives`
* `[PlutoLib]` Now has a `module-info.java`
* `[PlutoLib]` Now uses JetBrains annotations instead of JSR 305
* `[PlutoDisplay]` Removed the `flipped` word from all buffer functions
* `[PlutoRuntime]` Fixed opening .zip filesystems
* `[PlutoShader]` Added `UniformArrayFloat`, `UniformArrayRGBA`,
`UniformArrayVec2`, `UniformArrayVec3`, `UniformArrayVec4`
* `[PlutoRuntime]` `SmartSeverity.MODULE_CHECK` now correctly uses the standard output instead of `stderr`.
## 22.0.0.0-alpha.7
* `[PlutoRuntime]` Fixed several resource filesystem bugs
## 22.0.0.0-alpha.6
* `[PlutoSpritesheet]` Added a constructor to `PartialTextureSprite` that initializes the spritesheet to `null`
## 22.0.0.0-alpha.5
* `[PlutoRuntime]` Fixed module load ordering
## 22.0.0.0-alpha.4
* `[PlutoRuntime]` Implemented optional `ResourceFileSystem` features
## 22.0.0.0-alpha.3
* `[SDK]` **Extensions are now published via GitHub actions**
## 22.0.0.0-alpha.2
* `[SDK]` **Created a new extension project category**
* `[PlutoUSS2]` **Now an extension**
* `PlutoLib` no longer depends on `PlutoUSS2`
* `[PlutoGameObject]` **Reimplemented `RAID` as a Pluto extension**
## 22.0.0.0-alpha.1
* `[SDK]` Jar sources and JavaDoc are now published
* `[PlutoRuntime]` `Mod` objects now properly contain the version number
## 22.0.0.0-alpha.0
* Version bumped to 2022
* `[SDK]` Maven version is now properly set again
## 20.2.0.0-alpha.3
* `[SDK]` Restructured the repository
* All build scripts are now written in Kotlin
* **Added runnable examples**
* **Upgraded to Java 17** to take advantage of new language features and a more efficient JVM
* **The repostiory now contains examples**
* **Moved all classes to the `org.plutoengine` package**
* *Removed* the prepackaged JVM wrapper introduced in the previous alpha
as it caused numerous issues
* In the future, JDKs will be packaged with the SDK
* `[PlutoComponent]` **Added PlutoComponent as a new module**
* `[PlutoLib]` `PlutoLib` now depends on `PlutoComponent`
* `[PlutoUSS2]` **Added USS2 as a new module**
* `[PlutoLib]` `PlutoLib` now depends on `PlutoUSS2`
* `[PlutoLib]` **Greatly simplified the API and moved PlutoEngine specific classes to `PlutoRuntime`**
* ***Moved* the module system to `PlutoRuntime`**
* *Removed* `ResourceSubscriber`,
* *Removed* `cz.tefek.pluto.io.pluto.pp`
* *Removed* `RAID`
* *Moved* `Logger`, `OutputSplitStream` to `PlutoRuntime`
* *Removed* `Severity`, use `SmartSeverity` instead
* *Removed* `TextIn`, `TextOut`, `ResourceImage` and `ResourceInputStream`
* Use Java's NIO instead
* *Removed* `StaticPlutoEventManager` as the implementation was too obscure
* The module system now uses its own event management
* *Removed* the `EventData` class
* `[PlutoRuntime]` **Added PlutoRuntime as a new module**
* **Completely rewrote the module system**
* *Removed* support for external mods as the feature needs a complete overhaul
* **Revamped resource system now based on NIO**
* *Moved* the logging system from `PlutoLib` to `PlutoRuntime`
* Made `OutputSplitStream` public as it is now reusable
* **Added the Version API**
* Added the `IVersion` interface
* Added support for version objects
* As a result, all fields in `Pluto` except the version string are no longer compile-time constants
* Added the `@ConstantExpression` annotation
* `[PlutoDisplay]` **Renamed `PlutoStatic` to `PlutoDisplay`**
* Added the `ModGLFW` virtual module
* `DisplayErrorCallback` and simplified the callbacks in `Display`
* `[PlutoCommandParser]` **Module discontinued as a part of PlutoEngine, it will still be developed seprately**
* `[PlutoTexturing]` Renamed to `PlutoTexture`
* Removed `Texture#load(String)` and `Texture#load(String, MagFilter, MinFilter, WrapMode...)`
* `[PlutoLib]` The transitive dependency JOML is now provided by `PlutoLib` instead of `PlutoStatic`
* `[PlutoLib]` Created a simple Color API
* `[PlutoLib]` Added the 8-bit RGBA `Color` class as a counterpart to AWT's `Color` class
* `[PlutoLib]` Added the `RGBA` and `RGB` single precision float color objects
* `[PlutoLib]` Added the respective `IRGBA` and `IRGB` read-only interfaces
* `[PlutoLib]` Added the `HSBA` and `HSB` single precision float color objects
* `[PlutoLib]` Added methods to convert between HSBA, RGBA, HSB and RGB
* `[PlutoShader]` Added the `UniformRGBA` and `UniformRGB` shader uniform types
* `[PlutoCore]` Made `PlutoApplication`'s constructor protected
* `[PlutoLib]` `MiniTimeParseException` no longer contains a hardcoded String message
## 20.2.0.0-alpha.2
* `build.gradle` Extracted the version numbers into separate variables
* `build.gradle` **[experimental]** `gradlew` should now automatically download JDK11 when needed
* `build.gradle` Updated the build scripts and added source Maven publication
* `[PlutoLib]` Renamed the `cz.tefek.pluto.eventsystem` package to `cz.tefek.pluto.event`
* Moved all subpackages
* Updated all references
* `[PlutoLib]` Minor code cleanup in `cz.tefek.pluto.modloader.event`
* `[Pluto]` Moved `TPL` from `cz.tefek.pluto.tpl` to `cz.tefek.pluto.io.tpl`
* Updated all references
* `[PlutoMesher]` Renamed all occurrences of `attrib` to `attribute`
* Renamed `VertexArray#createArrayAttrib` to `VertexArray#createArrayAttribute`
* Renamed `VertexArray#getVertexAttribs` to `VertexArray#getVertexAttributes`
* `[PlutoCore]` Made `PlutoApplication.StartupConfig` fields private, options
can now only be modified only through public setters
* `[PlutoLib]` Added the `ThreadSensitive` annotation
* `[PlutoLib]` Renamed `MiniTimeCouldNotBeParsedException` to `MiniTimeParseException`
* `[PlutoCore]` Refactored `InputBus` and added several convenience methods
* `[PlutoCore]` Refactored input callbacks
* `[PlutoStatic]` Slight cleanup in the `Display` and `DisplayBuilder` classes
* `[PlutoCommandParser]` **Initial release**
## 20.2.0.0-alpha.1
* `[PlutoLib#cz.tefek.pluto.io.logger]` Refactored the Logger subsystem
@ -188,4 +44,4 @@
* `[PlutoCore]` `[PlutoApplication]` now properly closes the `Logger` on exit
* `[PlutoLib]` Various typo fixes
* `[Pluto*]` Deprecated `Severity` for `SmartSeverity` and replaced all usages
* `[Pluto*]` Replaced `CRLF` with `LF` in all Java source files
* `[Pluto*]` Deprecated `CRLF` with `LF` in all Java source files

83
build.gradle Normal file
View File

@ -0,0 +1,83 @@
import org.gradle.internal.os.OperatingSystem
plugins {
id "me.filippov.gradle.jvm.wrapper" version "0.9.3"
}
jvmWrapper {
linuxJvmUrl = "https://corretto.aws/downloads/latest/amazon-corretto-11-x64-linux-jdk.tar.gz"
macJvmUrl = "https://corretto.aws/downloads/latest/amazon-corretto-11-x64-macos-jdk.tar.gz"
windowsJvmUrl = "https://corretto.aws/downloads/latest/amazon-corretto-11-x64-windows-jdk.zip"
}
wrapper {
distributionType = Wrapper.DistributionType.ALL
}
project.ext.versionYear = 20
project.ext.versionMajor = 2
project.ext.versionMinor = 0
project.ext.versionPatch = 0
project.ext.isPrerelease = true
project.ext.prereleaseName = "alpha"
project.ext.prerealeaseUpdate = 2
subprojects {
apply plugin: 'java'
apply plugin: 'maven-publish'
project.ext.lwjglVersion = "3.2.3"
project.ext.jomlVersion = "1.9.25"
project.ext.steamworks4jVersion = "1.8.0"
project.ext.steamworks4jServerVersion = "1.8.0"
group = "cz.tefek"
version = isPrerelease ?
"${versionYear}.${versionMajor}.${versionMinor}.${versionPatch}-${prereleaseName}.${prerealeaseUpdate}"
:
"${versionYear}.${versionMajor}.${versionMinor}.${versionPatch}"
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
task sourcesJar(type: Jar, dependsOn: classes) {
from sourceSets.main.allJava
}
publishing {
publications {
maven(MavenPublication) {
from components.java
artifact sourcesJar {
classifier "sources"
}
}
}
}
switch (OperatingSystem.current()) {
case OperatingSystem.LINUX:
project.ext.lwjglNatives = "natives-linux"
break
case OperatingSystem.MAC_OS:
project.ext.lwjglNatives = "natives-macos"
break
case OperatingSystem.WINDOWS:
project.ext.lwjglNatives = "natives-windows"
break
}
repositories {
mavenCentral()
}
}

View File

@ -1,19 +0,0 @@
import org.plutoengine.Versions
project.ext["isPlutoBuild"] = true;
tasks.withType<Wrapper> {
distributionType = Wrapper.DistributionType.ALL
gradleVersion = "7.4.2"
}
allprojects {
group = "org.plutoengine"
version = Versions.versionFull
}
subprojects {
tasks.withType<JavaCompile> {
options.encoding = "UTF-8"
}
}

View File

@ -1,24 +0,0 @@
plugins {
`kotlin-dsl`
}
repositories {
mavenCentral()
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions {
jvmTarget = "17"
}
}
dependencies {
implementation("org.jetbrains.kotlin", "kotlin-gradle-plugin", "1.6.20")
implementation(gradleApi())
}

View File

@ -1,40 +0,0 @@
package org.plutoengine
import org.gradle.api.JavaVersion
object Versions {
const val lwjglVersion = "3.3.1"
val lwjglNatives = listOf(
"natives-linux-arm64",
"natives-linux-arm32",
"natives-linux",
"natives-macos-arm64",
"natives-macos",
"natives-windows-arm64",
"natives-windows",
"natives-windows-x86"
)
const val jomlVersion = "1.10.2"
const val jomlPrimitivesVersion = "1.10.0"
const val steamworks4jVersion = "1.8.0"
const val steamworks4jServerVersion = "1.8.0"
const val versionYear = 22
const val versionMajor = 3
const val versionMinor = 0
const val versionPatch = 0
const val isPrerelease = true
const val prereleaseName = "alpha"
const val prerealeaseUpdate = 1
val versionFull =
if (isPrerelease)
"$versionYear.$versionMajor.$versionMinor.$versionPatch-$prereleaseName.$prerealeaseUpdate"
else
"$versionYear.$versionMajor.$versionMinor.$versionPatch"
val javaTargetVersion = JavaVersion.VERSION_17
}

View File

@ -1,31 +0,0 @@
/*/.settings
/.vscode
# Ignore Eclipse project files
/*/.project
/*/.classpath
/.project
/.settings
# Ignore IDEA project files
/.idea
/*/.idea
.idea
*.log
/.gradle/
# Ignore Gradle project-specific cache directory
.gradle
# Ignore Gradle build output directory
/build
/*/build
/bin
/*/bin
/out
/*/out

View File

@ -1,70 +0,0 @@
import org.plutoengine.Versions
task("publish") {
file(".").listFiles().forEach {
if (!it.isDirectory)
return@forEach
dependsOn(":plutoengine:${it.name}:publish")
}
}
subprojects {
apply(plugin = "java")
apply(plugin = "java-library")
apply(plugin = "maven-publish")
apply(plugin = "signing")
repositories {
mavenCentral()
}
configure<JavaPluginExtension> {
sourceCompatibility = Versions.javaTargetVersion
targetCompatibility = Versions.javaTargetVersion
withJavadocJar()
withSourcesJar()
}
configure<SourceSetContainer> {
named("main") {
tasks.withType<Jar> {
from(allJava)
}
}
}
configure<PublishingExtension> {
publications {
create<MavenPublication>("maven") {
from(components["java"])
}
}
repositories {
maven {
name = "Vega"
url = uri("https://vega.botdiril.com/releases")
credentials {
val vegaUsername: String? by project
val vegaPassword: String? by project
username = vegaUsername
password = vegaPassword
}
}
}
}
tasks.withType<Jar> {
duplicatesStrategy = DuplicatesStrategy.INCLUDE
}
configure<SigningExtension> {
val signingKey: String? by project
val signingPassword: String? by project
useInMemoryPgpKeys(signingKey, signingPassword)
sign(the<PublishingExtension>().publications["maven"])
}
}

View File

@ -1,18 +0,0 @@
import org.plutoengine.Versions
plugins {
java
`java-library`
}
description = "PlutoEngine's sound subsystem."
dependencies {
api(project(":plutoengine:plutodisplay"))
api("org.lwjgl:lwjgl-openal")
org.plutoengine.Versions.lwjglNatives.forEach {
runtimeOnly("org.lwjgl", "lwjgl-openal", classifier = it)
}
}

View File

@ -1,95 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio;
import org.lwjgl.system.MemoryUtil;
import org.plutoengine.buffer.BufferHelper;
import org.plutoengine.logger.Logger;
import org.plutoengine.logger.SmartSeverity;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
public class AudioLoader
{
/**
* Loads an audio track denoted by this {@link Path} into memory
* for from-memory Vorbis decoding and streaming. Good for frequently used
* medium-sized audio files, however it is discouraged to use such a track
* in multiple audio sources at once due to the cost of seeking.
*/
public static SeekableTrack loadMemoryDecoded(Path path)
{
Logger.logf(SmartSeverity.AUDIO_PLUS, "Loading audio file: %s\n", path);
try
{
return new MemoryDecodedVorbisTrack(path);
}
catch (IOException e)
{
Logger.logf(SmartSeverity.AUDIO_ERROR, "Failed to load an audio file: '%s'\n", path);
e.printStackTrace();
return null;
}
}
/**
* Loads an audio track denoted by this {@link Path} into memory
* for from-memory PCM streaming. Good for frequently used small audio
* files.
*/
public static RandomAccessClip loadMemoryPCM(Path path)
{
Logger.logf(SmartSeverity.AUDIO_PLUS, "Loading audio file: %s\n", path);
try
{
return new MemoryPCMClip(path);
}
catch (IOException e)
{
Logger.logf(SmartSeverity.AUDIO_ERROR, "Failed to load an audio file: '%s'\n", path);
e.printStackTrace();
return null;
}
}
static ByteBuffer loadIntoMemory(Path path) throws IOException
{
var size = Files.size(path);
if (size > Integer.MAX_VALUE)
throw new IOException("File '%s' is too big to be loaded!".formatted(path));
var readData = MemoryUtil.memAlloc((int) size);
return BufferHelper.readToByteBuffer(path, readData);
}
}

View File

@ -1,36 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio;
public abstract class ClipTrack extends SeekableTrack implements ISeekableClip
{
protected int samplesLength;
@Override
public int getLengthInSamples()
{
return this.samplesLength;
}
}

View File

@ -1,34 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio;
public interface IAudio extends AutoCloseable
{
int getSampleRate();
int getChannels();
void close();
}

View File

@ -1,30 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio;
public interface IClip extends IAudio
{
int getLengthInSamples();
}

View File

@ -1,32 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio;
import java.nio.ShortBuffer;
public interface IRandomAccessAudio extends IClip
{
int getSamples(ShortBuffer pcm, int offset, boolean loopRead);
}

View File

@ -1,38 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio;
public interface ISeekableClip extends ISeekableTrack, IClip
{
default void skip(int sampleCount)
{
this.seek(Math.min(Math.max(0, this.getSampleOffset() + sampleCount), this.getLengthInSamples()));
}
default void skipTo(float offset0to1)
{
this.seek(Math.round(this.getLengthInSamples() * offset0to1));
}
}

View File

@ -1,35 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio;
public interface ISeekableTrack extends IStreamingAudio
{
void seek(int sampleIndex);
default void rewind()
{
this.seek(0);
}
}

View File

@ -1,34 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio;
import java.nio.ShortBuffer;
public interface IStreamingAudio extends IAudio
{
int getSamples(ShortBuffer pcm);
int getSampleOffset();
}

View File

@ -1,119 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio;
import org.lwjgl.stb.STBVorbis;
import org.lwjgl.stb.STBVorbisInfo;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import org.plutoengine.logger.Logger;
import org.plutoengine.logger.SmartSeverity;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.nio.file.Path;
public class MemoryDecodedVorbisTrack extends ClipTrack
{
protected long handle;
private final ByteBuffer encodedAudio;
MemoryDecodedVorbisTrack(Path path) throws IOException
{
try
{
this.encodedAudio = AudioLoader.loadIntoMemory(path);
}
catch (IOException e)
{
this.close();
throw e;
}
try (MemoryStack stack = MemoryStack.stackPush())
{
IntBuffer error = stack.mallocInt(1);
this.handle = STBVorbis.stb_vorbis_open_memory(this.encodedAudio, error, null);
if (this.handle == MemoryUtil.NULL)
{
this.close();
throw new IOException(String.format("Failed to load '%s', error code %d.\n", path, error.get(0)));
}
STBVorbisInfo info = STBVorbisInfo.malloc(stack);
STBVorbis.stb_vorbis_get_info(this.handle, info);
this.channels = info.channels();
this.sampleRate = info.sample_rate();
}
this.samplesLength = STBVorbis.stb_vorbis_stream_length_in_samples(this.handle);
Logger.logf(SmartSeverity.AUDIO, """
\tSample rate:\t%d
\t\tChannels:\t%d
\t\tSamples:\t%d
%n""", this.sampleRate, this.channels, this.samplesLength);
}
@Override
public synchronized int getSamples(ShortBuffer pcm)
{
if (this.handle == MemoryUtil.NULL)
{
return -1;
}
return STBVorbis.stb_vorbis_get_samples_short_interleaved(this.handle, this.getChannels(), pcm);
}
@Override
public void close()
{
MemoryUtil.memFree(this.encodedAudio);
if (this.handle != MemoryUtil.NULL)
{
STBVorbis.stb_vorbis_close(this.handle);
this.handle = MemoryUtil.NULL;
}
}
@Override
public synchronized void seek(int sampleIndex)
{
STBVorbis.stb_vorbis_seek(this.handle, sampleIndex);
}
@Override
public int getSampleOffset()
{
return STBVorbis.stb_vorbis_get_sample_offset(this.handle);
}
}

View File

@ -1,125 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio;
import org.lwjgl.stb.STBVorbis;
import org.lwjgl.stb.STBVorbisInfo;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.nio.file.Path;
public class MemoryPCMClip extends RandomAccessClip
{
private final ShortBuffer pcmAudio;
MemoryPCMClip(Path path) throws IOException
{
long handle = MemoryUtil.NULL;
ByteBuffer audioBytes = null;
try (MemoryStack stack = MemoryStack.stackPush())
{
audioBytes = AudioLoader.loadIntoMemory(path);
IntBuffer error = stack.mallocInt(1);
handle = STBVorbis.stb_vorbis_open_memory(audioBytes, error, null);
if (handle == MemoryUtil.NULL)
{
this.close();
throw new IOException(String.format("Failed to load '%s', error code %d.\n", path, error.get(0)));
}
STBVorbisInfo info = STBVorbisInfo.malloc(stack);
STBVorbis.stb_vorbis_get_info(handle, info);
this.channels = info.channels();
this.sampleRate = info.sample_rate();
// Downmix to mono, SOUNDS HORRIBLE
//
// this.channels = 1;
// this.samplesLength = STBVorbis.stb_vorbis_stream_length_in_samples(handle) * this.channels;
// this.pcmAudio = MemoryUtil.memAllocShort(this.samplesLength);
// var ptr = stack.pointers(this.pcmAudio);
// STBVorbis.stb_vorbis_get_samples_short(handle, ptr, this.samplesLength);
this.samplesLength = STBVorbis.stb_vorbis_stream_length_in_samples(handle) * this.channels;
this.pcmAudio = MemoryUtil.memAllocShort(this.samplesLength);
STBVorbis.stb_vorbis_get_samples_short_interleaved(handle, this.channels, this.pcmAudio);
}
catch (IOException e)
{
this.close();
throw e;
}
finally
{
MemoryUtil.memFree(audioBytes);
if (handle != MemoryUtil.NULL)
{
STBVorbis.stb_vorbis_close(handle);
}
}
}
@Override
public int getLengthInSamples()
{
return this.samplesLength / this.getChannels();
}
@Override
public int getSamples(ShortBuffer pcm, int offset, boolean loopRead)
{
int readTotal = 0;
int read;
do
{
int thisRemaining = this.pcmAudio.limit() - offset;
read = Math.min(pcm.remaining() - readTotal, thisRemaining);
pcm.put(pcm.position() + readTotal, this.pcmAudio, offset, read);
readTotal += read;
offset = (offset + read) % (this.getLengthInSamples() * this.channels);
}
while (loopRead && pcm.limit() - readTotal > 0);
return readTotal / this.getChannels();
}
@Override
public void close()
{
MemoryUtil.memFree(this.pcmAudio);
}
}

View File

@ -1,36 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio;
public abstract class RandomAccessClip extends Track implements IRandomAccessAudio, IClip
{
protected int samplesLength;
@Override
public int getLengthInSamples()
{
return this.samplesLength;
}
}

View File

@ -1,29 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio;
public abstract class SeekableTrack extends Track implements ISeekableTrack
{
}

View File

@ -1,43 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio;
abstract class Track implements IAudio
{
protected int channels;
protected int sampleRate;
@Override
public int getChannels()
{
return this.channels;
}
@Override
public int getSampleRate()
{
return this.sampleRate;
}
}

View File

@ -1,59 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio.al;
import org.lwjgl.openal.AL10;
import java.nio.ShortBuffer;
class AudioBuffer implements AutoCloseable
{
private final int id;
private final int format;
private final int sampleRate;
AudioBuffer(int id, int format, int sampleRate)
{
this.id = id;
this.format = format;
this.sampleRate = sampleRate;
}
public int getID()
{
return this.id;
}
public void writeData(ShortBuffer data)
{
AL10.alBufferData(this.id, this.format, data, this.sampleRate);
}
@Override
public void close()
{
AL10.alDeleteBuffers(this.id);
}
}

View File

@ -1,68 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio.al;
import org.plutoengine.audio.RandomAccessClip;
import java.nio.ShortBuffer;
public class AudioClipSource extends AudioDoubleBufferedSource
{
private final RandomAccessClip clip;
private final boolean looping;
private int readHead = 0;
public AudioClipSource(RandomAccessClip clip, boolean looping)
{
super(clip);
this.clip = clip;
this.looping = looping;
}
public AudioClipSource(RandomAccessClip clip)
{
this(clip, false);
}
@Override
protected int getSamples(ShortBuffer pcmTransferBuf)
{
var read = this.clip.getSamples(pcmTransferBuf, this.readHead * this.channels, this.looping);
this.readHead += read / this.channels;
if (this.looping)
this.readHead %= this.clip.getLengthInSamples();
return read;
}
public boolean isLooping()
{
return this.looping;
}
}

View File

@ -1,176 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio.al;
import org.joml.Matrix4x3f;
import org.joml.Matrix4x3fc;
import org.joml.Vector3f;
import org.joml.Vector3fc;
import org.lwjgl.openal.*;
import org.lwjgl.system.MemoryUtil;
import org.plutoengine.Pluto;
import org.plutoengine.component.PlutoLocalComponent;
import org.plutoengine.logger.Logger;
import org.plutoengine.logger.SmartSeverity;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
/**
* @author 493msi
*
*/
public class AudioContext extends PlutoLocalComponent
{
private long device = MemoryUtil.NULL;
private long context = MemoryUtil.NULL;
private ALCapabilities capabilities;
private Matrix4x3fc transformation;
AudioContext()
{
this.transformation = new Matrix4x3f();
}
@Override
protected void onMount(ComponentDependencyManager manager)
{
var devicePtr = ALC10.alcOpenDevice((ByteBuffer) null);
if (devicePtr == MemoryUtil.NULL)
{
Logger.log(SmartSeverity.AUDIO_ERROR, "Failed to open the default audio device.");
// No audio device found, but the game should not crash just because we have no audio
return;
}
this.device = devicePtr;
var contextPtr = ALC10.alcCreateContext(devicePtr, (IntBuffer) null);
if (contextPtr == MemoryUtil.NULL)
{
ALC10.alcCloseDevice(devicePtr);
Logger.log(SmartSeverity.AUDIO_ERROR, "Failed to create an OpenAL context.");
// The game should not crash just because we have no audio
return;
}
this.context = contextPtr;
EXTThreadLocalContext.alcSetThreadContext(contextPtr);
ALCCapabilities deviceCaps = ALC.createCapabilities(devicePtr);
var alCapabilities = AL.createCapabilities(deviceCaps);
if (Pluto.DEBUG_MODE)
{
Logger.logf(SmartSeverity.AUDIO, "OpenAL10: %b\n", alCapabilities.OpenAL10);
Logger.logf(SmartSeverity.AUDIO, "OpenAL11: %b\n", alCapabilities.OpenAL11);
Logger.logf(SmartSeverity.AUDIO, "Distance model: %s\n", EnumDistanceModel.getByID(AL11.alGetInteger(AL11.AL_DISTANCE_MODEL)));
}
this.capabilities = alCapabilities;
Logger.log(SmartSeverity.AUDIO_PLUS, "Audio engine started.");
}
public void setTransformation(Matrix4x3fc transformation)
{
this.transformation = transformation;
}
public Vector3fc transform(Vector3fc vector)
{
return this.transformation.transformPosition(vector, new Vector3f());
}
public void setDistanceModel(EnumDistanceModel model)
{
AL10.alDistanceModel(model.getALID());
}
public void setSpeedOfSound(float speedOfSound)
{
AL11.alSpeedOfSound(speedOfSound);
}
public void setSpeed(Vector3fc speed)
{
var tSpeed = this.transformation.transformPosition(speed, new Vector3f());
AL10.alListener3f(AL10.AL_VELOCITY, tSpeed.x(), tSpeed.y(), tSpeed.z());
}
public void setPosition(Vector3f position)
{
var tPosition = this.transformation.transformPosition(position, new Vector3f());
AL10.alListener3f(AL10.AL_POSITION, tPosition.x(), tPosition.y(), tPosition.z());
}
public void setVolume(float volume)
{
AL10.alListenerf(AL10.AL_GAIN, volume);
}
public void setOrientation(Vector3f at, Vector3f up)
{
float[] data = new float[6];
data[0] = at.x;
data[1] = at.y;
data[2] = at.z;
data[3] = up.x;
data[4] = up.y;
data[5] = up.z;
AL10.alListenerfv(AL10.AL_ORIENTATION, data);
}
public boolean isReady()
{
return this.capabilities != null;
}
@Override
protected void onUnmount()
{
Logger.log(SmartSeverity.AUDIO_MINUS, "Shutting down the audio engine.");
EXTThreadLocalContext.alcSetThreadContext(MemoryUtil.NULL);
ALC10.alcDestroyContext(this.context);
ALC10.alcCloseDevice(this.device);
this.context = MemoryUtil.NULL;
this.device = MemoryUtil.NULL;
this.capabilities = null;
}
@Override
public boolean isUnique()
{
return true;
}
}

View File

@ -1,215 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio.al;
import org.lwjgl.openal.AL10;
import org.lwjgl.openal.SOFTDirectChannels;
import org.lwjgl.system.MemoryUtil;
import org.plutoengine.audio.IAudio;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
abstract class AudioDoubleBufferedSource extends AudioSource
{
private static final int BUFFER_SIZE_PER_CHANNEL = 8192;
private static final int DOUBLE_BUFFER = 2;
protected final int format;
protected final int channels;
protected final int sampleRate;
private final IntBuffer bufferIDs;
protected final Map<Integer, AudioBuffer> buffers;
protected final ShortBuffer pcmTransferBuf;
protected boolean audioBufferDepleted;
protected boolean closed;
protected AudioDoubleBufferedSource(IAudio audio)
{
this.format = switch (audio.getChannels()) {
case 1 -> AL10.AL_FORMAT_MONO16;
case 2 -> AL10.AL_FORMAT_STEREO16;
default -> throw new UnsupportedOperationException("Unsupported number of channels: " + audio.getChannels());
};
this.channels = audio.getChannels();
this.sampleRate = audio.getSampleRate();
int bufferSize = audio.getChannels() * BUFFER_SIZE_PER_CHANNEL;
this.pcmTransferBuf = MemoryUtil.memAllocShort(bufferSize);
this.bufferIDs = MemoryUtil.memCallocInt(DOUBLE_BUFFER);
AL10.alGenBuffers(this.bufferIDs);
this.buffers = IntStream.range(0, this.bufferIDs.limit())
.mapToObj(i -> new AudioBuffer(this.bufferIDs.get(i), this.format, this.sampleRate))
.collect(Collectors.toMap(AudioBuffer::getID, Function.identity(), (l, r) -> l));
AL10.alSourcei(this.id, SOFTDirectChannels.AL_DIRECT_CHANNELS_SOFT, AL10.AL_TRUE);
}
public boolean play()
{
if (this.closed)
return false;
var state = this.getState();
return switch (state)
{
case AL10.AL_PLAYING -> true;
case AL10.AL_PAUSED, AL10.AL_STOPPED -> super.play();
case AL10.AL_INITIAL -> {
this.buffers.values()
.forEach(this::stream);
yield super.play();
}
default -> false; // Unexpected value, just say it didn't play
};
}
private void stream(AudioBuffer buffer)
{
if (this.audioBufferDepleted)
return;
this.fillTransferBuffer();
if (this.audioBufferDepleted)
return;
buffer.writeData(this.pcmTransferBuf);
AL10.alSourceQueueBuffers(this.id, buffer.getID());
}
private void fillTransferBuffer()
{
this.pcmTransferBuf.clear();
int samplesPerChannel = this.getSamples(this.pcmTransferBuf);
if (samplesPerChannel < BUFFER_SIZE_PER_CHANNEL)
{
this.audioBufferDepleted = true;
return;
}
var samples = samplesPerChannel * this.channels;
this.pcmTransferBuf.limit(samples);
}
protected abstract int getSamples(ShortBuffer pcmTransferBuf);
protected List<AudioBuffer> unqueueBuffers()
{
int processed = AL10.alGetSourcei(this.id, AL10.AL_BUFFERS_PROCESSED);
var unqueued = new ArrayList<AudioBuffer>(DOUBLE_BUFFER);
for (int i = 0; i < processed; i++)
{
int bufID = AL10.alSourceUnqueueBuffers(this.id);
var buffer = this.buffers.get(bufID);
unqueued.add(buffer);
}
return unqueued;
}
private int getState()
{
return AL10.alGetSourcei(this.id, AL10.AL_SOURCE_STATE);
}
public boolean update()
{
if (this.isClosed())
return false;
var unqueued = this.unqueueBuffers();
unqueued.forEach(this::stream);
var sourceState = this.getState();
if (sourceState == AL10.AL_STOPPED)
{
if (this.audioBufferDepleted)
return false;
if (unqueued.size() == DOUBLE_BUFFER)
return super.play();
return false;
}
return true;
}
public boolean updateOrClose()
{
boolean shouldClose = !this.update();
if (shouldClose)
this.close();
return shouldClose;
}
public boolean isClosed()
{
return this.closed;
}
@Override
public void close()
{
if (this.isClosed())
return;
this.closed = true;
this.stop();
this.unqueueBuffers();
super.close();
this.buffers.values()
.forEach(AudioBuffer::close);
MemoryUtil.memFree(this.pcmTransferBuf);
}
}

View File

@ -1,112 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio.al;
import org.apache.commons.lang3.tuple.Pair;
import org.joml.Vector3f;
import org.plutoengine.component.AbstractComponent;
import org.plutoengine.component.ComponentToken;
import org.plutoengine.component.PlutoLocalComponent;
import java.util.ArrayList;
import java.util.List;
public class AudioEngine extends PlutoLocalComponent
{
public static final ComponentToken<AudioEngine> TOKEN = ComponentToken.create(AudioEngine::new);
private AudioContext context;
private final List<Pair<AudioClipSource, AudioSourceInfo>> sfx;
private AudioEngine()
{
this.sfx = new ArrayList<>();
}
@Override
protected void onMount(AbstractComponent<PlutoLocalComponent>.ComponentDependencyManager manager)
{
this.context = manager.declareDependency(ComponentToken.create(AudioContext::new));
}
public void update()
{
for (var iterator = this.sfx.listIterator(); iterator.hasNext(); )
{
var data = iterator.next();
var source = data.getKey();
var info = data.getValue();
var kaFunc = info.keepAliveFunction();
if (kaFunc != null && !kaFunc.getAsBoolean())
source.close();
var moveFunc = info.moveFunction();
if (!source.isClosed() && moveFunc != null)
{
var prevPos = source.getPosition();
var newPos = moveFunc.apply(prevPos);
var velocity = newPos.sub(prevPos, new Vector3f());
source.position(this.context, newPos);
source.velocity(this.context, velocity);
}
if (source.updateOrClose())
iterator.remove();
}
}
public void playSound(SoundEffect sfx)
{
var soundEffect = new AudioClipSource(sfx.getClip());
soundEffect.volume(sfx.getVolume());
soundEffect.pitch(sfx.getPitch());
soundEffect.position(this.context, sfx.getPosition());
soundEffect.play();
var info = new AudioSourceInfo(sfx.getMovementMapper(), sfx.getKeepAliveFunction());
var data = Pair.of(soundEffect, info);
this.sfx.add(data);
}
@Override
protected void onUnmount()
{
}
@Override
public boolean isUnique()
{
return true;
}
public AudioContext getContext()
{
return this.context;
}
}

View File

@ -1,97 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio.al;
import org.jetbrains.annotations.MustBeInvokedByOverriders;
import org.joml.Vector3fc;
import org.lwjgl.openal.AL10;
public abstract class AudioSource implements AutoCloseable
{
protected final int id;
protected Vector3fc position;
protected AudioSource()
{
this.id = AL10.alGenSources();
}
@MustBeInvokedByOverriders
public boolean play()
{
AL10.alSourcePlay(this.id);
return true;
}
@MustBeInvokedByOverriders
public void pause()
{
AL10.alSourcePause(this.id);
}
@MustBeInvokedByOverriders
public void stop()
{
AL10.alSourceStop(this.id);
}
@MustBeInvokedByOverriders
public void close()
{
AL10.alDeleteSources(this.id);
}
@MustBeInvokedByOverriders
public void position(AudioContext context, Vector3fc pos)
{
this.position = pos;
var tPos = context.transform(pos);
AL10.alSource3f(this.id, AL10.AL_POSITION, tPos.x(), tPos.y(), tPos.z());
}
public Vector3fc getPosition()
{
return this.position;
}
@MustBeInvokedByOverriders
public void velocity(AudioContext context, Vector3fc velocity)
{
var tVelocity = context.transform(velocity);
AL10.alSource3f(this.id, AL10.AL_VELOCITY, tVelocity.x(), tVelocity.y(), tVelocity.z());
}
@MustBeInvokedByOverriders
public void pitch(float f)
{
AL10.alSourcef(this.id, AL10.AL_PITCH, f);
}
@MustBeInvokedByOverriders
public void volume(float f)
{
AL10.alSourcef(this.id, AL10.AL_GAIN, f);
}
}

View File

@ -1,37 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio.al;
import org.joml.Vector3fc;
import java.util.function.BooleanSupplier;
import java.util.function.UnaryOperator;
public record AudioSourceInfo(
UnaryOperator<Vector3fc> moveFunction,
BooleanSupplier keepAliveFunction
)
{
}

View File

@ -1,54 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio.al;
import org.plutoengine.audio.ISeekableTrack;
import java.nio.ShortBuffer;
public class AudioTrackSource extends AudioDoubleBufferedSource
{
private final ISeekableTrack track;
public AudioTrackSource(ISeekableTrack track)
{
super(track);
this.track = track;
}
public boolean play()
{
this.track.rewind();
return super.play();
}
@Override
protected int getSamples(ShortBuffer pcmTransferBuf)
{
return this.track.getSamples(pcmTransferBuf);
}
}

View File

@ -1,58 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio.al;
import org.lwjgl.openal.AL11;
import java.util.Arrays;
public enum EnumDistanceModel implements IOpenALEnum
{
NONE(AL11.AL_NONE),
INVERSE_DISTANCE(AL11.AL_INVERSE_DISTANCE),
INVERSE_DISTANCE_CLAMPED(AL11.AL_INVERSE_DISTANCE_CLAMPED),
LINEAR_DISTANCE(AL11.AL_LINEAR_DISTANCE),
LINEAR_DISTANCE_CLAMPED(AL11.AL_LINEAR_DISTANCE_CLAMPED),
EXPONENT_DISTANCE(AL11.AL_EXPONENT_DISTANCE),
EXPONENT_DISTANCE_CLAMPED(AL11.AL_EXPONENT_DISTANCE_CLAMPED);
private final int alID;
EnumDistanceModel(int alID)
{
this.alID = alID;
}
public static EnumDistanceModel getByID(int id)
{
return Arrays.stream(EnumDistanceModel.values()).filter(model -> model.getALID() == id).findAny().orElse(null);
}
@Override
public int getALID()
{
return this.alID;
}
}

View File

@ -1,30 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio.al;
public interface IOpenALEnum
{
int getALID();
}

View File

@ -1,110 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio.al;
import org.jetbrains.annotations.NotNull;
import org.joml.Vector3fc;
import org.plutoengine.audio.RandomAccessClip;
import java.util.function.BooleanSupplier;
import java.util.function.UnaryOperator;
public class SoundEffect
{
private final @NotNull RandomAccessClip clip;
private @NotNull Vector3fc position;
private float volume;
private float pitch;
private UnaryOperator<Vector3fc> movementMapper;
private BooleanSupplier keepAliveFunction;
public SoundEffect(@NotNull RandomAccessClip soundEffect, @NotNull Vector3fc position, float volume)
{
this.clip = soundEffect;
this.position = position;
this.volume = volume;
this.pitch = 1.0f;
}
public SoundEffect position(Vector3fc position)
{
this.position = position;
return this;
}
public SoundEffect volume(float volume)
{
this.volume = volume;
return this;
}
public SoundEffect pitch(float pitch)
{
this.pitch = pitch;
return this;
}
public SoundEffect movementMapper(UnaryOperator<Vector3fc> movementMapper)
{
this.movementMapper = movementMapper;
return this;
}
public SoundEffect keepAliveFunction(BooleanSupplier keepAliveFunction)
{
this.keepAliveFunction = keepAliveFunction;
return this;
}
@NotNull RandomAccessClip getClip()
{
return this.clip;
}
@NotNull Vector3fc getPosition()
{
return this.position;
}
float getVolume()
{
return this.volume;
}
float getPitch()
{
return this.pitch;
}
UnaryOperator<Vector3fc> getMovementMapper()
{
return this.movementMapper;
}
BooleanSupplier getKeepAliveFunction()
{
return this.keepAliveFunction;
}
}

View File

@ -1,49 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.audio.util;
import org.lwjgl.stb.STBVorbis;
import org.lwjgl.stb.STBVorbisInfo;
import org.plutoengine.logger.Logger;
import org.plutoengine.logger.SmartSeverity;
public class AudioUtil
{
public static void printInfo(long handle, STBVorbisInfo info)
{
Logger.log(SmartSeverity.AUDIO, "stream length, samples: " + STBVorbis.stb_vorbis_stream_length_in_samples(handle));
Logger.log(SmartSeverity.AUDIO, "stream length, seconds: " + STBVorbis.stb_vorbis_stream_length_in_seconds(handle));
Logger.log(SmartSeverity.AUDIO);
Logger.log(SmartSeverity.AUDIO, "channels = " + info.channels());
Logger.log(SmartSeverity.AUDIO, "sampleRate = " + info.sample_rate());
Logger.log(SmartSeverity.AUDIO, "maxFrameSize = " + info.max_frame_size());
Logger.log(SmartSeverity.AUDIO, "setupMemoryRequired = " + info.setup_memory_required());
Logger.log(SmartSeverity.AUDIO, "setupTempMemoryRequired() = " + info.setup_temp_memory_required());
Logger.log(SmartSeverity.AUDIO, "tempMemoryRequired = " + info.temp_memory_required());
}
}

View File

@ -1,14 +0,0 @@
plugins {
java
`java-library`
}
description = "A module acting as glue for all PlutoEngine components."
dependencies {
api("org.jetbrains", "annotations", "23.0.0")
implementation("org.apache.commons", "commons-lang3", "3.12.0")
implementation("org.apache.commons", "commons-collections4", "4.4")
}

View File

@ -1,124 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.component;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;
public abstract class AbstractComponent<T extends AbstractComponent<? super T>>
{
private static final AtomicLong ID_SOURCE = new AtomicLong();
private final long id;
private ComponentDependencyManager manager;
protected AbstractComponent()
{
this.id = ID_SOURCE.getAndIncrement();
}
public long getID()
{
return this.id;
}
/**
* Denotes whether this component should be unique.
* Unique components can only exist once per instance
* in a given {@link ComponentManager}.
*
* @return whether this component should be unique
*/
public abstract boolean isUnique();
void initialize(ComponentManager<? super T> manager) throws Exception
{
this.manager = this.new ComponentDependencyManager(manager);
onMount(this.manager);
}
protected void onMount(ComponentDependencyManager manager) throws Exception
{
}
void destroy(ComponentManager<? super T> manager) throws Exception
{
if (this.manager.dependencies != null)
{
this.manager.dependencies.forEach(manager::removeComponent);
this.manager.dependencies.clear();
}
this.onUnmount();
}
protected void onUnmount() throws Exception
{
}
@Override
public boolean equals(Object o)
{
if (this == o) return true;
if (o == null || this.getClass() != o.getClass()) return false;
AbstractComponent<?> that = (AbstractComponent<?>) o;
return this.id == that.id;
}
@Override
public int hashCode()
{
return Objects.hash(this.id);
}
public class ComponentDependencyManager
{
private final ComponentManager<? super T> manager;
private Deque<T> dependencies;
private ComponentDependencyManager(ComponentManager<? super T> componentManager)
{
this.manager = componentManager;
}
public <R extends T> R declareDependency(ComponentToken<R> token)
{
if (this.dependencies == null)
this.dependencies = new ArrayDeque<>();
var dependency = this.manager.addComponent(token);
this.dependencies.push(dependency);
return dependency;
}
}
}

View File

@ -1,170 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.component;
import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
import org.apache.commons.collections4.multimap.HashSetValuedHashMap;
import org.apache.commons.lang3.ClassUtils;
import org.jetbrains.annotations.MustBeInvokedByOverriders;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.stream.Stream;
public class ComponentManager<R extends AbstractComponent<R>>
{
private final Class<R> base;
protected final MultiValuedMap<ComponentToken<?>, R> components;
protected final Map<R, ComponentToken<?>> tokens;
protected final MultiValuedMap<Class<?>, R> implementationProviders;
protected final MultiValuedMap<R, Class<?>> implementationReceivers;
public ComponentManager(@NotNull Class<R> base)
{
this.base = base;
this.components = new HashSetValuedHashMap<>();
this.tokens = new HashMap<>();
this.implementationProviders = new HashSetValuedHashMap<>();
this.implementationReceivers = new ArrayListValuedHashMap<>();
}
public <T extends R> T addComponent(@NotNull ComponentToken<T> token)
{
T component = token.createInstance();
var clazz = component.getClass();
if (component.isUnique() && this.implementationProviders.containsKey(clazz))
throw new IllegalArgumentException("Cannot have two components of the same class '%s'".formatted(clazz.getCanonicalName()));
var superclasses = ClassUtils.getAllSuperclasses(clazz);
for (var superclass : superclasses)
{
if (superclass.isAssignableFrom(AbstractComponent.class))
continue;
this.implementationProviders.put(superclass, component);
this.implementationReceivers.put(component, superclass);
}
this.implementationProviders.put(clazz, component);
this.components.put(token, component);
this.tokens.put(component, token);
this.onComponentAdded(component);
return component;
}
@MustBeInvokedByOverriders
protected void onComponentAdded(R component)
{
try
{
component.initialize(this);
}
catch (Exception e)
{
throw new RuntimeException("An exception has occured while mounting the component", e);
}
}
public Class<R> getComponentBase()
{
return this.base;
}
public <T extends R> Stream<T> streamComponents(@NotNull Class<T> componentClazz)
{
var providers = this.implementationProviders.get(componentClazz);
return providers.stream().map(componentClazz::cast);
}
public <T extends R> T getComponent(@NotNull Class<T> componentClazz) throws NoSuchElementException
{
return this.streamComponents(componentClazz)
.findAny()
.orElseThrow();
}
public <T extends R> T getComponent(@NotNull Class<T> componentClazz, @NotNull Comparator<T> heuristic) throws NoSuchElementException
{
return this.streamComponents(componentClazz)
.max(heuristic)
.orElseThrow();
}
public <T extends R> List<T> getComponents(@NotNull Class<T> componentClazz)
{
return this.streamComponents(componentClazz).toList();
}
public void removeComponent(@NotNull R component) throws IllegalArgumentException
{
var token = this.tokens.remove(component);
if (token == null)
throw new IllegalArgumentException("Component to token mapping could not be found: %d -> ???".formatted(component.getID()));
this.components.removeMapping(token, component);
var classes = this.implementationReceivers.remove(component);
classes.forEach(clazz -> this.implementationProviders.removeMapping(clazz, component));
this.onComponentRemoved(component);
}
@MustBeInvokedByOverriders
protected void onComponentRemoved(R component)
{
try
{
component.destroy(this);
}
catch (Exception e)
{
throw new RuntimeException("An exception has occured whiile unmounting the component", e);
}
}
public <T extends R> void removeComponents(@NotNull ComponentToken<T> componentToken)
{
var activeComponents = this.components.remove(componentToken);
activeComponents.forEach(component -> {
this.tokens.remove(component);
var classes = this.implementationReceivers.remove(component);
classes.forEach(clazz -> this.implementationProviders.removeMapping(clazz, component));
this.onComponentRemoved(component);
});
}
}

View File

@ -1,75 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.component;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Supplier;
public final class ComponentToken<T extends AbstractComponent<? super T>>
{
private static final AtomicLong ID_SOURCE = new AtomicLong();
private final long id;
private final Supplier<T> supplier;
private ComponentToken(Supplier<T> valueSupplier)
{
this.id = ID_SOURCE.getAndIncrement();
this.supplier = valueSupplier;
}
public static <G extends AbstractComponent<? super G>> ComponentToken<G> create(@NotNull Supplier<G> valueSupplier)
{
return new ComponentToken<>(valueSupplier);
}
public T createInstance()
{
return this.supplier.get();
}
public long getID()
{
return this.id;
}
@Override
public boolean equals(Object o)
{
if (this == o) return true;
if (o == null || this.getClass() != o.getClass()) return false;
ComponentToken<?> that = (ComponentToken<?>) o;
return this.id == that.id;
}
@Override
public int hashCode()
{
return Objects.hash(this.id);
}
}

View File

@ -1,11 +0,0 @@
plugins {
java
`java-library`
}
description = "The foundation module for games and apps built on top of PlutoEngine."
dependencies {
api(project(":plutoengine:plutogui"))
api(project(":plutoengine:plutoaudio"))
}

View File

@ -1,67 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.input;
import org.plutoengine.component.ComponentToken;
import org.plutoengine.component.PlutoLocalComponent;
import org.plutoengine.display.Display;
public class InputBus extends PlutoLocalComponent
{
public static ComponentToken<InputBus> fromDisplay(Display display)
{
return ComponentToken.create(() -> new InputBus(display));
}
private final Display display;
private Keyboard keyboard;
private Mouse mouse;
private InputBus(Display display)
{
this.display = display;
}
@Override
protected void onMount(ComponentDependencyManager manager)
{
this.keyboard = manager.declareDependency(ComponentToken.create(() -> new Keyboard(this.display.getWindowPointer())));
this.mouse = manager.declareDependency(ComponentToken.create(() -> new Mouse(this.display.getWindowPointer())));
}
public void resetStates()
{
this.keyboard.resetStates();
this.mouse.resetStates();
}
@Override
public boolean isUnique()
{
return true;
}
}

View File

@ -1,102 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.input;
import org.lwjgl.glfw.GLFW;
import org.plutoengine.component.PlutoLocalComponent;
import org.plutoengine.input.callback.KeyboardCharInput;
import org.plutoengine.input.callback.KeyboardInputCallback;
public class Keyboard extends PlutoLocalComponent
{
private final KeyboardInputCallback keyboard = new KeyboardInputCallback();
private final KeyboardCharInput charInput = new KeyboardCharInput();
private final long windowPointer;
Keyboard(long windowPointer)
{
this.windowPointer = windowPointer;
}
public KeyboardInputCallback keyboard()
{
return this.keyboard;
}
public KeyboardCharInput charInput()
{
return this.charInput;
}
void resetStates()
{
this.keyboard.resetPressed();
this.charInput.reset();
}
@Override
protected void onMount(ComponentDependencyManager manager)
{
GLFW.glfwSetKeyCallback(this.windowPointer, this.keyboard);
GLFW.glfwSetCharCallback(this.windowPointer, this.charInput);
}
@Override
protected void onUnmount() throws Exception
{
GLFW.glfwSetKeyCallback(this.windowPointer, null);
GLFW.glfwSetCharCallback(this.windowPointer, null);
this.keyboard.free();
this.charInput.free();
}
public boolean pressed(int key)
{
return this.keyboard.hasBeenPressed(key);
}
public boolean released(int key)
{
return this.keyboard.hasBeenReleased(key);
}
public boolean isKeyDown(int key)
{
return this.keyboard.isKeyDown(key);
}
public String getTypedText()
{
return this.charInput.getTypedText();
}
@Override
public boolean isUnique()
{
return false;
}
}

View File

@ -1,143 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.input;
import org.lwjgl.glfw.GLFW;
import org.plutoengine.component.PlutoLocalComponent;
import org.plutoengine.input.callback.CursorPositionCallback;
import org.plutoengine.input.callback.MouseButtonCallback;
import org.plutoengine.input.callback.ScrollInputCallback;
public class Mouse extends PlutoLocalComponent
{
private final MouseButtonCallback mouseButton = new MouseButtonCallback();
private final CursorPositionCallback cursorPosition = new CursorPositionCallback();
private final ScrollInputCallback scroll = new ScrollInputCallback();
private final long windowPointer;
Mouse(long windowPointer)
{
this.windowPointer = windowPointer;
}
public MouseButtonCallback mouseButtons()
{
return this.mouseButton;
}
public ScrollInputCallback scroll()
{
return this.scroll;
}
public CursorPositionCallback cursorPosition()
{
return this.cursorPosition;
}
void resetStates()
{
this.mouseButton.reset();
this.scroll.reset();
this.cursorPosition.reset();
}
@Override
protected void onMount(ComponentDependencyManager manager)
{
GLFW.glfwSetMouseButtonCallback(this.windowPointer, this.mouseButton);
GLFW.glfwSetCursorPosCallback(this.windowPointer, this.cursorPosition);
GLFW.glfwSetScrollCallback(this.windowPointer, this.scroll);
}
@Override
protected void onUnmount() throws Exception
{
GLFW.glfwSetMouseButtonCallback(this.windowPointer, null);
GLFW.glfwSetCursorPosCallback(this.windowPointer, null);
GLFW.glfwSetScrollCallback(this.windowPointer, null);
this.mouseButton.free();
this.cursorPosition.free();
this.scroll.free();
}
public boolean clicked(int button)
{
return this.mouseButton.buttonClicked[button];
}
public boolean released(int button)
{
return this.mouseButton.buttonReleased[button];
}
public boolean isButtonDown(int button)
{
return this.mouseButton.buttonDown[button];
}
public double getX()
{
return this.cursorPosition.getX();
}
public double getY()
{
return this.cursorPosition.getY();
}
public boolean isInside(int x1, int y1, int x2, int y2)
{
return this.cursorPosition.isInside(x1, y1, x2, y2);
}
public double getDX()
{
return this.cursorPosition.getDeltaX();
}
public double getDY()
{
return this.cursorPosition.getDeltaY();
}
public double getScrollX()
{
return this.scroll.getXScroll();
}
public double getScrollY()
{
return this.scroll.getYScroll();
}
@Override
public boolean isUnique()
{
return false;
}
}

View File

@ -1,77 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.input.callback;
import org.lwjgl.glfw.GLFWCursorPosCallback;
public class CursorPositionCallback extends GLFWCursorPosCallback
{
private double posX;
private double posY;
private double deltaX;
private double deltaY;
@Override
public void invoke(long window, double xpos, double ypos)
{
this.deltaX = this.posX - xpos;
this.deltaY = this.posY - ypos;
this.posX = xpos;
this.posY = ypos;
}
public void reset()
{
this.deltaX = 0;
this.deltaY = 0;
}
public double getX()
{
return this.posX;
}
public double getY()
{
return this.posY;
}
public double getDeltaX()
{
return this.deltaX;
}
public double getDeltaY()
{
return this.deltaY;
}
public boolean isInside(int x, int y, int x2, int y2)
{
return this.getX() > x && this.getX() < x2 && this.getY() > y && this.getY() < y2;
}
}

View File

@ -1,49 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.input.callback;
import org.lwjgl.glfw.GLFWCharCallback;
public class KeyboardCharInput extends GLFWCharCallback
{
private final StringBuilder typedText = new StringBuilder();
@Override
public void invoke(long window, int codepoint)
{
this.typedText.appendCodePoint(codepoint);
}
public String getTypedText()
{
return this.typedText.toString();
}
public void reset()
{
this.typedText.setLength(0);
}
}

View File

@ -1,82 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.input.callback;
import org.lwjgl.glfw.GLFWKeyCallback;
import java.util.HashSet;
import java.util.Set;
import static org.lwjgl.glfw.GLFW.GLFW_PRESS;
import static org.lwjgl.glfw.GLFW.GLFW_RELEASE;
public class KeyboardInputCallback extends GLFWKeyCallback
{
private final Set<Integer> keyPressed = new HashSet<>();
private final Set<Integer> keyDown = new HashSet<>();
private final Set<Integer> keyReleased = new HashSet<>();
@Override
public void invoke(long window, int key, int scancode, int action, int mods)
{
if (key < 0)
{
return;
}
if (action == GLFW_PRESS)
{
this.keyDown.add(key);
this.keyPressed.add(key);
}
if (action == GLFW_RELEASE)
{
this.keyDown.remove(key);
this.keyReleased.add(key);
}
}
public void resetPressed()
{
this.keyPressed.clear();
this.keyReleased.clear();
}
public boolean hasBeenPressed(int key)
{
return this.keyPressed.contains(key);
}
public boolean hasBeenReleased(int key)
{
return this.keyReleased.contains(key);
}
public boolean isKeyDown(int key)
{
return this.keyDown.contains(key);
}
}

View File

@ -1,52 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.input.callback;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWMouseButtonCallback;
import java.util.Arrays;
public class MouseButtonCallback extends GLFWMouseButtonCallback
{
public boolean[] buttonClicked = new boolean[32];
public boolean[] buttonDown = new boolean[32];
public boolean[] buttonReleased = new boolean[32];
@Override
public void invoke(long window, int button, int action, int mods)
{
this.buttonClicked[button] = action == GLFW.GLFW_PRESS;
this.buttonDown[button] = action != GLFW.GLFW_RELEASE;
this.buttonReleased[button] = action == GLFW.GLFW_RELEASE;
}
public void reset()
{
Arrays.fill(this.buttonClicked, false);
Arrays.fill(this.buttonReleased, false);
}
}

View File

@ -1,60 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.input.callback;
import org.lwjgl.glfw.GLFWScrollCallback;
/**
* @author 493msi
*
*/
public class ScrollInputCallback extends GLFWScrollCallback
{
private double xScroll;
private double yScroll;
@Override
public void invoke(long window, double xoffset, double yoffset)
{
xScroll = xoffset;
yScroll = yoffset;
}
public void reset()
{
xScroll = 0;
yScroll = 0;
}
public double getYScroll()
{
return yScroll;
}
public double getXScroll()
{
return xScroll;
}
}

View File

@ -1,27 +0,0 @@
import org.plutoengine.Versions
plugins {
java
`java-library`
}
description = ""
dependencies {
api(project(":plutoengine:plutoruntime"))
api("org.lwjgl", "lwjgl")
api("org.lwjgl", "lwjgl-glfw")
api("org.lwjgl", "lwjgl-opengl")
api("org.lwjgl", "lwjgl-stb")
org.plutoengine.Versions.lwjglNatives.forEach {
runtimeOnly("org.lwjgl", "lwjgl", classifier = it)
runtimeOnly("org.lwjgl", "lwjgl-glfw", classifier = it)
runtimeOnly("org.lwjgl", "lwjgl-opengl", classifier = it)
runtimeOnly("org.lwjgl", "lwjgl-stb", classifier = it)
}
api("com.code-disaster.steamworks4j", "steamworks4j", Versions.steamworks4jVersion)
api("com.code-disaster.steamworks4j", "steamworks4j-server", Versions.steamworks4jServerVersion)
}

View File

@ -1,35 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine;
import org.lwjgl.glfw.GLFW;
import org.plutoengine.mod.ModEntry;
@ModEntry(modID = "glfw", version = ModGLFW.VERSION, dependencies = ModLWJGL.class)
public class ModGLFW
{
public static final String VERSION = GLFW.GLFW_VERSION_MAJOR + "." + GLFW.GLFW_VERSION_MINOR + "." + GLFW.GLFW_VERSION_REVISION;
}

View File

@ -1,36 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine;
import org.lwjgl.Version;
import org.plutoengine.mod.ModEntry;
@ModEntry(modID = "lwjgl",
version = ModLWJGL.version)
public class ModLWJGL
{
public static final String version = Version.VERSION_MAJOR + "." + Version.VERSION_MINOR + "." + Version.VERSION_REVISION;
}

View File

@ -1,31 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Utilities for better native buffer handling.
*
* @author 493msi
*
*/
package org.plutoengine.buffer;

View File

@ -1,253 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.display;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
import org.lwjgl.system.MemoryUtil;
import org.plutoengine.Pluto;
import org.plutoengine.annotation.ThreadSensitive;
import org.plutoengine.component.PlutoLocalComponent;
import org.plutoengine.gl.GLDebugInfo;
import org.plutoengine.logger.Logger;
import org.plutoengine.logger.SmartSeverity;
/**
* A wrapper class to provide abstraction over GLFW windows.
*
* @author 493msi
* @since 0.2
*/
@ThreadSensitive(localContexts = true)
public class Display extends PlutoLocalComponent
{
int width;
int height;
boolean debugMode;
boolean coreProfile = true;
private String name = Pluto.ENGINE_NAME;
private boolean wasResized;
private boolean openGLContext;
private long windowPointer;
private final GLFWErrorCallbackI glfwErrorCallback;
private GLFWWindowSizeCallbackI resizeCallback;
private GLDebugMessageARBCallbackI glDebugCallback;
Display()
{
this.windowPointer = MemoryUtil.NULL;
this.glfwErrorCallback = (int error, long description) -> {
Logger.logf(SmartSeverity.ERROR, "GLFW Error code %d:\n", error);
Logger.logf(GLFWErrorCallback.getDescription(description));
};
GLFW.glfwSetErrorCallback(this.glfwErrorCallback);
}
public void create()
{
GLFW.glfwWindowHint(GLFW.GLFW_STENCIL_BITS, 4);
this.windowPointer = GLFW.glfwCreateWindow(this.width, this.height, this.name, MemoryUtil.NULL, MemoryUtil.NULL);
if (this.windowPointer == MemoryUtil.NULL)
{
this.destroy();
throw new IllegalStateException("Failed to create a window...");
}
var vidmode = GLFW.glfwGetVideoMode(GLFW.glfwGetPrimaryMonitor());
if (vidmode == null)
{
this.destroy();
throw new IllegalStateException("Failed to detect the primary monitor.");
}
GLFW.glfwSetWindowPos(this.windowPointer, (vidmode.width() - this.width) / 2, (vidmode.height() - this.height) / 2);
GLFW.glfwMakeContextCurrent(this.windowPointer);
this.resizeCallback = (long window, int width, int height) -> {
if (width > 0 && height > 0)
{
if (this.debugMode)
{
Logger.logf(SmartSeverity.INFO, "Resized to %dx%d.\n", width, height);
}
this.width = width;
this.height = height;
this.wasResized = true;
if (this.openGLContext)
{
GL33.glViewport(0, 0, this.width, this.height);
}
}
};
GLFW.glfwSetWindowSizeCallback(this.windowPointer, this.resizeCallback);
}
public void setName(String newName)
{
this.name = newName;
if (this.windowPointer != MemoryUtil.NULL)
GLFW.glfwSetWindowTitle(this.windowPointer, this.name);
}
public void show()
{
GLFW.glfwShowWindow(this.windowPointer);
}
public void setWindowSizeLimits(int minWidth, int minHeight, int maxWidth, int maxHeight)
{
GLFW.glfwSetWindowSizeLimits(this.windowPointer, minWidth, minHeight, maxWidth, maxHeight);
}
public void setIcons(GLFWImage.Buffer iconBuffer)
{
GLFW.glfwSetWindowIcon(this.windowPointer, iconBuffer);
iconBuffer.flip();
iconBuffer.forEach(GLFWImage::free);
iconBuffer.free();
}
public void setShouldClose(boolean shouldClose)
{
GLFW.glfwSetWindowShouldClose(this.windowPointer, shouldClose);
}
public void maximize()
{
GLFW.glfwMaximizeWindow(this.windowPointer);
}
public void lockSwapInterval(int interval)
{
GLFW.glfwSwapInterval(interval);
}
public void swapBuffers()
{
GLFW.glfwSwapBuffers(this.windowPointer);
Framerate.tick();
}
public boolean isClosing()
{
return GLFW.glfwWindowShouldClose(this.windowPointer);
}
public void pollEvents()
{
this.wasResized = false;
GLFW.glfwPollEvents();
}
public void destroy()
{
if (this.glfwErrorCallback instanceof GLFWErrorCallback glfwErrorCallback)
{
glfwErrorCallback.free();
}
if (this.glDebugCallback instanceof GLDebugMessageARBCallback glDebugMessageARBCallback)
{
glDebugMessageARBCallback.free();
}
if (this.resizeCallback instanceof GLFWWindowSizeCallback windowSizeCallback)
{
windowSizeCallback.free();
}
if (this.windowPointer != MemoryUtil.NULL)
{
GLFW.glfwDestroyWindow(this.windowPointer);
}
}
public int getHeight()
{
return this.height;
}
public int getWidth()
{
return this.width;
}
public long getWindowPointer()
{
return this.windowPointer;
}
public boolean wasResized()
{
return this.wasResized;
}
public void createOpenGLCapabilities()
{
var glCapabilities = GL.createCapabilities(this.coreProfile);
GLDebugInfo.printDebugInfo(glCapabilities);
if (this.debugMode)
{
this.glDebugCallback = (int source, int type, int id, int severity, int length, long messagePtr, long userParam) -> {
var message = GLDebugMessageARBCallback.getMessage(length, messagePtr);
Logger.log(SmartSeverity.WARNING, message);
};
ARBDebugOutput.glDebugMessageCallbackARB(this.glDebugCallback, MemoryUtil.NULL);
}
GL33.glEnable(GL33.GL_CULL_FACE);
GL33.glCullFace(GL33.GL_BACK);
this.openGLContext = true;
}
@Override
public boolean isUnique()
{
return true;
}
}

View File

@ -1,109 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.display;
import java.util.Deque;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
/**
* @author 493msi
*
*/
public class Framerate
{
private static long lastDraw = 0;
private static double frameTime = Double.NaN;
private static double animationTimer = 0;
private static double fps = Double.NaN;
private static int interpolatedFPS;
private static boolean firstRemoved = false;
private static final Deque<Long> drawTimestamps = new LinkedBlockingDeque<>();
public static double getFrameTime()
{
return frameTime;
}
public static double getFPS()
{
return fps;
}
public static int getInterpolatedFPS()
{
return interpolatedFPS;
}
public static float getAnimationTimer()
{
return (float) animationTimer;
}
public static void tick()
{
var now = System.nanoTime();
if (lastDraw > 0)
{
var frameTimeNs = now - lastDraw;
frameTime = frameTimeNs / (double) TimeUnit.MILLISECONDS.toNanos(1);
animationTimer += frameTimeNs / (double) TimeUnit.SECONDS.toNanos(1);
// Maintain precision in case the engine runs for many hours
animationTimer %= TimeUnit.DAYS.toMinutes(1);
fps = TimeUnit.SECONDS.toMillis(1) / frameTime;
}
var nowMs = System.currentTimeMillis();
drawTimestamps.add(nowMs);
Long oldestDraw;
long oneSecondAgo = nowMs - 1000;
while ((oldestDraw = drawTimestamps.peek()) != null && oldestDraw < oneSecondAgo)
{
drawTimestamps.remove();
firstRemoved = true;
}
if (firstRemoved)
{
interpolatedFPS = drawTimestamps.size();
}
else
{
interpolatedFPS = (int) Math.round(fps);
}
lastDraw = now;
}
}

View File

@ -1,31 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Utilities for display handling.
*
* @author 493msi
*
*/
package org.plutoengine.display;

View File

@ -1,57 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.math;
import org.joml.Matrix3x2f;
/**
* A class with factory methods for the most used view transformations.
*
* @author 493msi
* @since 0.3
*/
public class ViewMatrix
{
/**
* Create a 2D view matrix.
*
* @param x The X camera translation
* @param y The Y camera translation
* @param zoom The zoom
*
* @return the view matrix
*
* @author 493msi
* @since 0.3
*/
public static Matrix3x2f createView(int x, int y, float zoom)
{
var view = new Matrix3x2f();
view.scale(zoom);
view.translate(x, y);
return view;
}
}

View File

@ -1,31 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Math utility classes.
*
* @author 493msi
*
*/
package org.plutoengine.math;

View File

@ -1,22 +0,0 @@
plugins {
java
`java-library`
}
description = ""
dependencies {
api(project(":plutoengine:plutospritesheet"))
api(project(":libra"))
api("io.reactivex.rxjava3", "rxjava", "3.1.4")
implementation("com.fasterxml.jackson.dataformat", "jackson-dataformat-yaml", "2.12.3")
implementation("org.lwjgl", "lwjgl-yoga")
org.plutoengine.Versions.lwjglNatives.forEach {
runtimeOnly("org.lwjgl", "lwjgl-yoga", classifier = it)
}
implementation("org.commonmark", "commonmark", "0.18.1")
}

View File

@ -1,140 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.graphics;
import org.joml.Matrix3f;
import org.joml.primitives.Rectanglef;
import org.plutoengine.graphics.gui.PlutoGUICommandParser;
import org.plutoengine.graphics.gui.font.PlutoFont;
import org.plutoengine.libra.command.LiCommandBuffer;
import org.plutoengine.libra.command.impl.LiCommandSetTransform;
import org.plutoengine.libra.text.LiTextInfo;
import org.plutoengine.libra.text.font.LiFontFamily;
import org.plutoengine.libra.text.shaping.TextShaper;
import org.plutoengine.libra.text.shaping.TextStyleOptions;
import java.util.EnumSet;
public class ImmediateFontRenderer
{
public static <T extends PlutoFont<T>> void drawString(float x, float y, String text, LiFontFamily<T> fontFamily, TextStyleOptions style)
{
var font = style.pickFont(fontFamily);
var shaper = font.getDefaultShaper();
var info = shaper.shape(EnumSet.of(TextShaper.EnumFeature.KERNING), font, text, style);
draw(x, y, info, style);
}
public static <T extends PlutoFont<T>> void drawStringNoKern(float x, float y, String text, LiFontFamily<T> fontFamily, TextStyleOptions style)
{
var font = style.pickFont(fontFamily);
var shaper = font.getDefaultShaper();
var info = shaper.shape(EnumSet.noneOf(TextShaper.EnumFeature.class), font, text, style);
draw(x, y, info, style);
}
public static void draw(float x, float y, LiTextInfo info, TextStyleOptions style)
{
var transformBuf = LiCommandBuffer.uncleared();
var fitBox = style.getFitBox();
var initialScale = style.getSize() / PlutoFont.NORMALIZED_PIXEL_HEIGHT;
var scaleX = initialScale;
var scaleY = initialScale;
var bounds = info.getBoundingBox().scale(scaleX, scaleY, new Rectanglef());
if (fitBox != null)
{
// Rescale in sync in both are set to scale
if (style.getOverflowX() == TextStyleOptions.OverflowXStrategy.SCALE_TO_FIT &&
style.getOverflowY() == TextStyleOptions.OverflowYStrategy.SCALE_TO_FIT)
{
var smaller = Math.min(fitBox.lengthX() / bounds.lengthX(), fitBox.lengthY() / bounds.lengthY());
var rescale = Math.min(1.0f, smaller);
scaleX *= rescale;
bounds.scale(rescale, rescale);
}
else
{
if (style.getOverflowX() == TextStyleOptions.OverflowXStrategy.SCALE_TO_FIT)
{
var rescale = Math.min(1.0f, fitBox.lengthX() / bounds.lengthX());
scaleX *= rescale;
bounds.scale(rescale, 1.0f);
}
if (style.getOverflowY() == TextStyleOptions.OverflowYStrategy.SCALE_TO_FIT)
{
var rescale = Math.min(1.0f, fitBox.lengthY() / bounds.lengthY());
scaleY *= rescale;
bounds.scale(1.0f, rescale);
}
}
x += switch (style.getHorizontalAlign()) {
case START -> fitBox.minX - bounds.minX;
case CENTER -> (fitBox.maxX + fitBox.minX) / 2.0f - bounds.lengthX() / 2.0f;
case END -> fitBox.maxX - bounds.lengthX();
};
y += switch (style.getVerticalAlign()) {
case START -> fitBox.minY - bounds.minY;
case CENTER -> (fitBox.maxY + fitBox.minY) / 2.0f - bounds.lengthY() / 2.0f;
case END -> fitBox.maxY - bounds.lengthY();
};
}
else
{
x += switch (style.getHorizontalAlign()) {
case START -> -bounds.minX;
case CENTER -> -bounds.minX + -bounds.lengthX() / 2.0f;
case END -> -bounds.lengthX();
};
y += switch (style.getVerticalAlign()) {
case START -> -bounds.lengthY();
case CENTER -> -bounds.lengthY() / 2.0f;
case END -> 0;
};
}
transformBuf.push(new LiCommandSetTransform(new Matrix3f().scale(scaleX, scaleY, 1.0f).m20(x).m21(y)));
var buf = info.getDrawCommandBuffer();
var commandParser = new PlutoGUICommandParser();
commandParser.add(LiCommandBuffer.cleared());
commandParser.add(transformBuf);
commandParser.add(buf);
try (var drawCalls = commandParser.parse())
{
drawCalls.render();
}
}
}

View File

@ -1,76 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.graphics;
import org.plutoengine.Pluto;
import org.plutoengine.graphics.gui.BitmapFontShader;
import org.plutoengine.graphics.gui.FontShader;
import org.plutoengine.graphics.texture.MagFilter;
import org.plutoengine.graphics.texture.MinFilter;
import org.plutoengine.graphics.texture.WrapMode;
import org.plutoengine.graphics.texture.texture2d.RectangleTexture;
import org.plutoengine.mod.IModEntryPoint;
import org.plutoengine.mod.Mod;
import org.plutoengine.mod.ModEntry;
import org.plutoengine.graphics.shader.RenderShaderBuilder;
/**
* @author 493msi
*
*/
@ModEntry(modID = PlutoGUIMod.MOD_ID,
dependencies = { PlutoSpriteSheetMod.class },
version = Pluto.VERSION)
public class PlutoGUIMod implements IModEntryPoint
{
public static final String MOD_ID = "tefek.plutogui";
public static Mod instance;
public static RectangleTexture uiElementsAtlas;
public static FontShader fontShader;
public static BitmapFontShader bitmapFontShader;
public void onLoad(Mod mod)
{
instance = mod;
fontShader = new RenderShaderBuilder(mod.getResource("shaders.VertexFontShader#glsl"), mod.getResource("shaders.FragmentFontShader#glsl")).build(FontShader.class, false);
bitmapFontShader = new RenderShaderBuilder(mod.getResource("shaders.VertexBitmapFontShader#glsl"), mod.getResource("shaders.FragmentBitmapFontShader#glsl")).build(BitmapFontShader.class, false);
uiElementsAtlas = new RectangleTexture();
uiElementsAtlas.load(mod.getResource("gui.elements#png"), MagFilter.NEAREST, MinFilter.NEAREST, WrapMode.CLAMP_TO_EDGE, WrapMode.CLAMP_TO_EDGE);
}
public void onUnload()
{
uiElementsAtlas.close();
fontShader.close();
}
}

View File

@ -1,117 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.graphics.gui;
import org.joml.Matrix3fc;
import org.plutoengine.graphics.vao.attrib.ReservedAttributes;
import org.plutoengine.graphics.shader.uniform.*;
import org.plutoengine.libra.paint.LiColorPaint;
import org.plutoengine.libra.paint.LiGradientPaint;
import org.plutoengine.libra.paint.LiPaint;
import org.plutoengine.graphics.shader.ShaderBase;
import org.plutoengine.graphics.shader.ShaderProgram;
import org.plutoengine.graphics.shader.VertexArrayAttribute;
import org.plutoengine.graphics.shader.uniform.auto.AutoViewportProjection;
import org.plutoengine.util.color.IRGBA;
@ShaderProgram
public final class BitmapFontShader extends ShaderBase implements IGUIShader
{
@AutoViewportProjection
@Uniform(name = "projection")
public UniformMat4 projectionMatrix;
@Uniform(name = "transformation")
public UniformMat3 transformationMatrix;
@Uniform
public UniformInt paintType;
@Uniform
public UniformRGBA paintColor;
@Uniform
public UniformInt paintGradientStopCount;
@Uniform
public UniformArrayRGBA paintGradientColors;
@Uniform
public UniformArrayFloat paintGradientPositions;
@Uniform
public UniformArrayVec2 paintGradientEnds;
@VertexArrayAttribute(ReservedAttributes.POSITION)
public int position;
@VertexArrayAttribute(ReservedAttributes.UV)
public int uvCoords;
@VertexArrayAttribute(2)
public int paintUVCoords;
@Override
public void setTransform(Matrix3fc transform)
{
this.transformationMatrix.load(transform);
}
@Override
public void setPaint(LiPaint paint)
{
switch (paint.getType())
{
case SOLID_COLOR -> {
var col = ((LiColorPaint) paint).getColor();
this.paintType.load(0);
this.paintColor.load(col.getFloatComponentsRGBA());
}
case GRADIENT -> {
var gradPaint = (LiGradientPaint) paint;
this.paintType.load(1);
this.paintGradientEnds.load(gradPaint.getStart(), gradPaint.getEnd());
var stops = gradPaint.getStops();
this.paintGradientStopCount.load(stops.length);
var colors = new IRGBA[stops.length];
var positions = new float[stops.length];
int i = 0;
for (var stop : stops)
{
var col = stop.color();
colors[i] = col.getFloatComponentsRGBA();
positions[i] = stop.position();
i++;
}
this.paintGradientColors.load(colors);
this.paintGradientPositions.load(positions);
}
}
}
}

View File

@ -1,129 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.graphics.gui;
import org.joml.Matrix3fc;
import org.plutoengine.graphics.vao.attrib.ReservedAttributes;
import org.plutoengine.graphics.shader.uniform.*;
import org.plutoengine.libra.paint.LiColorPaint;
import org.plutoengine.libra.paint.LiGradientPaint;
import org.plutoengine.libra.paint.LiPaint;
import org.plutoengine.graphics.shader.ShaderBase;
import org.plutoengine.graphics.shader.ShaderProgram;
import org.plutoengine.graphics.shader.VertexArrayAttribute;
import org.plutoengine.graphics.shader.uniform.auto.AutoViewportProjection;
import org.plutoengine.util.color.IRGBA;
@ShaderProgram
public final class FontShader extends ShaderBase implements ISDFTextShader
{
@AutoViewportProjection
@Uniform(name = "projection")
public UniformMat4 projectionMatrix;
@Uniform(name = "transformation")
public UniformMat3 transformationMatrix;
@Uniform
public UniformInt paintType;
@Uniform
public UniformRGBA paintColor;
@Uniform
public UniformInt paintGradientStopCount;
@Uniform
public UniformArrayRGBA paintGradientColors;
@Uniform
public UniformArrayFloat paintGradientPositions;
@Uniform
public UniformArrayVec2 paintGradientEnds;
@Uniform
public UniformFloat pxScale;
@VertexArrayAttribute(ReservedAttributes.POSITION)
public int position;
@VertexArrayAttribute(ReservedAttributes.UV)
public int uvCoords;
@VertexArrayAttribute(2)
public int page;
@VertexArrayAttribute(3)
public int paintUVCoords;
@Override
public void setTransform(Matrix3fc transform)
{
this.transformationMatrix.load(transform);
}
@Override
public void setPaint(LiPaint paint)
{
switch (paint.getType())
{
case SOLID_COLOR -> {
var col = ((LiColorPaint) paint).getColor();
this.paintType.load(0);
this.paintColor.load(col.getFloatComponentsRGBA());
}
case GRADIENT -> {
var gradPaint = (LiGradientPaint) paint;
this.paintType.load(1);
this.paintGradientEnds.load(gradPaint.getStart(), gradPaint.getEnd());
var stops = gradPaint.getStops();
this.paintGradientStopCount.load(stops.length);
var colors = new IRGBA[stops.length];
var positions = new float[stops.length];
int i = 0;
for (var stop : stops)
{
var col = stop.color();
colors[i] = col.getFloatComponentsRGBA();
positions[i] = stop.position();
i++;
}
this.paintGradientColors.load(colors);
this.paintGradientPositions.load(positions);
}
}
}
@Override
public void setPixelScale(float scale)
{
this.pxScale.load(scale);
}
}

View File

@ -1,35 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.graphics.gui;
import org.joml.Matrix3fc;
import org.plutoengine.libra.paint.LiPaint;
public interface IGUIShader
{
void setTransform(Matrix3fc transform);
void setPaint(LiPaint paint);
}

View File

@ -1,30 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.graphics.gui;
public interface ISDFTextShader extends IGUIShader
{
void setPixelScale(float scale);
}

View File

@ -1,168 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.graphics.gui;
import org.plutoengine.graphics.gl.DrawMode;
import org.plutoengine.graphics.vao.VertexArray;
import org.plutoengine.graphics.vao.VertexArrayBuilder;
import org.plutoengine.graphics.gui.command.PlutoCommandDrawMesh;
import org.plutoengine.graphics.gui.command.PlutoCommandDrawMeshDirectBuffer;
import org.plutoengine.graphics.gui.command.PlutoCommandSwitchShader;
import org.plutoengine.graphics.gui.command.PlutoCommandSwitchTexture;
import org.plutoengine.libra.command.AbstractGUICommandParser;
import org.plutoengine.libra.command.IGUIRenderer;
import org.plutoengine.libra.command.LiCommandBuffer;
import org.plutoengine.libra.command.impl.LiCommandSetPaint;
import org.plutoengine.libra.command.impl.LiCommandSetTransform;
import org.plutoengine.libra.command.impl.LiCommandSpecial;
import org.plutoengine.graphics.shader.ShaderBase;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashSet;
public class PlutoGUICommandParser extends AbstractGUICommandParser
{
@Override
protected IGUIRenderer parse(LiCommandBuffer mergedBuffer)
{
var drawCalls = new ArrayList<Runnable>();
var closeCalls = new ArrayDeque<Runnable>();
var alreadyEnabledAttribs = new HashSet<Integer>();
var currentShader = (ShaderBase & IGUIShader) null;
for (var cmd : mergedBuffer)
{
var type = cmd.getType();
switch (type)
{
case DRAW_MESH -> {
if (!(cmd instanceof PlutoCommandDrawMesh drawCmd))
throw new IllegalStateException();
var vab = new VertexArrayBuilder();
var data = drawCmd.getData();
var attrInfo = drawCmd.getAttributeInfo();
data.forEach((attr, val) -> vab.attrib(attr, attrInfo.get(attr).dimensions(), val.flip()));
var indices = drawCmd.getIndices();
if (indices != null)
vab.indices(indices.flip());
var vao = vab.build();
var attribs = vao.getUsedAttributes();
var attribsToEnable = new HashSet<>(attribs);
attribsToEnable.removeAll(alreadyEnabledAttribs);
alreadyEnabledAttribs.addAll(attribsToEnable);
if (drawCmd instanceof PlutoCommandDrawMeshDirectBuffer dBuf)
dBuf.close();
drawCalls.add(() -> {
vao.bind();
attribsToEnable.forEach(VertexArray::enableAttribute);
vao.draw(DrawMode.TRIANGLES);
});
closeCalls.add(vao::close);
}
case SET_TRANSFORM -> {
if (!(cmd instanceof LiCommandSetTransform transformCmd))
throw new IllegalStateException();
var shaderCapture = currentShader;
assert shaderCapture != null;
drawCalls.add(() -> shaderCapture.setTransform(transformCmd.getTransform()));
}
case SET_PAINT -> {
if (!(cmd instanceof LiCommandSetPaint paintCmd))
throw new IllegalStateException();
var shaderCapture = currentShader;
assert shaderCapture != null;
drawCalls.add(() -> shaderCapture.setPaint(paintCmd.getPaint()));
}
case SWITCH_SHADER -> {
if (!(cmd instanceof PlutoCommandSwitchShader swSh))
throw new IllegalStateException();
var shaderCapture = currentShader = (ShaderBase & IGUIShader) swSh.getShader();
assert shaderCapture != null;
drawCalls.add(() -> shaderCapture.start());
}
case SWITCH_TEXTURE -> {
if (!(cmd instanceof PlutoCommandSwitchTexture swTx))
throw new IllegalStateException();
var textureCapture = swTx.getTexture();
assert textureCapture != null;
drawCalls.add(textureCapture::bind);
}
case SPECIAL -> {
if (!(cmd instanceof LiCommandSpecial cSp))
throw new IllegalStateException();
var af = cSp.getAction();
drawCalls.add(() -> af.accept(mergedBuffer));
}
}
}
return new IGUIRenderer()
{
@Override
public void render()
{
drawCalls.forEach(Runnable::run);
}
@Override
public void close()
{
var it = closeCalls.descendingIterator();
while (it.hasNext())
{
var call = it.next();
call.run();
}
}
};
}
}

View File

@ -1,97 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.graphics.gui;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL33;
import org.plutoengine.graphics.texture.MagFilter;
import org.plutoengine.graphics.texture.MinFilter;
import org.plutoengine.graphics.texture.Texture;
import org.plutoengine.graphics.texture.WrapMode;
import org.plutoengine.tpl.ImageLoader;
import org.plutoengine.tpl.ImageY;
import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import java.util.List;
public class SDFTextureArray extends Texture
{
public SDFTextureArray()
{
super(GL33.GL_TEXTURE_2D_ARRAY, 2);
}
@Override
public boolean supportsMipMapping()
{
return false;
}
@Override
public void writeData(long address)
{
GL33.glTexImage3D(GL33.GL_TEXTURE_2D_ARRAY, 0, GL33.GL_R8, this.width, this.height, this.depth, 0, GL33.GL_RED, GL11.GL_UNSIGNED_BYTE, address);
}
public void loadImg(List<BufferedImage> imageData, int width, int height, int depth, MagFilter magFilter, MinFilter minFilter, WrapMode... wrap)
{
var data = imageData.stream()
.map(ImageLoader::loadImageGrayscale)
.map(ImageY::getData)
.toList();
this.load(data, width, height, depth, magFilter, minFilter, wrap);
}
public void load(List<ByteBuffer> imageData, int width, int height, int depth, MagFilter magFilter, MinFilter minFilter, WrapMode... wrap)
{
this.width = width;
this.height = height;
this.depth = imageData.size();
this.bind();
this.setFilteringOptions(magFilter, minFilter);
this.setWrapOptions(wrap);
this.writeData(0);
for (int i = 0; i < imageData.size(); i++)
{
var img = imageData.get(i);
GL33.glTexSubImage3D(GL33.GL_TEXTURE_2D_ARRAY, 0,
0, 0, i,
this.width, this.height, 1,
GL33.GL_RED, GL11.GL_UNSIGNED_BYTE, img);
}
}
@Override
public void load(ByteBuffer imageData, int width, int height, MagFilter magFilter, MinFilter minFilter, WrapMode... wrap)
{
throw new UnsupportedOperationException();
}
}

View File

@ -1,128 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.graphics.gui.command;
import org.plutoengine.graphics.vao.attrib.AttributeInfo;
import org.plutoengine.libra.command.impl.LiCommand;
import org.plutoengine.libra.command.impl.LiCommandDrawMesh;
import java.nio.Buffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;
public abstract sealed class PlutoCommandDrawMesh extends LiCommandDrawMesh permits PlutoCommandDrawMeshDirectBuffer, PlutoCommandDrawMeshHeap
{
protected final Map<Integer, AttributeInfo> attributeInfo;
protected final Map<Integer, Buffer> data;
protected IntBuffer indices;
public PlutoCommandDrawMesh()
{
this.attributeInfo = new TreeMap<>();
this.data = new TreeMap<>();
}
public IntBuffer getIndices()
{
if (this.indices == null)
return null;
return this.indices;
}
public Map<Integer, AttributeInfo> getAttributeInfo()
{
return Collections.unmodifiableMap(this.attributeInfo);
}
public Map<Integer, Buffer> getData()
{
return Collections.unmodifiableMap(this.data);
}
public void addIndices(int[] data)
{
if (data == null)
return;
this.addIndices(IntBuffer.wrap(data));
}
public abstract void addIndices(IntBuffer data);
public void addAttribute(int attrib, float[] data, int dimensions)
{
if (data == null)
return;
this.addAttribute(attrib, FloatBuffer.wrap(data), dimensions);
}
public abstract void addAttribute(int attrib, FloatBuffer data, int dimensions);
public void addAttribute(int attrib, int[] data, int dimensions)
{
if (data == null)
return;
this.addAttribute(attrib, IntBuffer.wrap(data), dimensions);
}
public abstract void addAttribute(int attrib, IntBuffer data, int dimensions);
@Override
public boolean supportsMerge(LiCommand other)
{
if (!(other instanceof PlutoCommandDrawMesh pcdm))
return false;
return this.attributeInfo.equals(pcdm.attributeInfo);
}
@Override
public PlutoCommandDrawMesh merge(LiCommand other)
{
if (!(other instanceof PlutoCommandDrawMesh pcdm))
throw new UnsupportedOperationException();
pcdm.data.forEach((k, v) -> {
var attrInfo = this.attributeInfo.get(k);
switch (attrInfo.type())
{
case FLOAT -> this.addAttribute(k, (FloatBuffer) v, attrInfo.dimensions());
case INT -> this.addAttribute(k, (IntBuffer) v, attrInfo.dimensions());
case UNSIGNED_INT -> throw new UnsupportedOperationException();
}
});
this.addIndices(pcdm.getIndices());
return this;
}
}

View File

@ -1,166 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.graphics.gui.command;
import org.lwjgl.system.MemoryUtil;
import org.plutoengine.graphics.vao.attrib.AttributeInfo;
import org.plutoengine.graphics.vbo.EnumArrayBufferType;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
public final class PlutoCommandDrawMeshDirectBuffer extends PlutoCommandDrawMesh implements AutoCloseable
{
public void addIndices(IntBuffer data)
{
if (data == null)
return;
if (this.indices == null)
{
if (data.isDirect())
{
this.indices = data;
var size = this.indices.remaining();
this.indices.limit(size);
this.indices.position(size);
return;
}
else
{
this.indices = MemoryUtil.memAllocInt(data.remaining());
}
}
if (this.indices.remaining() < data.remaining())
{
var newSize = Math.max(this.indices.capacity() << 1, this.indices.capacity() + data.remaining());
this.indices = MemoryUtil.memRealloc(this.indices, newSize);
}
this.indices.put(data);
if (data.isDirect())
MemoryUtil.memFree(data);
}
public void addAttribute(int attrib, FloatBuffer data, int dimensions)
{
if (data == null)
return;
var meta = this.attributeInfo.computeIfAbsent(attrib, k -> new AttributeInfo(EnumArrayBufferType.FLOAT, attrib, dimensions));
if (meta.dimensions() != dimensions)
throw new IllegalArgumentException("Attribute dimensions mismatch!");
this.data.compute(attrib, (k, v) -> {
if (v == null)
{
if (data.isDirect())
{
var size = data.remaining();
data.limit(size);
data.position(size);
return data;
}
else
{
return MemoryUtil.memAllocFloat(data.remaining()).put(data);
}
}
if (!(v instanceof FloatBuffer fab))
throw new IllegalArgumentException();
if (data.remaining() > fab.remaining())
{
var newSize = Math.max(fab.capacity() << 1, fab.capacity() + data.remaining());
fab = MemoryUtil.memRealloc(fab, newSize);
}
fab.put(data);
if (data.isDirect())
MemoryUtil.memFree(data);
return fab;
});
}
public void addAttribute(int attrib, IntBuffer data, int dimensions)
{
if (data == null)
return;
var meta = this.attributeInfo.computeIfAbsent(attrib, k -> new AttributeInfo(EnumArrayBufferType.INT, attrib, dimensions));
if (meta.dimensions() != dimensions)
throw new IllegalArgumentException("Attribute dimensions mismatch!");
this.data.compute(attrib, (k, v) -> {
if (v == null)
{
if (data.isDirect())
{
var size = data.remaining();
data.limit(size);
data.position(size);
return data;
}
else
{
return MemoryUtil.memAllocInt(data.remaining()).put(data);
}
}
if (!(v instanceof IntBuffer iab))
throw new IllegalArgumentException();
if (data.remaining() > iab.remaining())
{
var newSize = Math.max(iab.capacity() << 1, iab.capacity() + data.remaining());
iab = MemoryUtil.memRealloc(iab, newSize);
}
iab.put(data);
if (data.isDirect())
MemoryUtil.memFree(data);
return iab;
});
}
@Override
public void close()
{
MemoryUtil.memFree(this.indices);
this.data.values()
.forEach(MemoryUtil::memFree);
}
}

View File

@ -1,121 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.graphics.gui.command;
import org.plutoengine.graphics.vao.attrib.AttributeInfo;
import org.plutoengine.graphics.vbo.EnumArrayBufferType;
import org.plutoengine.libra.command.impl.LiCommand;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
public final class PlutoCommandDrawMeshHeap extends PlutoCommandDrawMesh
{
public void addIndices(IntBuffer data)
{
if (data == null)
return;
if (this.indices == null)
this.indices = IntBuffer.allocate(data.remaining());
if (this.indices.remaining() < data.remaining())
this.indices = IntBuffer.allocate(Math.max(this.indices.capacity() << 1, this.indices.capacity() + data.remaining())).put(this.indices.flip());
this.indices.put(data);
}
public void addAttribute(int attrib, FloatBuffer data, int dimensions)
{
if (data == null)
return;
var meta = this.attributeInfo.computeIfAbsent(attrib, k -> new AttributeInfo(EnumArrayBufferType.FLOAT, attrib, dimensions));
if (meta.dimensions() != dimensions)
throw new IllegalArgumentException("Attribute dimensions mismatch!");
this.data.compute(attrib, (k, v) -> {
if (v == null)
return FloatBuffer.allocate(data.remaining()).put(data);
if (!(v instanceof FloatBuffer fab))
throw new IllegalArgumentException();
if (data.remaining() <= fab.remaining())
return fab.put(data);
var newBuf = FloatBuffer.allocate(Math.max(v.capacity() << 1, v.capacity() + data.remaining()));
return newBuf.put(fab.flip()).put(data);
});
}
public void addAttribute(int attrib, IntBuffer data, int dimensions)
{
if (data == null)
return;
var meta = this.attributeInfo.computeIfAbsent(attrib, k -> new AttributeInfo(EnumArrayBufferType.INT, attrib, dimensions));
if (meta.dimensions() != dimensions)
throw new IllegalArgumentException("Attribute dimensions mismatch!");
this.data.compute(attrib, (k, v) -> {
if (v == null)
return IntBuffer.allocate(data.remaining()).put(data);
if (!(v instanceof IntBuffer iab))
throw new IllegalArgumentException();
if (data.remaining() <= iab.remaining())
return iab.put(data);
var newBuf = IntBuffer.allocate(Math.max(v.capacity() << 1, v.capacity() + data.remaining()));
return newBuf.put(iab.flip()).put(data);
});
}
@Override
public PlutoCommandDrawMeshHeap merge(LiCommand other)
{
if (!(other instanceof PlutoCommandDrawMesh pcdm))
throw new UnsupportedOperationException();
pcdm.data.forEach((k, v) -> {
var attrInfo = this.attributeInfo.get(k);
switch (attrInfo.type())
{
case FLOAT -> this.addAttribute(k, (FloatBuffer) v, attrInfo.dimensions());
case INT -> this.addAttribute(k, (IntBuffer) v, attrInfo.dimensions());
case UNSIGNED_INT -> throw new UnsupportedOperationException();
}
});
this.addIndices(pcdm.indices);
return this;
}
}

View File

@ -1,36 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.graphics.gui.command;
import org.plutoengine.graphics.gui.IGUIShader;
import org.plutoengine.libra.command.impl.LiCommandSwitchShader;
public class PlutoCommandSwitchShader extends LiCommandSwitchShader<IGUIShader>
{
public PlutoCommandSwitchShader(IGUIShader shader)
{
super(shader);
}
}

View File

@ -1,36 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.graphics.gui.command;
import org.plutoengine.graphics.texture.Texture;
import org.plutoengine.libra.command.impl.LiCommandSwitchTexture;
public class PlutoCommandSwitchTexture extends LiCommandSwitchTexture<Texture>
{
public PlutoCommandSwitchTexture(Texture texture)
{
super(texture);
}
}

View File

@ -1,183 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.graphics.gui.font;
import org.plutoengine.graphics.texture.Texture;
import org.plutoengine.libra.text.font.GlyphMetrics;
import org.plutoengine.libra.text.font.LiFont;
import org.plutoengine.libra.text.shaping.IShapingStrategy;
import java.util.Map;
public abstract class PlutoFont<T extends PlutoFont<? super T>> extends LiFont<PlutoFont<T>.PlutoGlyphAtlas, PlutoFont<T>.PlutoGlyphMetrics> implements AutoCloseable
{
public static final int NORMALIZED_PIXEL_HEIGHT = 64;
protected int descent;
protected int ascent;
protected int lineGap;
protected int lineAdvance;
protected float scale;
protected Map<Integer, Integer> glyphIndexLookup;
protected Map<PlutoFont.KerningPair, Integer> kerningTable;
public record KerningPair(int left, int right)
{
}
protected PlutoFont(String name)
{
super(name);
}
public abstract IShapingStrategy<? extends PlutoFont<? super T>.PlutoGlyphMetrics, ? extends PlutoFont<? super T>.PlutoGlyphAtlas, T> getDefaultShaper();
public float getScale()
{
return this.scale;
}
public int getAscent()
{
return this.ascent;
}
public int getDescent()
{
return this.descent;
}
public int getLineGap()
{
return this.lineGap;
}
public int getLineAdvance()
{
return this.lineAdvance;
}
public int getKerningOffset(int left, int right)
{
var sk = new PlutoFont.KerningPair(glyphIndexLookup.getOrDefault(left, -1), glyphIndexLookup.getOrDefault(right, -1));
return this.kerningTable.getOrDefault(sk, 0);
}
@Override
public void close()
{
var tex = this.getGlyphAtlas().getGlyphAtlasTexture();
tex.close();
}
public class PlutoGlyphAtlas extends LiFont<PlutoFont<T>.PlutoGlyphAtlas, PlutoFont<T>.PlutoGlyphMetrics>.GlyphAtlas
{
private Texture glyphAtlasTexture;
public void setGlyphAtlasTexture(Texture glyphAtlasTexture)
{
this.glyphAtlasTexture = glyphAtlasTexture;
}
public Texture getGlyphAtlasTexture()
{
return this.glyphAtlasTexture;
}
}
public class PlutoGlyphMetrics extends GlyphMetrics
{
private final int codepoint;
protected int advanceX;
protected int leftSideBearing;
protected int cx0;
protected int cy0;
protected int cx1;
protected int cy1;
protected int xOrigin;
protected int yOrigin;
public PlutoGlyphMetrics(int codepoint)
{
this.codepoint = codepoint;
}
public int getAdvanceX()
{
return this.advanceX;
}
public int getLeftSideBearing()
{
return this.leftSideBearing;
}
public int getCodepoint()
{
return this.codepoint;
}
public int getKerning(int cp)
{
return PlutoFont.this.getKerningOffset(this.codepoint, cp);
}
public int getCX0()
{
return this.cx0;
}
public int getCY0()
{
return this.cy0;
}
public int getCX1()
{
return this.cx1;
}
public int getCY1()
{
return this.cy1;
}
public int getXOrigin()
{
return this.xOrigin;
}
public int getYOrigin()
{
return this.yOrigin;
}
}
}

View File

@ -1,151 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.graphics.gui.font.bitmap;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import org.joml.primitives.Rectanglef;
import org.plutoengine.graphics.gui.font.PlutoFont;
import org.plutoengine.graphics.texture.MagFilter;
import org.plutoengine.graphics.texture.MinFilter;
import org.plutoengine.graphics.texture.WrapMode;
import org.plutoengine.graphics.texture.texture2d.RectangleTexture;
import org.plutoengine.libra.text.font.GlyphInfo;
import org.plutoengine.libra.text.shaping.IShapingStrategy;
import org.plutoengine.logger.Logger;
import org.plutoengine.logger.SmartSeverity;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
public class BitmapFont extends PlutoFont<BitmapFont>
{
private int padding;
private BitmapFont(String name)
{
super(name);
}
public int getPadding()
{
return this.padding;
}
@Override
public IShapingStrategy<BitmapFont.PlutoGlyphMetrics, BitmapFont.PlutoGlyphAtlas, BitmapFont> getDefaultShaper()
{
return new BitmapTextShaper();
}
public static BitmapFont load(Path path)
{
try
{
var objectMapper = new ObjectMapper(YAMLFactory.builder().build());
BitmapFontInfo info;
try (var br = Files.newBufferedReader(path))
{
info = objectMapper.readValue(br, BitmapFontInfo.class);
}
var font = new BitmapFont(info.name());
Logger.logf(SmartSeverity.ADDED, "Loading font: %s%n", font.getName());
font.atlas = font.new PlutoGlyphAtlas();
var tex = new RectangleTexture();
var dir = path.getParent();
var texPath = dir.resolve(info.atlas());
var magFilter = switch (info.filtering()) {
case NEAREST -> MagFilter.NEAREST;
case LINEAR -> MagFilter.LINEAR;
};
tex.load(texPath, magFilter, MinFilter.LINEAR, WrapMode.CLAMP_TO_EDGE, WrapMode.CLAMP_TO_EDGE);
font.atlas.setGlyphAtlasTexture(tex);
var meta = info.meta();
font.ascent = meta.ascent();
font.descent = meta.descent();
font.lineGap = meta.lineGap();
font.lineAdvance = font.ascent - font.descent + font.lineGap;
font.scale = 1.0f / meta.scale() * PlutoFont.NORMALIZED_PIXEL_HEIGHT;
var kern = info.kern();
font.kerningTable = new HashMap<>();
kern.forEach(e -> font.kerningTable.put(new PlutoFont.KerningPair(e.left(), e.right()), e.offset()));
var glyphs = info.glyphs();
font.glyphIndexLookup = new HashMap<>();
font.padding = meta.padding();
glyphs.forEach(glyph -> {
var sprite = glyph.sprite();
var cp = glyph.cp();
var glyphMetrics = font.new PlutoGlyphMetrics(cp) {{
this.advanceX = glyph.advance();
this.leftSideBearing = glyph.leftBearing();
this.xOrigin = (this.leftSideBearing - font.padding) * PlutoFont.NORMALIZED_PIXEL_HEIGHT / meta.scale();
this.yOrigin = (glyph.topOffset() - font.ascent - font.padding) * PlutoFont.NORMALIZED_PIXEL_HEIGHT / meta.scale();
this.cx0 = this.leftSideBearing + font.padding;
this.cy0 = glyph.topOffset() - font.ascent + font.padding;
this.cx1 = this.leftSideBearing + sprite.w() - font.padding;
this.cy1 = sprite.h() - font.ascent - font.padding;
}};
var rect = new Rectanglef(
sprite.x(),
sprite.y(),
sprite.x() + sprite.w(),
sprite.y() + sprite.h()
);
var glyphInfo = new GlyphInfo<>(font.atlas, 0, rect);
font.addGlyph(cp, glyphMetrics, glyphInfo);
});
return font;
}
catch (Exception e)
{
Logger.logf(SmartSeverity.ERROR, "Failed to load font: %s%n", path);
Logger.log(e);
return null;
}
}
}

View File

@ -1,89 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.graphics.gui.font.bitmap;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.ext.NioPathDeserializer;
import java.nio.file.Path;
import java.util.List;
record BitmapFontInfo(
String name,
FontInfoMeta meta,
@JsonDeserialize(using = NioPathDeserializer.class) Path atlas,
Filtering filtering,
@JsonDeserialize(contentAs = KerningInfo.class) List<KerningInfo> kern,
@JsonDeserialize(contentAs = GlyphInfo.class) List<GlyphInfo> glyphs
)
{
enum Filtering
{
NEAREST,
LINEAR
}
record FontInfoMeta(
int ascent,
int descent,
int lineGap,
int padding,
int scale
)
{
}
record KerningInfo(
int left,
int right,
int offset
)
{
}
record GlyphInfo(
int cp,
int glyphClass,
GlyphSprite sprite,
int leftBearing,
int advance,
int topOffset
)
{
}
record GlyphSprite(
int x,
int y,
int w,
int h
)
{
}
}

View File

@ -1,192 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.graphics.gui.font.bitmap;
import org.joml.primitives.Rectanglef;
import org.lwjgl.system.MemoryUtil;
import org.plutoengine.graphics.PlutoGUIMod;
import org.plutoengine.graphics.gui.command.PlutoCommandDrawMeshDirectBuffer;
import org.plutoengine.graphics.gui.command.PlutoCommandSwitchShader;
import org.plutoengine.graphics.gui.command.PlutoCommandSwitchTexture;
import org.plutoengine.libra.command.LiCommandBuffer;
import org.plutoengine.libra.command.impl.LiCommandSetPaint;
import org.plutoengine.libra.text.LiTextInfo;
import org.plutoengine.libra.text.font.GlyphInfo;
import org.plutoengine.libra.text.shaping.IShapingStrategy;
import org.plutoengine.libra.text.shaping.TextShaper;
import org.plutoengine.libra.text.shaping.TextStyleOptions;
import java.util.EnumSet;
import java.util.Objects;
public class BitmapTextShaper implements IShapingStrategy<BitmapFont.PlutoGlyphMetrics, BitmapFont.PlutoGlyphAtlas, BitmapFont>
{
private LiCommandBuffer commandBuffer;
public BitmapTextShaper setCommandBuffer(LiCommandBuffer commandBuffer)
{
this.commandBuffer = commandBuffer;
return this;
}
@Override
public LiTextInfo shape(EnumSet<TextShaper.EnumFeature> features, BitmapFont font, String text, TextStyleOptions style)
{
var commandBuf = Objects.requireNonNullElseGet(this.commandBuffer, LiCommandBuffer::uncleared);
var atlas = font.getGlyphAtlas();
var atlasTexture = atlas.getGlyphAtlasTexture();
var texSwitch = new PlutoCommandSwitchTexture(atlasTexture);
commandBuf.push(texSwitch);
var shader = PlutoGUIMod.bitmapFontShader;
var shaderSwitch = new PlutoCommandSwitchShader(shader);
commandBuf.push(shaderSwitch);
commandBuf.push(new LiCommandSetPaint(style.getPaint()));
var cpCount = (int) text.codePoints().count();
var mesh = new PlutoCommandDrawMeshDirectBuffer();
final var quadVerts = 4;
final var twoTriVerts = 6;
var vertDim = 2;
var vertexBuf = MemoryUtil.memAllocFloat(vertDim * quadVerts * cpCount);
var uvDim = 2;
var uvBuf = MemoryUtil.memAllocFloat(uvDim * quadVerts * cpCount);
var paintUVBuf = MemoryUtil.memAllocFloat(uvDim * quadVerts * cpCount);
var indexBuf = MemoryUtil.memAllocInt(twoTriVerts * cpCount);
var cpIt = text.codePoints().iterator();
var indices = new int[] {
0, 1, 2,
0, 2, 3
};
float[] vertices = new float[vertDim * quadVerts];
float[] uvs = new float[uvDim * quadVerts];
float scale = font.getScale();
float x = 0;
float y = 0;
int padding = font.getPadding();
GlyphInfo<?, ?> info;
BitmapFont.PlutoGlyphMetrics metrics = null;
int cp;
float minX = Float.POSITIVE_INFINITY, maxX = Float.NEGATIVE_INFINITY, minY = Float.POSITIVE_INFINITY, maxY = Float.NEGATIVE_INFINITY;
while (cpIt.hasNext())
{
cp = cpIt.next();
switch (cp)
{
case '\n' -> {
x = 0;
y += font.getLineAdvance() * scale;
continue;
}
}
if (metrics != null && features.contains(TextShaper.EnumFeature.KERNING))
x += metrics.getKerning(cp) * scale;
metrics = font.getGlyphMetrics(cp);
info = atlas.getGlyph(cp);
if (metrics == null)
continue;
if (info != null)
{
float gx = x + metrics.getXOrigin();
float gy = y + metrics.getYOrigin() + font.getAscent() * scale;
float xLow = gx - padding;
float xHigh = gx + metrics.getCX1() * scale - metrics.getCX0() * scale + padding;
float yLow = gy - padding;
float yHigh = gy + metrics.getCY1() * scale - metrics.getCY0() * scale + padding;
minX = Math.min(minX, xLow);
minY = Math.min(minY, yLow);
maxX = Math.max(maxX, xHigh);
maxY = Math.max(maxY, yHigh);
vertices[6] = vertices[0] = xLow;
vertices[3] = vertices[1] = yHigh;
vertices[4] = vertices[2] = xHigh;
vertices[7] = vertices[5] = yLow;
var uvRect = info.getRect();
uvs[6] = uvs[0] = uvRect.minX;
uvs[3] = uvs[1] = atlasTexture.getHeight() - uvRect.maxY;
uvs[4] = uvs[2] = uvRect.maxX;
uvs[7] = uvs[5] = atlasTexture.getHeight() - uvRect.minY;
vertexBuf.put(vertices);
uvBuf.put(uvs);
indexBuf.put(indices);
indices[0] += quadVerts;
indices[1] += quadVerts;
indices[2] += quadVerts;
indices[3] += quadVerts;
indices[4] += quadVerts;
indices[5] += quadVerts;
}
x += metrics.getAdvanceX() * scale;
}
vertexBuf.flip();
while (vertexBuf.hasRemaining())
{
paintUVBuf.put((vertexBuf.get() - minX) / (maxX - minX));
paintUVBuf.put((vertexBuf.get() - minY) / (maxY - minY));
}
mesh.addAttribute(shader.position, vertexBuf.rewind(), vertDim);
mesh.addAttribute(shader.uvCoords, uvBuf.flip(), uvDim);
mesh.addAttribute(shader.paintUVCoords, paintUVBuf.flip(), uvDim);
mesh.addIndices(indexBuf.flip());
commandBuf.push(mesh);
return new LiTextInfo(commandBuf, new Rectanglef(minX, minY, maxX, maxY));
}
}

View File

@ -1,263 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.graphics.gui.font.stbttf;
import org.joml.primitives.Rectanglef;
import org.lwjgl.stb.*;
import org.lwjgl.system.MemoryStack;
import org.plutoengine.buffer.BufferHelper;
import org.plutoengine.graphics.gui.SDFTextureArray;
import org.plutoengine.graphics.gui.font.PlutoFont;
import org.plutoengine.graphics.texture.MagFilter;
import org.plutoengine.graphics.texture.MinFilter;
import org.plutoengine.graphics.texture.WrapMode;
import org.plutoengine.libra.text.font.GlyphInfo;
import org.plutoengine.libra.text.shaping.IShapingStrategy;
import org.plutoengine.logger.Logger;
import org.plutoengine.logger.SmartSeverity;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.WritableRaster;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.stream.IntStream;
public class STBTTFont extends PlutoFont<STBTTFont>
{
public static final int SDF_PADDING = 8;
public static final int SHEET_SIZE = 1024;
private STBTTFont(String name)
{
super(name);
}
@Override
public IShapingStrategy<STBTTFont.PlutoGlyphMetrics, STBTTFont.PlutoGlyphAtlas, STBTTFont> getDefaultShaper()
{
return new STBTTTextShaper();
}
public static STBTTFont load(Path path)
{
try (var stack = MemoryStack.stackPush())
{
var fontInfo = STBTTFontinfo.calloc(stack);
var data = BufferHelper.readToByteBuffer(path);
if (!STBTruetype.stbtt_InitFont(fontInfo, data))
{
Logger.logf(SmartSeverity.ERROR, "Failed to load font: %s%n", path);
return null;
}
var nameBuf = STBTruetype.stbtt_GetFontNameString(fontInfo,
STBTruetype.STBTT_PLATFORM_ID_MICROSOFT,
STBTruetype.STBTT_MS_EID_UNICODE_BMP,
STBTruetype.STBTT_MS_LANG_ENGLISH,
1);
if (nameBuf == null)
{
Logger.logf(SmartSeverity.ERROR, "Failed to load font: %s%n", path);
return null;
}
var name = StandardCharsets.UTF_16BE.decode(nameBuf).toString();
Logger.logf(SmartSeverity.ADDED, "Loading font: %s%n", name);
var font = new STBTTFont(name);
font.scale = STBTruetype.stbtt_ScaleForPixelHeight(fontInfo, NORMALIZED_PIXEL_HEIGHT);
var ascentBuf = stack.callocInt(1);
var descentBuf = stack.callocInt(1);
var lineGapBuf = stack.callocInt(1);
STBTruetype.stbtt_GetFontVMetrics(fontInfo, ascentBuf, descentBuf, lineGapBuf);
var codepoints = IntStream.rangeClosed(0x0000, 0x04ff);
var sdfWidthBuf = stack.mallocInt(1);
var sdfHeightBuf = stack.mallocInt(1);
var xOffsBuf = stack.mallocInt(1);
var yOffsBuf = stack.mallocInt(1);
var rectPacker = STBRPContext.malloc(stack);
var nodes = STBRPNode.calloc(SHEET_SIZE * 4);
STBRectPack.stbrp_init_target(rectPacker, SHEET_SIZE, SHEET_SIZE, nodes);
STBRectPack.stbrp_setup_allow_out_of_mem(rectPacker, true);
var rect = STBRPRect.malloc(1, stack);
var sheets = new ArrayList<BufferedImage>();
var atlas = new BufferedImage(SHEET_SIZE, SHEET_SIZE, BufferedImage.TYPE_BYTE_GRAY);
var graphics = atlas.getGraphics();
var colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY);
var colorModel = new ComponentColorModel(colorSpace, new int[] { 8 }, false,false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
font.atlas = font.new PlutoGlyphAtlas();
font.glyphIndexLookup = new HashMap<>();
var advanceWidth = stack.mallocInt(1);
var leftSideBearingBuf = stack.mallocInt(1);
var cx0Buf = stack.mallocInt(1);
var cy0Buf = stack.mallocInt(1);
var cx1Buf = stack.mallocInt(1);
var cy1Buf = stack.mallocInt(1);
var onedgeValue = 128;
var pixelDistScale = onedgeValue / (float) SDF_PADDING;
for (var cp : codepoints.toArray())
{
var buf = STBTruetype.stbtt_GetCodepointSDF(fontInfo,
font.scale,
cp,
SDF_PADDING,
(byte) onedgeValue,
pixelDistScale,
sdfWidthBuf,
sdfHeightBuf,
xOffsBuf,
yOffsBuf);
var width = sdfWidthBuf.get(0);
var height = sdfHeightBuf.get(0);
var glyphInfo = (GlyphInfo<STBTTFont.PlutoGlyphAtlas, STBTTFont.PlutoGlyphMetrics>) null;
if (buf != null)
{
rect.w(width);
rect.h(height);
if (STBRectPack.stbrp_pack_rects(rectPacker, rect) == 0)
{
sheets.add(atlas);
atlas = new BufferedImage(SHEET_SIZE, SHEET_SIZE, BufferedImage.TYPE_BYTE_GRAY);
graphics = atlas.getGraphics();
STBRectPack.stbrp_init_target(rectPacker, SHEET_SIZE, SHEET_SIZE, nodes);
STBRectPack.stbrp_setup_allow_out_of_mem(rectPacker, true);
STBRectPack.stbrp_pack_rects(rectPacker, rect);
}
var dataBuf = new DataBuffer(DataBuffer.TYPE_BYTE, width * height) {
@Override
public int getElem(int bank, int i)
{
return buf.get(i);
}
@Override
public void setElem(int bank, int i, int val)
{
buf.put(i, (byte) val);
}
};
var sampleModel = colorModel.createCompatibleSampleModel(width, height);
var raster = new WritableRaster(sampleModel, dataBuf, new Point()) {};
var image = new BufferedImage(colorModel, raster, false, null);
graphics.drawImage(image, rect.x(), rect.y(), null);
var glyphRect = new Rectanglef(
rect.x() / (float) SHEET_SIZE,
rect.y() / (float) SHEET_SIZE,
(rect.x() + rect.w()) / (float) SHEET_SIZE,
(rect.y() + rect.h()) / (float) SHEET_SIZE);
glyphInfo = new GlyphInfo<>(font.atlas, sheets.size(), glyphRect);
STBTruetype.stbtt_FreeSDF(buf);
}
STBTruetype.stbtt_GetCodepointHMetrics(fontInfo, cp, advanceWidth, leftSideBearingBuf);
var glyphMetrics = font.new PlutoGlyphMetrics(cp) {{
this.advanceX = advanceWidth.get(0);
this.leftSideBearing = leftSideBearingBuf.get(0);
this.xOrigin = xOffsBuf.get(0);
this.yOrigin = yOffsBuf.get(0);
STBTruetype.stbtt_GetCodepointBox(fontInfo, cp, cx0Buf, cy0Buf, cx1Buf, cy1Buf);
this.cx0 = cx0Buf.get(0);
this.cy0 = cy0Buf.get(0);
this.cx1 = cx1Buf.get(0);
this.cy1 = cy1Buf.get(0);
}};
font.addGlyph(cp, glyphMetrics, glyphInfo);
font.glyphIndexLookup.put(cp, STBTruetype.stbtt_FindGlyphIndex(fontInfo, cp));
}
if (!sheets.contains(atlas))
sheets.add(atlas);
nodes.free();
var kerningTableLength = STBTruetype.stbtt_GetKerningTableLength(fontInfo);
try (var kerningTable = STBTTKerningentry.malloc(kerningTableLength))
{
STBTruetype.stbtt_GetKerningTable(fontInfo, kerningTable);
font.kerningTable = new HashMap<>();
kerningTable.forEach(e -> font.kerningTable.put(new PlutoFont.KerningPair(e.glyph1(), e.glyph2()), e.advance()));
}
font.ascent = ascentBuf.get(0);
font.descent = descentBuf.get(0);
font.lineGap = lineGapBuf.get(0);
font.lineAdvance = font.ascent - font.descent + font.lineGap;
var tex = new SDFTextureArray();
tex.loadImg(sheets, SHEET_SIZE, SHEET_SIZE, sheets.size(), MagFilter.LINEAR, MinFilter.LINEAR, WrapMode.MIRROR_CLAMP_TO_EDGE, WrapMode.MIRROR_CLAMP_TO_EDGE);
font.atlas.setGlyphAtlasTexture(tex);
return font;
}
catch (Exception e)
{
Logger.logf(SmartSeverity.ERROR, "Failed to load font: %s%n", path);
Logger.log(e);
return null;
}
}
}

View File

@ -1,202 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.graphics.gui.font.stbttf;
import org.joml.primitives.Rectanglef;
import org.lwjgl.system.MemoryUtil;
import org.plutoengine.graphics.PlutoGUIMod;
import org.plutoengine.graphics.gui.command.PlutoCommandDrawMeshDirectBuffer;
import org.plutoengine.graphics.gui.command.PlutoCommandSwitchShader;
import org.plutoengine.graphics.gui.command.PlutoCommandSwitchTexture;
import org.plutoengine.libra.command.LiCommandBuffer;
import org.plutoengine.libra.command.impl.LiCommandSetPaint;
import org.plutoengine.libra.command.impl.LiCommandSpecial;
import org.plutoengine.libra.text.LiTextInfo;
import org.plutoengine.libra.text.font.GlyphInfo;
import org.plutoengine.libra.text.shaping.IShapingStrategy;
import org.plutoengine.libra.text.shaping.TextShaper;
import org.plutoengine.libra.text.shaping.TextStyleOptions;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Objects;
public class STBTTTextShaper implements IShapingStrategy<STBTTFont.PlutoGlyphMetrics, STBTTFont.PlutoGlyphAtlas, STBTTFont>
{
private LiCommandBuffer commandBuffer;
public STBTTTextShaper setCommandBuffer(LiCommandBuffer commandBuffer)
{
this.commandBuffer = commandBuffer;
return this;
}
@Override
public LiTextInfo shape(EnumSet<TextShaper.EnumFeature> features, STBTTFont font, String text, TextStyleOptions style)
{
var commandBuf = Objects.requireNonNullElseGet(this.commandBuffer, LiCommandBuffer::uncleared);
var atlas = font.getGlyphAtlas();
var atlasTexture = atlas.getGlyphAtlasTexture();
var texSwitch = new PlutoCommandSwitchTexture(atlasTexture);
commandBuf.push(texSwitch);
var shader = PlutoGUIMod.fontShader;
var shaderSwitch = new PlutoCommandSwitchShader(shader);
commandBuf.push(shaderSwitch);
commandBuf.push(new LiCommandSetPaint(style.getPaint()));
var cpCount = (int) text.codePoints().count();
var mesh = new PlutoCommandDrawMeshDirectBuffer();
final var quadVerts = 4;
final var twoTriVerts = 6;
var vertDim = 2;
var vertexBuf = MemoryUtil.memAllocFloat(vertDim * quadVerts * cpCount);
var uvDim = 2;
var uvBuf = MemoryUtil.memAllocFloat(uvDim * quadVerts * cpCount);
var paintUVBuf = MemoryUtil.memAllocFloat(uvDim * quadVerts * cpCount);
var pageDim = 1;
var pageBuf = MemoryUtil.memAllocInt(pageDim * quadVerts * cpCount);
var indexBuf = MemoryUtil.memAllocInt(twoTriVerts * cpCount);
var cpIt = text.codePoints().iterator();
var indices = new int[] {
0, 1, 2,
0, 2, 3
};
float[] vertices = new float[vertDim * quadVerts];
float[] uvs = new float[uvDim * quadVerts];
int[] pages = new int[pageDim * quadVerts];
float scale = font.getScale();
commandBuf.push(new LiCommandSpecial(cb -> PlutoGUIMod.fontShader.setPixelScale(style.getSize())));
float x = 0;
float y = 0;
GlyphInfo<?, ?> info;
STBTTFont.PlutoGlyphMetrics metrics = null;
int cp;
float minX = Float.POSITIVE_INFINITY, maxX = Float.NEGATIVE_INFINITY, minY = Float.POSITIVE_INFINITY, maxY = Float.NEGATIVE_INFINITY;
while (cpIt.hasNext())
{
cp = cpIt.next();
switch (cp)
{
case '\n' -> {
x = 0;
y += font.getLineAdvance() * scale;
continue;
}
}
if (metrics != null && features.contains(TextShaper.EnumFeature.KERNING))
x += metrics.getKerning(cp) * scale;
metrics = font.getGlyphMetrics(cp);
info = atlas.getGlyph(cp);
if (metrics == null)
continue;
if (info != null)
{
float gx = x + metrics.getXOrigin();
float gy = y + metrics.getYOrigin() + font.getAscent() * scale;
float xLow = gx - STBTTFont.SDF_PADDING;
float xHigh = gx + metrics.getCX1() * scale - metrics.getCX0() * scale + STBTTFont.SDF_PADDING;
float yLow = gy - STBTTFont.SDF_PADDING;
float yHigh = gy + metrics.getCY1() * scale - metrics.getCY0() * scale + STBTTFont.SDF_PADDING;
minX = Math.min(minX, xLow);
minY = Math.min(minY, yLow);
maxX = Math.max(maxX, xHigh);
maxY = Math.max(maxY, yHigh);
vertices[6] = vertices[0] = xLow;
vertices[3] = vertices[1] = yHigh;
vertices[4] = vertices[2] = xHigh;
vertices[7] = vertices[5] = yLow;
var uvRect = info.getRect();
uvs[6] = uvs[0] = uvRect.minX;
uvs[3] = uvs[1] = 1 - uvRect.maxY;
uvs[4] = uvs[2] = uvRect.maxX;
uvs[7] = uvs[5] = 1 - uvRect.minY;
Arrays.fill(pages, info.getPage());
vertexBuf.put(vertices);
uvBuf.put(uvs);
pageBuf.put(pages);
indexBuf.put(indices);
indices[0] += quadVerts;
indices[1] += quadVerts;
indices[2] += quadVerts;
indices[3] += quadVerts;
indices[4] += quadVerts;
indices[5] += quadVerts;
}
x += metrics.getAdvanceX() * scale;
}
vertexBuf.flip();
while (vertexBuf.hasRemaining())
{
paintUVBuf.put((vertexBuf.get() - minX) / (maxX - minX));
paintUVBuf.put((vertexBuf.get() - minY) / (maxY - minY));
}
mesh.addAttribute(shader.position, vertexBuf.rewind(), vertDim);
mesh.addAttribute(shader.uvCoords, uvBuf.flip(), uvDim);
mesh.addAttribute(shader.page, pageBuf.flip(), pageDim);
mesh.addAttribute(shader.paintUVCoords, paintUVBuf.flip(), uvDim);
mesh.addIndices(indexBuf.flip());
commandBuf.push(mesh);
return new LiTextInfo(commandBuf, new Rectanglef(minX, minY, maxX, maxY));
}
}

View File

@ -1,23 +0,0 @@
import org.plutoengine.Versions
plugins {
java
`java-library`
}
description = "Multi-purpose utility library that can be used in basically any project."
dependencies {
api("org.jetbrains", "annotations", "23.0.0")
api("org.yaml", "snakeyaml", "1.28")
api("com.fasterxml.jackson.core", "jackson-core", "2.13.2")
api("com.fasterxml.jackson.core", "jackson-databind", "2.13.2")
api("org.joml", "joml", Versions.jomlVersion)
api("org.joml", "joml-primitives", Versions.jomlPrimitivesVersion)
api("org.apache.commons", "commons-lang3", "3.12.0")
}

View File

@ -1,25 +0,0 @@
module org.plutoengine.plutolib {
requires java.base;
requires java.desktop;
requires transitive org.joml;
requires transitive org.joml.primitives;
requires transitive com.fasterxml.jackson.core;
requires transitive com.fasterxml.jackson.databind;
requires transitive com.fasterxml.jackson.annotation;
requires transitive org.jetbrains.annotations;
requires org.yaml.snakeyaml;
requires org.apache.commons.lang3;
opens org.plutoengine.address;
exports org.plutoengine.address;
exports org.plutoengine.util.color;
exports org.plutoengine.io.property;
exports org.plutoengine.math;
exports org.plutoengine.event.lambda;
exports org.plutoengine.chrono;
}

View File

@ -1,319 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.address;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.KeyDeserializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Range;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;
@JsonDeserialize(using = VirtualAddress.Deserializer.class, keyUsing = VirtualAddress.KeyAddrDeserializer.class)
@JsonSerialize(using = VirtualAddress.Serializer.class, keyUsing = VirtualAddress.Serializer.class)
public final class VirtualAddress implements Comparable<VirtualAddress>
{
public static final int MAX_LENGTH = 128;
public static final int MAX_KEYS = 32;
public static final int MAX_KEY_LENGTH = 32;
public static final int TOKEN_PATH_SEPARATOR = '.';
public static final int TOKEN_HIERARCHY_UP = '~';
private static final VirtualAddress ROOT_ADDRESS = new VirtualAddress("", List.of(), false, 0);
private final String fullPath;
private final List<String> components;
private final boolean relative;
@Range(from = 0, to = Integer.MAX_VALUE)
private final int rootOffset;
VirtualAddress(String fullPath, List<String> components, boolean relative, int rootOffset)
{
this.fullPath = fullPath;
this.components = Collections.unmodifiableList(components);
this.relative = relative;
this.rootOffset = rootOffset;
}
public static VirtualAddress ofRoot()
{
return ROOT_ADDRESS;
}
public List<String> getComponents()
{
return this.components;
}
public boolean isRelative()
{
return this.relative;
}
public boolean isEmpty()
{
return this.fullPath.isEmpty();
}
@Range(from = 0, to = Integer.MAX_VALUE)
public int getRootOffset()
{
return this.rootOffset;
}
@Override
public String toString()
{
return this.fullPath;
}
@Override
public boolean equals(Object o)
{
if (this == o)
return true;
if (o == null || this.getClass() != o.getClass())
return false;
VirtualAddress that = (VirtualAddress) o;
return this.fullPath.equals(that.fullPath);
}
@Override
public int hashCode()
{
return Objects.hash(this.fullPath);
}
public static VirtualAddress parse(String inputStr)
{
return parse(inputStr, false);
}
public static VirtualAddress parse(String inputStr, boolean permitRelative)
{
var parser = new VirtualAddressParser(permitRelative);
inputStr.codePoints()
.sequential()
.forEachOrdered(parser::accept);
return parser.build();
}
public static VirtualAddressParser createParser(boolean permitRelative)
{
return new VirtualAddressParser(permitRelative);
}
@Override
public int compareTo(VirtualAddress o)
{
if (this.rootOffset != o.rootOffset)
return this.rootOffset - o.rootOffset;
return this.fullPath.compareToIgnoreCase(o.fullPath);
}
public int getNameCount()
{
return this.components.size() + this.rootOffset;
}
public @NotNull VirtualAddress getName(int index)
{
if (index < this.rootOffset)
return new VirtualAddress("", List.of(), true, 1);
var component = this.components.get(index - this.rootOffset);
return new VirtualAddress(component, List.of(component), true, 0);
}
public @NotNull VirtualAddress getParent()
{
if (this.components.isEmpty())
{
if (!this.relative)
{
throw new IllegalStateException("Cannot get a parent of a root absolute address!");
}
else
{
var offset = this.rootOffset - 1;
var components = List.<String>of();
return new VirtualAddress(VirtualAddressParser.getNormalizedString(offset, components), components, true, offset);
}
}
var componentsNew = this.components.subList(0, this.components.size() - 1);
return new VirtualAddress(VirtualAddressParser.getNormalizedString(this.rootOffset, componentsNew), componentsNew, this.relative, this.rootOffset);
}
public @NotNull VirtualAddress relativize(@NotNull VirtualAddress other)
{
if (this.relative != other.relative)
throw new IllegalArgumentException("Cannot relativize an address when only one of the inputs is absolute!");
if (this.relative && this.rootOffset > other.rootOffset)
throw new IllegalArgumentException("Cannot relativize against a relative address with a root offset higher than the target one!");
if (this.isEmpty())
return other;
int newOffset = other.rootOffset - this.rootOffset;
var thIt = this.components.iterator();
var oIt = other.components.iterator();
var newPath = new ArrayList<String>();
if (newOffset == 0)
{
while (thIt.hasNext() && oIt.hasNext())
{
var thComp = thIt.next();
var oComp = oIt.next();
if (!thComp.equals(oComp))
{
newOffset++;
newPath.add(oComp);
break;
}
}
}
while (thIt.hasNext())
{
newOffset++;
thIt.next();
}
while (oIt.hasNext())
newPath.add(oIt.next());
return new VirtualAddress(VirtualAddressParser.getNormalizedString(newOffset, newPath), newPath, true, newOffset);
}
public @NotNull VirtualAddress resolve(@NotNull VirtualAddress other)
{
if (!other.relative)
return other;
int removedComponentsSigned = other.rootOffset - this.components.size();
int newOffset = this.rootOffset + Math.max(removedComponentsSigned, 0);
if (!this.relative && newOffset > 0)
throw new IllegalArgumentException("Cannot resolve a relative address against an absolute address that would make it higher than the root!");
int compListEnd = Math.max(-removedComponentsSigned, 0);
var componentsNew = Stream.concat(this.components.stream().limit(compListEnd), other.components.stream()).toList();
return new VirtualAddress(VirtualAddressParser.getNormalizedString(newOffset, componentsNew), componentsNew, this.relative, newOffset);
}
public @NotNull VirtualAddress subAddress(int startIndex, int endIndex)
{
var componentCount = this.components.size();
var maxComponents = this.rootOffset + componentCount;
if (startIndex == 0 && endIndex == 0)
{
var components = List.<String>of();
return new VirtualAddress(VirtualAddressParser.getNormalizedString(0, components), components, this.relative, 0);
}
if (startIndex < 0 || endIndex > maxComponents || endIndex > startIndex)
throw new IndexOutOfBoundsException();
var newComponents = this.components.subList(startIndex - this.rootOffset, endIndex - this.rootOffset);
var newOffset = Math.max(0, this.rootOffset - startIndex);
return new VirtualAddress(VirtualAddressParser.getNormalizedString(newOffset, newComponents), newComponents, this.relative, newOffset);
}
public boolean startsWith(@NotNull VirtualAddress other)
{
return this.fullPath.startsWith(other.fullPath);
}
public boolean endsWith(@NotNull VirtualAddress other)
{
return this.fullPath.endsWith(other.fullPath);
}
public static class KeyAddrDeserializer extends KeyDeserializer
{
@Override
public VirtualAddress deserializeKey(String key, DeserializationContext ctxt)
{
return VirtualAddress.parse(key, false);
}
}
public static class Serializer extends StdSerializer<VirtualAddress>
{
public Serializer()
{
super(VirtualAddress.class);
}
@Override
public void serialize(VirtualAddress value, JsonGenerator gen, SerializerProvider provider) throws IOException
{
gen.writeString(value.fullPath);
}
}
public static class Deserializer extends StdDeserializer<VirtualAddress>
{
public Deserializer()
{
super(VirtualAddress.class);
}
@Override
public VirtualAddress deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
{
return VirtualAddress.parse(p.getValueAsString(), false);
}
}
}

View File

@ -1,33 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.address;
public class VirtualAddressParseException extends RuntimeException
{
public VirtualAddressParseException(String message)
{
super(message);
}
}

View File

@ -1,179 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.address;
import org.jetbrains.annotations.Range;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
public class VirtualAddressParser
{
private enum State
{
HIERARCHY_UP,
KEY,
PATH_SEPARATOR
}
private int position;
private int depth;
private State state;
private final Deque<String> components;
private StringBuilder tokenBuilder;
private final boolean permitRelative;
// Decrement for every root-level ~
@Range(from = 0, to = Integer.MAX_VALUE)
private int rootOffset = 0;
VirtualAddressParser(boolean permitRelative)
{
this.depth = 0;
this.position = 0;
this.state = State.PATH_SEPARATOR;
this.components = new ArrayDeque<>(VirtualAddress.MAX_KEYS);
this.permitRelative = permitRelative;
}
public void accept(int codepoint)
{
switch (this.state)
{
case PATH_SEPARATOR -> {
if (Character.isLetter(codepoint))
{
if (this.components.size() >= VirtualAddress.MAX_KEYS)
throw new VirtualAddressParseException("Max amount of keys (%d) exceeded!".formatted(VirtualAddress.MAX_KEYS));
this.state = State.KEY;
this.tokenBuilder = new StringBuilder(VirtualAddress.MAX_KEY_LENGTH);
this.tokenBuilder.appendCodePoint(codepoint);
}
else if (codepoint == VirtualAddress.TOKEN_HIERARCHY_UP)
{
if (!this.permitRelative)
throw new VirtualAddressParseException("Cannot use the hierarchy-up token (%s) in a non-relative context.".formatted(VirtualAddress.TOKEN_HIERARCHY_UP));
this.state = State.HIERARCHY_UP;
this.tokenBuilder = null;
if (!this.components.isEmpty())
this.components.removeLast();
else
this.rootOffset++;
}
else
{
throw new VirtualAddressParseException("Unexpected character at position %d: %s".formatted(this.position, Character.toString(codepoint)));
}
}
case KEY -> {
if (Character.isLetterOrDigit(codepoint) || codepoint == '_' || codepoint == '-')
{
if (this.tokenBuilder.length() >= VirtualAddress.MAX_KEY_LENGTH)
throw new VirtualAddressParseException("Single key length (%d) exceeded!".formatted(VirtualAddress.MAX_KEY_LENGTH));
this.state = State.KEY;
this.tokenBuilder.appendCodePoint(codepoint);
}
else if (codepoint == VirtualAddress.TOKEN_PATH_SEPARATOR)
{
if (this.depth >= VirtualAddress.MAX_KEYS)
throw new VirtualAddressParseException("Max amount of keys (%d) exceeded!".formatted(VirtualAddress.MAX_KEYS));
if (this.state != State.HIERARCHY_UP)
this.components.addLast(this.tokenBuilder.toString());
this.state = State.PATH_SEPARATOR;
this.depth++;
}
else
{
throw new VirtualAddressParseException("Unexpected character at position %d: %s".formatted(this.position, Character.toString(codepoint)));
}
}
case HIERARCHY_UP -> {
if (codepoint == VirtualAddress.TOKEN_HIERARCHY_UP)
{
if (!this.components.isEmpty())
this.components.removeLast();
else
this.rootOffset++;
}
else if (codepoint == VirtualAddress.TOKEN_PATH_SEPARATOR)
{
if (this.depth >= VirtualAddress.MAX_KEYS)
throw new VirtualAddressParseException("Max amount of keys (%d) exceeded!".formatted(VirtualAddress.MAX_KEYS));
this.state = State.PATH_SEPARATOR;
this.depth++;
}
else
{
throw new VirtualAddressParseException("Unexpected character at position %d: %s".formatted(this.position, Character.toString(codepoint)));
}
}
}
this.position++;
if (this.rootOffset >= VirtualAddress.MAX_KEYS)
throw new VirtualAddressParseException("Cannot move than %d levels up in the hierarchy!".formatted(VirtualAddress.MAX_KEYS));
}
public VirtualAddress build()
{
if (this.state == State.KEY && this.tokenBuilder != null)
this.components.addLast(this.tokenBuilder.toString());
var normalizedAddress = getNormalizedString(this.rootOffset, this.components);
return new VirtualAddress(normalizedAddress, List.copyOf(this.components), this.permitRelative, this.rootOffset);
}
static String getNormalizedString(int rootOffset, Iterable<String> components)
{
var separator = Character.toString(VirtualAddress.TOKEN_PATH_SEPARATOR);
var componentsJoined = String.join(separator, components);
var sb = new StringBuilder();
sb.append(Character.toString(VirtualAddress.TOKEN_HIERARCHY_UP).repeat(rootOffset));
if (rootOffset > 0 && !componentsJoined.isEmpty())
sb.append(separator);
sb.append(componentsJoined);
return sb.toString();
}
}

View File

@ -1,31 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Utilities for time manipulation and conversion.
*
* @author 493msi
*
*/
package org.plutoengine.chrono;

View File

@ -1,90 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.io.property;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.error.YAMLException;
import org.yaml.snakeyaml.nodes.MappingNode;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.ScalarNode;
import org.yaml.snakeyaml.nodes.Tag;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.LinkedHashMap;
import java.util.Map;
public class YAMLPropertiesReader
{
public static Map<String, String> loadFromFile(Path file) throws IOException, YAMLException
{
try (var br = Files.newBufferedReader(file))
{
var yaml = new Yaml(new Constructor() {
private void recursivelyBuildTree(Map<String, String> map, String accessor, Node node)
{
if (node instanceof MappingNode mappingNode)
{
var kvps = mappingNode.getValue();
for (var kvp : kvps)
{
var key = kvp.getKeyNode();
if (key.getTag() != Tag.STR || !(key instanceof ScalarNode))
throw new YAMLException("All keys in property trees must be strings!");
var valueNode = kvp.getValueNode();
var newAccessorFormat = valueNode instanceof MappingNode ? "%s%s." : "%s%s";
this.recursivelyBuildTree(map, newAccessorFormat.formatted(accessor, super.constructScalar((ScalarNode) key)), valueNode);
}
}
else if (node instanceof ScalarNode scalarNode)
{
map.put(accessor, super.constructScalar(scalarNode));
}
else
{
throw new YAMLException("Invalid node tag: %s".formatted(node.getTag()));
}
}
@Override
protected Object constructObject(Node node)
{
var propertyMap = new LinkedHashMap<String, String>();
this.recursivelyBuildTree(propertyMap, "", node);
return propertyMap;
}
});
return yaml.load(br);
}
}
}

View File

@ -1,74 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.math;
import org.joml.Math;
public class BasicInterpolation
{
public static int roundedLerp(float value, int min, int max)
{
return min + Math.round(value * (max - min));
}
public static int roundedLerpWrap(float value, int min, int max)
{
var range = max - min;
return min + (roundedLerp(value, 0, range) % range + range) % range;
}
public static int roundedLerp(double value, int min, int max)
{
return (int) (min + Math.round(value * (max - min)));
}
public static int roundedLerpWrap(double value, int min, int max)
{
var range = max - min;
return min + (roundedLerp(value, 0, range) % range + range) % range;
}
public static int floorLerp(float value, int min, int max)
{
return (int) (min + Math.floor(value * (max - min)));
}
public static int floorLerpWrap(float value, int min, int max)
{
var range = max - min;
return min + (floorLerp(value, 0, range) % range + range) % range;
}
public static int floorLerp(double value, int min, int max)
{
return (int) (min + Math.floor(value * (max - min)));
}
public static int floorLerpWrap(double value, int min, int max)
{
var range = max - min;
return min + (floorLerp(value, 0, range) % range + range) % range;
}
}

View File

@ -1,31 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Math utility classes.
*
* @author 493msi
*
*/
package org.plutoengine.math;

View File

@ -1,493 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.util.color;
import org.jetbrains.annotations.NotNull;
/**
* A simple 8-bit RGBA color container.
*
* <p><em>
* Some methods mutate the object to avoid new object creation.
* These methods are prefixed with "store".
* </em></p>
*
* Each of the color components is stored separately as a 32-bit integer
* to avoid unnecessary type conversion at the cost of some memory.
*
* <p>
* This however should not be a problem as <em>this class is not designed
* for large-scale or performance-sensitive color operations</em>.
* </p>
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public final class Color
{
// Black and white
public static Color WHITE = new Color(255, 255, 255);
public static Color BLACK = new Color(0, 0, 0);
// Shades of gray
public static Color VERY_DARK_GRAY = new Color(40, 40, 40);
public static Color DARK_GRAY = new Color(85, 85, 85);
public static Color GRAY = new Color(128, 128, 128);
public static Color SILVER = new Color(192, 192, 192);
public static Color LIGHT_GRAY = new Color(212, 212, 212);
// Basic colors
public static Color RED = new Color(255, 0, 0);
public static Color GREEN = new Color(0, 255, 0);
public static Color BLUE = new Color(0, 0, 255);
public static Color YELLOW = new Color(255, 255, 0);
public static Color TRANSPARENT = new Color(0, 0, 0, 0);
public static Color TRANSPARENT_WHITE = new Color(255, 255, 255, 0);
public static Color AMBER = new Color(255, 190, 0);
public static Color AMETHYST = new Color(153, 102, 204);
public static Color APRICOT = new Color(235, 147, 115);
public static Color AZURE = new Color(0, 57, 169);
public static Color BROWN = new Color(150, 75, 0);
public static Color COBALT = new Color(0, 71, 171);
public static Color COPPER = new Color(184, 115, 51);
public static Color CORAL_RED = new Color(255, 50, 60);
public static Color CORNFLOWER_BLUE = new Color(112, 112, 255);
public static Color CRIMSON = new Color(220, 26, 64);
public static Color CYAN = new Color(0, 188, 212);
public static Color DARK_BROWN = new Color(66, 33, 0);
public static Color DARK_GREEN = new Color(0, 150, 0);
public static Color LIGHT_AZURE = new Color(0, 128, 255);
public static Color LIME = new Color(191, 255, 0);
public static Color MAGENTA = new Color(255, 0, 255);
public static Color MALACHITE = new Color(11, 218, 81);
public static Color NAVY_BLUE = new Color(0, 0, 128);
public static Color OBSIDIAN = new Color(16, 18, 29);
public static Color ORANGE = new Color(255, 102, 0);
public static Color ORANGE_RED = new Color(255, 55, 0);
public static Color PEAR = new Color(209, 226, 49);
public static Color PINK = new Color(253, 109, 134);
public static Color PUMPKIN_ORANGE = new Color(255, 117, 0);
public static Color SAPPHIRE = new Color(47, 81, 158);
public static Color TEAL = new Color(0, 140, 140);
public static Color TURQUOISE = new Color(10, 255, 141);
public static Color PASTEL_PINK = new Color(255, 192, 203);
public static Color PASTEL_LIME = new Color(221, 255, 192);
public static Color PASTEL_YELLOW = new Color(252, 255, 192);
public static Color PASTEL_CYAN = new Color(192, 255, 234);
public static Color PASTEL_BLUE = new Color(192, 199, 255);
public static Color PASTEL_VIOLET = new Color(192, 199, 255);
public int red;
public int green;
public int blue;
public int alpha = 255;
/**
* Creates a new Color object from the supplied RGBA color components.
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public Color(int red, int green, int blue, int alpha)
{
this.red = red;
this.green = green;
this.blue = blue;
this.alpha = alpha;
}
/**
* Creates a new Color object from the supplied RGBA color components.
*
* Alpha is set to 255 by default.
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public Color(int red, int green, int blue)
{
this.red = red;
this.green = green;
this.blue = blue;
}
/**
* Converts the supplied float-based {@link IRGBA} color object to a new {@link Color} object and returns it.
*
* Color values are rounded to the nearest integer.
*
* @return A new {@link Color} object
*
* @param colorComponents An {@link IRGBA} color object
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public static Color from(@NotNull IRGBA colorComponents)
{
return new Color(Math.round(colorComponents.red() * 255),
Math.round(colorComponents.green() * 255),
Math.round(colorComponents.blue() * 255),
Math.round(colorComponents.alpha() * 255));
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public static Color from(@NotNull IRGB colorComponents)
{
return new Color(Math.round(colorComponents.red() * 255),
Math.round(colorComponents.green() * 255),
Math.round(colorComponents.blue() * 255));
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public static Color from(int color, @NotNull EnumColorFormat colorFormat)
{
return switch (colorFormat)
{
case CF_INT_BGR -> new Color(color & 0xff, (color >> 8) & 0xff, (color >> 16) & 0xff);
case CF_INT_RGB -> new Color((color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
case CF_INT_ABGR -> new Color(color & 0xff, (color >> 8) & 0xff, (color >> 16) & 0xff, (color >> 24) & 0xff);
case CF_INT_ARGB -> new Color((color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff, (color >> 24) & 0xff);
case CF_INT_BGRA -> new Color((color >> 8) & 0xff, (color >> 16) & 0xff, (color >> 24) & 0xff, color & 0xff);
case CF_INT_RGBA -> new Color((color >> 24) & 0xff, (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
default -> throw new UnsupportedOperationException("Use the from(byte[], int, ColorFormat) for byte color formats!");
};
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public static Color fromAWT(@NotNull java.awt.Color color)
{
return new Color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public static Color from(byte @NotNull [] color, @NotNull EnumColorFormat colorFormat)
{
return from(color, 0, colorFormat);
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public static Color from(byte @NotNull [] color, int offset, @NotNull EnumColorFormat colorFormat)
{
return switch (colorFormat)
{
case CF_3BYTE_BGR -> new Color(color[offset + 2] & 0xFF, color[offset + 1] & 0xFF, color[offset] & 0xFF);
case CF_3BYTE_RGB -> new Color(color[offset] & 0xFF, color[offset + 1] & 0xFF, color[offset + 2] & 0xFF);
case CF_4BYTE_ABGR -> new Color(color[offset + 3] & 0xFF, color[offset + 2] & 0xFF, color[offset + 1] & 0xFF, color[offset] & 0xFF);
case CF_4BYTE_ARGB -> new Color(color[offset + 1] & 0xFF, color[offset + 2] & 0xFF, color[offset + 3] & 0xFF, color[offset] & 0xFF);
case CF_4BYTE_BGRA -> new Color(color[offset + 2] & 0xFF, color[offset + 1] & 0xFF, color[offset] & 0xFF, color[offset + 3] & 0xFF);
case CF_4BYTE_RGBA -> new Color(color[offset] & 0xFF, color[offset + 1] & 0xFF, color[offset + 2] & 0xFF, color[offset + 3] & 0xFF);
default -> throw new UnsupportedOperationException("Use the from(int, ColorFormat) for int color formats!");
};
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public int getIntRGBA()
{
return get(EnumColorFormat.CF_INT_RGBA);
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public int getIntARGB()
{
return get(EnumColorFormat.CF_INT_ARGB);
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public int get(@NotNull EnumColorFormat colorFormat)
{
return switch (colorFormat)
{
case CF_INT_BGR -> (this.blue << 16) | (this.green << 8) | this.red;
case CF_INT_RGB -> (this.red << 16) | (this.green << 8) | this.blue;
case CF_INT_ABGR -> (this.alpha << 24) | (this.blue << 16) | (this.green << 8) | this.red;
case CF_INT_ARGB -> (this.alpha << 24) | (this.red << 16) | (this.green << 8) | this.blue;
case CF_INT_BGRA -> (this.blue << 24) | (this.green << 16) | (this.red << 8) | this.alpha;
case CF_INT_RGBA -> (this.red << 24) | (this.green << 16) | (this.blue << 8) | this.alpha;
default -> throw new UnsupportedOperationException("Use the get(ColorFormat, byte[], int) for byte color formats!");
};
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public void get(@NotNull EnumColorFormat colorFormat, byte @NotNull [] dataOut)
{
get(colorFormat, dataOut, 0);
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public void get(@NotNull EnumColorFormat colorFormat, byte @NotNull [] dataOut, int offset)
{
switch (colorFormat)
{
case CF_3BYTE_BGR -> {
dataOut[offset++] = (byte) this.blue;
dataOut[offset++] = (byte) this.green;
dataOut[offset] = (byte) this.red;
}
case CF_3BYTE_RGB -> {
dataOut[offset++] = (byte) this.red;
dataOut[offset++] = (byte) this.green;
dataOut[offset] = (byte) this.blue;
}
case CF_4BYTE_ABGR -> {
dataOut[offset++] = (byte) this.alpha;
dataOut[offset++] = (byte) this.blue;
dataOut[offset++] = (byte) this.green;
dataOut[offset] = (byte) this.red;
}
case CF_4BYTE_ARGB -> {
dataOut[offset++] = (byte) this.alpha;
dataOut[offset++] = (byte) this.red;
dataOut[offset++] = (byte) this.green;
dataOut[offset] = (byte) this.blue;
}
case CF_4BYTE_BGRA -> {
dataOut[offset++] = (byte) this.blue;
dataOut[offset++] = (byte) this.green;
dataOut[offset++] = (byte) this.red;
dataOut[offset] = (byte) this.alpha;
}
case CF_4BYTE_RGBA -> {
dataOut[offset++] = (byte) this.red;
dataOut[offset++] = (byte) this.green;
dataOut[offset++] = (byte) this.blue;
dataOut[offset] = (byte) this.alpha;
}
default -> throw new UnsupportedOperationException("Use the get(ColorFormat) for int color formats!");
}
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public int getRed()
{
return this.red;
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public int getGreen()
{
return this.green;
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public int getBlue()
{
return this.blue;
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public int getAlpha()
{
return this.alpha;
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public RGB getFloatComponentsRGB()
{
return new RGB(this.red / 255.0f, this.green / 255.0f, this.blue / 255.0f);
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public RGBA getFloatComponentsRGBA()
{
return new RGBA(this.red / 255.0f, this.green / 255.0f, this.blue / 255.0f, this.alpha / 255.0f);
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public HSB getFloatComponentsHSB()
{
return this.getFloatComponentsRGB().toHSB();
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public HSBA getFloatComponentsHSBA()
{
return this.getFloatComponentsRGBA().toHSBA();
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public void storeFloatComponentsRGBA(@NotNull RGBA target)
{
storeFloatComponentsRGB(target);
target.a = this.alpha / 255.0f;
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public void storeFloatComponentsRGB(@NotNull RGB target)
{
target.r = this.red / 255.0f;
target.g = this.green / 255.0f;
target.b = this.blue / 255.0f;
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public void storeFloatComponentsHSBA(@NotNull HSBA target)
{
var hsb = this.getFloatComponentsHSBA();
target.h = hsb.h;
target.s = hsb.s;
target.b = hsb.b;
target.a = hsb.a;
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public void storeFloatComponentsHSB(@NotNull HSB target)
{
var hsb = this.getFloatComponentsHSB();
target.h = hsb.h;
target.s = hsb.s;
target.b = hsb.b;
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public java.awt.Color toAWT()
{
return new java.awt.Color(this.red, this.green, this.blue, this.alpha);
}
}

View File

@ -1,105 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.util.color;
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public enum EnumColorFormat
{
/**
* 8-bit RGBA stored in a big-endian 32-bit integer
*/
CF_INT_RGBA(4),
/**
* 8-bit BGRA stored in a big-endian 32-bit integer
*/
CF_INT_BGRA(4),
/**
* 8-bit ARGB stored in a big-endian 32-bit integer
*/
CF_INT_ARGB(4),
/**
* 8-bit ABGR stored in a big-endian 32-bit integer
*/
CF_INT_ABGR(4),
/**
* 8-bit RGB stored in a big-endian 32-bit integer, the highest 8-bits are unused
*/
CF_INT_RGB(4),
/**
* 8-bit RGB stored in a big-endian 32-bit integer, the highest 8-bits are unused
*/
CF_INT_BGR(4),
/**
* 8-bit RGBA, one byte per color component
*/
CF_4BYTE_RGBA(4),
/**
* 8-bit BGRA, one byte per color component
*/
CF_4BYTE_BGRA(4),
/**
* 8-bit ARGB, one byte per color component
*/
CF_4BYTE_ARGB(4),
/**
* 8-bit ABGR, one byte per color component
*/
CF_4BYTE_ABGR(4),
/**
* 8-bit RGB, one byte per color component
*/
CF_3BYTE_RGB(3),
/**
* 8-bit BGR, one byte per color component
*/
CF_3BYTE_BGR(3);
private final int size;
EnumColorFormat(int size)
{
this.size = size;
}
/**
* Returns the size in bytes.
*
* @return The size of the color format, in bytes
*/
public int getSize()
{
return this.size;
}
}

View File

@ -1,163 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.util.color;
import org.apache.commons.lang3.Range;
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public class HSB
{
/**
* Hue [0°..360°]
* */
protected float h;
/**
* Saturation [0..1]
* */
protected float s;
private final static Range<Float> SATURATION_RANGE = Range.between(0.0f, 1.0f);
/**
* Value/Brightness [0..1]
* */
protected float b;
private final static Range<Float> BRIGHTNESS_RANGE = Range.between(0.0f, 1.0f);
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public HSB(float hue, float saturation, float brightness)
{
this.h = (360.0f + hue % 360.0f) % 360.0f;
this.s = SATURATION_RANGE.fit(saturation);
this.b = BRIGHTNESS_RANGE.fit(brightness);
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public RGB toRGB()
{
return this.toRGBA(1.0f);
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public RGBA toRGBA()
{
return this.toRGBA(1.0f);
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public RGBA toRGBA(float alpha)
{
float h6 = this.h / 60.0f;
int hueSide = (int) h6;
// The color component furthest on the hue wheel
float p = this.b * (1 - this.s);
float hueFractCCW = h6 - hueSide;
// The second-nearest color component on the hue wheel - counter-clockwise
float q = this.b * (1 - hueFractCCW * this.s);
float hueFractCW = 1 - hueFractCCW;
// The second-nearest color component on the hue wheel - clockwise
float t = this.b * (1 - hueFractCW * this.s);
return switch (hueSide % 6)
{
// Hues 60°-119° -- Green is the brightest color, no blue is present at max saturation
case 1 -> new RGBA(q, this.b, p, alpha);
// Hues 120°-179° -- Green is the brightest color, no red is present at max saturation
case 2 -> new RGBA(p, this.b, t, alpha);
// Hues 180°-239° -- Blue is the brightest color, no red is present at max saturation
case 3 -> new RGBA(p, q, this.b, alpha);
// Hues 240°-299° -- Blue is the brightest color, no green is present at max saturation
case 4 -> new RGBA(t, p, this.b, alpha);
// Hues 300°-359° -- Red is the brightest color, no green is present at max saturation
case 5 -> new RGBA(this.b, p, q, alpha);
// Hues 0°-59° -- Red is the brightest color, no blue is present at max saturation
case 0 -> new RGBA(this.b, t, p, alpha);
default -> throw new IllegalStateException("This HSB object's hue is negative - this is not legal.");
};
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public float hue()
{
return this.h;
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public float saturation()
{
return this.s;
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public float brightness()
{
return this.b;
}
}

View File

@ -1,75 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.util.color;
import org.apache.commons.lang3.Range;
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public class HSBA extends HSB
{
protected float a;
private final static Range<Float> ALPHA_RANGE = Range.between(0.0f, 1.0f);
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public HSBA(float hue, float saturation, float lightness, float alpha)
{
super(hue, saturation, lightness);
this.a = ALPHA_RANGE.fit(alpha);
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public float alpha()
{
return this.a;
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
@Override
public RGBA toRGBA()
{
return this.toRGBA(this.a);
}
}

View File

@ -1,55 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.util.color;
/**
* An interface for single precision RGB color objects.
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public interface IRGB
{
/**
* Returns the red color component.
*
* @return The red component, in range 0..1
*/
float red();
/**
* Returns the green color component.
*
* @return The green component, in range 0..1
*/
float green();
/**
* Returns the blue color component.
*
* @return The blue color component, in range 0..1
*/
float blue();
}

View File

@ -1,41 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.util.color;
/**
* An interface for single precision RGBA color objects.
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public interface IRGBA extends IRGB
{
/**
* Returns the alpha color component.
*
* @return The alpha component, in range 0..1
*/
float alpha();
}

View File

@ -1,145 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 493msi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.plutoengine.util.color;
import org.apache.commons.lang3.math.NumberUtils;
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public class RGB implements IRGB
{
protected float r;
protected float g;
protected float b;
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public RGB(float r, float g, float b)
{
this.r = r;
this.g = g;
this.b = b;
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public HSBA toHSB()
{
return this.toHSBA(1.0f);
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public HSBA toHSBA()
{
return this.toHSBA(1.0f);
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public HSBA toHSBA(float alpha)
{
float brightness = NumberUtils.max(this.r, this.g, this.b);
float min = NumberUtils.min(this.r, this.g, this.b);
if (brightness == 0)
return new HSBA(0, 0, 0, alpha);
float chroma = brightness - min;
if (chroma == 0)
return new HSBA(0, 0, brightness, alpha);
float saturation = chroma / brightness;
float hue;
if (brightness == this.r)
if (this.g < this.b)
hue = (this.g - this.b) / chroma + 6;
else
hue = (this.g - this.b) / chroma;
else if (brightness == this.g)
hue = (this.b - this.r) / chroma + 2;
else
hue = (this.r - this.g) / chroma + 4;
hue *= 60;
return new HSBA(hue, saturation, brightness, alpha);
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public float red()
{
return this.r;
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public float green()
{
return this.g;
}
/**
* TODO
*
* @since 20.2.0.0-alpha.3
* @author 493msi
*/
public float blue()
{
return this.b;
}
}

Some files were not shown because too many files have changed in this diff Show More