Compare commits
5 Commits
master
...
plutocomma
Author | SHA1 | Date |
---|---|---|
493msi | 9804e9f3f5 | |
493msi | c3db492a6d | |
493msi | 5952a26fee | |
493msi | aa70f1bbe2 | |
493msi | c3bd358bed |
|
@ -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 }}
|
|
|
@ -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
|
|
|
@ -1,17 +1,13 @@
|
||||||
/*/.settings
|
/*/.settings
|
||||||
|
|
||||||
/.vscode
|
|
||||||
|
|
||||||
# Ignore Eclipse project files
|
# Ignore Eclipse project files
|
||||||
/*/.project
|
/*/.project
|
||||||
/*/.classpath
|
/*/.classpath
|
||||||
/.project
|
/.project
|
||||||
/.settings
|
|
||||||
|
|
||||||
# Ignore IDEA project files
|
# Ignore IDEA project files
|
||||||
/.idea
|
/.idea
|
||||||
/*/.idea
|
/*/.idea
|
||||||
.idea
|
|
||||||
|
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
|
@ -23,7 +19,3 @@
|
||||||
# Ignore Gradle build output directory
|
# Ignore Gradle build output directory
|
||||||
/build
|
/build
|
||||||
/*/build
|
/*/build
|
||||||
|
|
||||||
/bin
|
|
||||||
/*/bin
|
|
||||||
/logs/
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[submodule "libra"]
|
|
||||||
path = libra
|
|
||||||
url = git@github.com:493msi/libra.git
|
|
|
@ -1,6 +1,6 @@
|
||||||
MIT License
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
|
@ -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/
|
|
|
@ -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
|
|
@ -1,56 +1,7 @@
|
||||||
# plutoengine
|
# 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.
|
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
|
### Versioning
|
||||||
|
|
||||||
All submodules share a version number for simplicity reasons.
|
All submodules share a version number for simplicity reasons.
|
||||||
|
@ -70,26 +21,42 @@ version numbers.*
|
||||||
|
|
||||||
## Usability status of submodules
|
## 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
|
### Safe submodules
|
||||||
* **PlutoCore** - Stable
|
* **PlutoCore** - Stable
|
||||||
* **PlutoSpritesheet** - Stable, some features are unfinished
|
* **PlutoFramebuffer** - Stable
|
||||||
* **PlutoDisplay** - Stable, collision API nowhere near completion
|
* **PlutoGUI** - Stable, awaiting a rewrite
|
||||||
* **PlutoLib** - Mostly stable
|
* **PlutoLib** - Mostly stable, the module API still has some quirks
|
||||||
* **PlutoRender** - Stable
|
* **PlutoMesher** - Stable
|
||||||
* **PlutoRuntime** - Mostly stable
|
* **PlutoShader** - Stable
|
||||||
|
* **PlutoSpriteSheet** - Stable, some features are unfinished
|
||||||
|
* **PlutoStatic** - Stable, collision API nowhere near completion
|
||||||
|
|
||||||
### Unstable submodules
|
### Unstable submodules
|
||||||
* **PlutoAudio** - Very tentative, work in progress
|
* **PlutoAudio** - Somewhat usable, unfinished
|
||||||
* **PlutoGUI** - Recently rewritten, the API is highly unstable, work in progress
|
|
||||||
|
|
||||||
### Extensions
|
|
||||||
* **PlutoUSS2** - Stable
|
|
||||||
* **PlutoGameObject** - Stable
|
|
||||||
|
|
||||||
|
### Broken submodules, do NOT use
|
||||||
|
* **PlutoCommandParser** - Unfinished, broken, unusable
|
||||||
|
* **PlutoDB** - Broken, unusable
|
||||||
|
|
||||||
## Current priorities
|
## 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
|
|
@ -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
|
## 20.2.0.0-alpha.2
|
||||||
* `build.gradle` Extracted the version numbers into separate variables
|
* `build.gradle` Extracted the version numbers into separate variables
|
||||||
* `build.gradle` **[experimental]** `gradlew` should now automatically download JDK11 when needed
|
* `build.gradle` **[experimental]** `gradlew` should now automatically download JDK11 when needed
|
||||||
* `build.gradle` Updated the build scripts and added source Maven publication
|
* `build.gradle` Updated the build scripts and added source Maven publication
|
||||||
* `[PlutoLib]` Renamed the `cz.tefek.pluto.eventsystem` package to `cz.tefek.pluto.event`
|
* `[PlutoLib]` Renamed the `cz.tefek.pluto.eventsystem` package to `cz.tefek.pluto.event`
|
||||||
* Moved all subpackages
|
* Moved all subpackages
|
||||||
|
* Updated all references
|
||||||
* `[PlutoLib]` Minor code cleanup in `cz.tefek.pluto.modloader.event`
|
* `[PlutoLib]` Minor code cleanup in `cz.tefek.pluto.modloader.event`
|
||||||
* `[Pluto]` Moved `TPL` from `cz.tefek.pluto.tpl` to `cz.tefek.pluto.io.tpl`
|
* `[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`
|
* `[PlutoMesher]` Renamed all occurrences of `attrib` to `attribute`
|
||||||
* Renamed `VertexArray#createArrayAttrib` to `VertexArray#createArrayAttribute`
|
* Renamed `VertexArray#createArrayAttrib` to `VertexArray#createArrayAttribute`
|
||||||
* Renamed `VertexArray#getVertexAttribs` to `VertexArray#getVertexAttributes`
|
* Renamed `VertexArray#getVertexAttribs` to `VertexArray#getVertexAttributes`
|
||||||
* `[PlutoCore]` Made `PlutoApplication.StartupConfig` fields private, options
|
* `[PlutoCore]` Made `PlutoApplication.StartupConfig` fields private, options
|
||||||
can now only be modified only through public setters
|
can now only be modified only through public setters
|
||||||
* `[PlutoLib]` Added the `ThreadSensitive` annotation
|
* `[PlutoLib]` Added the `ThreadSensitive` annotation
|
||||||
* `[PlutoLib]` Renamed `MiniTimeCouldNotBeParsedException` to `MiniTimeParseException`
|
|
||||||
* `[PlutoCore]` Refactored `InputBus` and added several convenience methods
|
* `[PlutoCore]` Refactored `InputBus` and added several convenience methods
|
||||||
* `[PlutoCore]` Refactored input callbacks
|
* `[PlutoCore]` Refactored input callbacks
|
||||||
* `[PlutoStatic]` Slight cleanup in the `Display` and `DisplayBuilder` classes
|
* `[PlutoStatic]` Slight cleanup in the `Display` and `DisplayBuilder` classes
|
||||||
|
* `[PlutoCommandParser]` **Initial release**
|
||||||
|
|
||||||
## 20.2.0.0-alpha.1
|
## 20.2.0.0-alpha.1
|
||||||
* `[PlutoLib#cz.tefek.pluto.io.logger]` Refactored the Logger subsystem
|
* `[PlutoLib#cz.tefek.pluto.io.logger]` Refactored the Logger subsystem
|
||||||
|
@ -188,4 +44,4 @@
|
||||||
* `[PlutoCore]` `[PlutoApplication]` now properly closes the `Logger` on exit
|
* `[PlutoCore]` `[PlutoApplication]` now properly closes the `Logger` on exit
|
||||||
* `[PlutoLib]` Various typo fixes
|
* `[PlutoLib]` Various typo fixes
|
||||||
* `[Pluto*]` Deprecated `Severity` for `SmartSeverity` and replaced all usages
|
* `[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
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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())
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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"])
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
)
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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")
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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"))
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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;
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
|
@ -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")
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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")
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
|
@ -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
Loading…
Reference in New Issue