Skip to content

Commit

Permalink
FreeType module restored and updated to the new AssetStorage API. #182
Browse files Browse the repository at this point in the history
  • Loading branch information
czyzby committed Mar 29, 2020
1 parent ab1ab6a commit f0995bf
Show file tree
Hide file tree
Showing 8 changed files with 402 additions and 179 deletions.
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,27 @@
- `PerformanceCounter.prettyPrint` allows to print basic performance data after profiling.
- **[CHANGE]** (`ktx-app`) `LetterboxingViewport` moved from `ktx-app` to `ktx-graphics`.
- **[FEATURE]** (`ktx-ashley`) Added `Entity.contains` (`in` operator) that checks if an `Entity` has a `Component`.
- **[FEATURE]** (`ktx-assets-async`) Added a new KTX module: coroutines-based asset loading.
- `AssetStorage` is a non-blocking coroutines-based alternative to LibGDX `AssetManager`.
- `get` operator obtains an asset from the storage as `Deferred`.
- `load` schedules asynchronous loading of an asset.
- `unload` schedules asynchronous unloading of an asset.
- `add` allows to manually add a loaded asset to `AssetManager`.
- `dispose` unloads all assets from the storage.
- `getLoader` and `setLoader` manage `AssetLoader` instances used to load assets.
- `isLoaded` checks if loading of an asset was finished.
- `contains` operator checks if the asset was scheduled for loading or added to the storage.
- `getReferenceCount` returns how many times the asset was loaded or referenced by other assets as a dependency.
- `getDependencies` returns a list of dependencies of the selected asset.
- `getAssetDescriptor` creates an `AssetDescriptor` with loading data for the selected asset.
- `getIdentifier` creates an `Identifier` uniquely pointing to an asset of selected type and file path.
- `AssetDescriptor.toIdentifier` allows to convert an `AssetDescriptor` to `Identifier` used to uniquely identify `AssetStorage` assets.
- **[FEATURE]** (`ktx-async`) Added `RenderingScope` factory function for custom scopes using rendering thread dispatcher.
- **[FEATURE]** (`ktx-async`) `newAsyncContext` and `newSingleThreadAsyncContext` now support `threadName` parameter
that allows to set thread name pattern of `AsyncExecutor` threads.
- **[FIX]** (`ktx-async`) `isOnRenderingThread` now behaves consistently regardless of launching coroutine context.
- **[FEATURE]** (`ktx-freetype-async`) This KTX module is now restored and updated to the new `AssetStorage` API.
There are no public API changes since the last released version.
- **[FEATURE]** (`ktx-graphics`) Added `LetterboxingViewport` from `ktx-app`.
- **[FEATURE]** (`ktx-graphics`) Added `takeScreenshot` utility function that allows to save a screenshot of the application.
- **[FEATURE]** (`ktx-graphics`) Added `BitmapFont.center` extension method that allows to center text on an object.
Expand Down
5 changes: 5 additions & 0 deletions assets-async/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,11 @@ Since these values can be passed in 3 basic ways, most methods are available in
- With LibGDX `AssetDescriptor` storing `Class`, path and loading data of the asset.

All three variants behave identically and are available for convenience.
To ease the API usage, the following utilities are provided:

- `AssetStorage.getAssetDescriptor` - creates an `AssetDescriptor` instance that has loading data of an asset.
- `AssetStorage.getIdentifier` - creates an `Identifier` instance that uniquely identifies a stored asset.
- `AssetDescriptor.toIdentifier` - converts an `AssetDescriptor` to an `Identifier`.

### Usage examples

Expand Down
6 changes: 2 additions & 4 deletions assets-async/src/test/kotlin/ktx/assets/async/storageTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,10 @@ class AssetStorageTest : AsyncTest() {
val storage = AssetStorage(fileResolver = ClasspathFileHandleResolver())
val path = "ktx/assets/async/string.txt"

// When:
val asset = runBlocking { storage.load<String>(path) }

// Then:
assertEquals("Content.", asset)
assertTrue(storage.isLoaded<String>(path))
assertSame(asset, storage.get<String>(path).joinAndGet())
Expand Down Expand Up @@ -590,8 +592,6 @@ class AssetStorageTest : AsyncTest() {
// Then:
assertFalse(storage.isLoaded<Texture>(path))
assertEquals(0, storage.getReferenceCount<Texture>(path))

storage.dispose()
}

@Test
Expand Down Expand Up @@ -663,8 +663,6 @@ class AssetStorageTest : AsyncTest() {
// Then:
assertFalse(storage.isLoaded<Pixmap>(path))
assertEquals(0, storage.getReferenceCount<Pixmap>(path))

storage.dispose()
}

@Test
Expand Down
70 changes: 38 additions & 32 deletions freetype-async/README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,29 @@
[![Maven Central](https://img.shields.io/maven-central/v/io.github.libktx/ktx-freetype-async.svg)](https://search.maven.org/artifact/io.github.libktx/ktx-freetype-async)

# Warning

As of the `1.9.9-b1` version, the `ktx-freetype-async` module is **disabled**, since `AssetStorage` was removed
from `ktx-async`. `AssetStorage` will eventually be refactored to use the new coroutines API and `ktx-freetype-async`
will be enabled. However, until then please use [`ktx-freetype`](../freetype) or a previous **KTX** version instead.

# KTX: FreeType font asynchronous loading utilities

A tiny modules that makes it easier to use [`gdx-freetype`](https://github.com/libgdx/libgdx/wiki/Gdx-freetype) library
along with the coroutines-based `AssetStorage` from [`ktx-async`](../async).
A tiny modules that makes it easier to use [`gdx-freetype`](https://github.com/libgdx/libgdx/wiki/Gdx-freetype)
library along with the coroutines-based `AssetStorage` from [`ktx-assets-async`](../assets-async).

### Why?

`gdx-freetype` requires quite a bit of setup before it can be fully integrated with LibGDX `AssetStorage` due to how
LibGDX `AssetManager` loaders are implemented. This module aims to limit the boilerplate necessary to load FreeType
fonts in LibGDX applications.
`gdx-freetype` requires quite a bit of setup before it can be fully integrated with `AssetManager` or `AssetStorage`
due to how LibGDX `AssetManager` loaders are implemented. This module aims to limit the boilerplate necessary to load
FreeType fonts in LibGDX applications with the asynchronous **KTX** `AssetStorage`.

See also [`ktx-freetype`](../freetype).
See also: [`ktx-freetype`](../freetype).

### Guide

This module consists of the following functions:
This module consists of the following utilities:

* Extension method `AssetStorage.registerFreeTypeFontLoaders` allows to register all loaders required to load FreeType
font assets. It should be called right after constructing a `AssetStorage` instance and before loading any assets.
* Extension method `AssetStorage.loadFreeTypeFont` allows to easily configure loaded `BitmapFont` instances with Kotlin
DSL.

Since it depends on the [`ktx-freetype`](../freetype) module, it also comes with the following functions:
Since it depends on the [`ktx-freetype`](../freetype) module, it also comes with the following utilities that might
prove useful even when using `AssetStorage`:

* `ktx.freetype.freeTypeFontParameters` function is a Kotlin DSL for customizing font loading parameters.
* `FreeTypeFontGenerator.generateFont` extension function allows to generate `BitmapFont` instances using a
Expand All @@ -39,23 +34,25 @@ Since it depends on the [`ktx-freetype`](../freetype) module, it also comes with
Creating `AssetStorage` with registered FreeType font loaders:

```kotlin
import ktx.async.assets.AssetStorage
import ktx.async.enableKtxCoroutines
import ktx.freetype.async.*
import ktx.assets.async.AssetStorage
import ktx.async.KtxAsync
import ktx.freetype.async.registerFreeTypeFontLoaders

fun initiateAssetStorage(): AssetStorage {
// Coroutines have to be enabled. AssetStorage uses an asynchronous executor,
// so concurrency level has to be above 0. See ktx-async documentation.
enableKtxCoroutines(asynchronousExecutorConcurrencyLevel = 1)
// Coroutines have to be enabled.
// This has to be called on the main rendering thread:
KtxAsync.initiate()

val assetStorage = AssetStorage()
// Calling registerFreeTypeFontLoaders is necessary in order to load TTF/OTF files.
// Registering TTF/OTF file loaders:
assetStorage.registerFreeTypeFontLoaders()

// AssetStorage is now ready to load FreeType fonts.
return assetStorage
}
```

Registering `BitmapFont` loaders for custom file extensions:
Registering `BitmapFont` loaders only for custom file extensions:

```kotlin
import ktx.freetype.async.*
Expand All @@ -74,18 +71,26 @@ assetStorage.registerFreeTypeFontLoaders(replaceDefaultBitmapFontLoader = true)
Loading a FreeType font using `AssetStorage` in a coroutine:

```kotlin
import ktx.async.ktxAsync
import ktx.freetype.async.*

ktxAsync {
val font = assetStorage.loadFreeTypeFont("font.ttf")
// font is BitmapFont
import com.badlogic.gdx.graphics.g2d.BitmapFont
import kotlinx.coroutines.launch
import ktx.assets.async.AssetStorage
import ktx.async.KtxAsync
import ktx.freetype.async.loadFreeTypeFont

fun loadFont(assetStorage: AssetStorage) {
// Launching a coroutine:
KtxAsync.launch {
// Loading a font:
val font: BitmapFont = assetStorage.loadFreeTypeFont("font.ttf")
// Font is now ready to use.
}
}
```

Loading a FreeType font with custom parameters using `AssetStorage`:

```kotlin
import com.badlogic.gdx.graphics.Color
import ktx.freetype.async.*

val font = assetStorage.loadFreeTypeFont("font.ttf") {
Expand All @@ -101,7 +106,7 @@ Accessing a fully loaded font:
```kotlin
import com.badlogic.gdx.graphics.g2d.BitmapFont

val font = assetStorage.get<BitmapFont>("font.ttf")
val font = assetStorage.get<BitmapFont>("font.ttf").await()
```

Loading a `FreeTypeFontGenerator`:
Expand Down Expand Up @@ -132,7 +137,7 @@ Generating a new `BitmapFont` using LibGDX `FreeTypeFontGenerator`:
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator
import ktx.freetype.*

val generator: FreeTypeFontGenerator = getGenerator()
val generator: FreeTypeFontGenerator
// Default parameters:
val fontA = generator.generateFont()
// Customized:
Expand All @@ -149,5 +154,6 @@ FreeType font loaders can be registered manually. See

#### Additional documentation

- [`gdx-freetype` article.](https://github.com/libgdx/libgdx/wiki/Gdx-freetype)
- [Official `gdx-freetype` article.](https://github.com/libgdx/libgdx/wiki/Gdx-freetype)
- [`ktx-async` module.](../async)
- [`ktx-assets-async` module.](../assets-async)
4 changes: 3 additions & 1 deletion freetype-async/build.gradle
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
dependencies {
compile project(':async')
compile project(':assets-async')
compile project(':freetype')
provided "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
provided "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"

testCompile project(':async').sourceSets.test.output
testCompile "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$kotlinCoroutinesVersion"
testCompile "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop"
testCompile "com.badlogicgames.gdx:gdx-backend-headless:$gdxVersion"
testCompile "com.badlogicgames.gdx:gdx-backend-lwjgl:$gdxVersion"
testCompile "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
}
50 changes: 29 additions & 21 deletions freetype-async/src/main/kotlin/ktx/freetype/async/freetypeAsync.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,49 @@ import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGeneratorLoader
import com.badlogic.gdx.graphics.g2d.freetype.FreetypeFontLoader
import ktx.async.assets.AssetStorage
import ktx.assets.async.AssetStorage
import ktx.freetype.freeTypeFontParameters

/**
* Registers all loaders necessary to load [BitmapFont] and [FreeTypeFontGenerator] instances from TTF and OTF files.
* @param fileExtensions a collection of supported file extensions. If an empty array is passed, [BitmapFont] loaders
* will not be registered. Defaults to ".ttf" and ".otf".
* @param replaceDefaultBitmapFontLoader if true, default [BitmapFont] loader will be replaced and any attempts to load
* [BitmapFont] will result in use of [FreetypeFontLoader] instead. [fileExtensions] will be ignored and FreeType loader
* will be used by default unless overridden.
* Registers all loaders necessary to load [BitmapFont] and [FreeTypeFontGenerator]
* instances from TTF and OTF files.
*
* [fileExtensions] is a collection of supported file extensions. If an empty array is passed,
* [BitmapFont] loaders will not be registered. Defaults to ".ttf" and ".otf".
*
* If [replaceDefaultBitmapFontLoader] is true, default [BitmapFont] loader will be replaced
* and any attempts to load [BitmapFont] will result in the use of [FreetypeFontLoader] instead.
* [fileExtensions] will be ignored and FreeType loader will be used by default for all font
* assets unless overridden.
*/
fun AssetStorage.registerFreeTypeFontLoaders(
fileExtensions: Array<String> = arrayOf(".ttf", ".otf"),
replaceDefaultBitmapFontLoader: Boolean = false) {
val fontGeneratorLoader = FreeTypeFontGeneratorLoader(fileResolver)
setLoader<FreeTypeFontGenerator>(fontGeneratorLoader)
fileExtensions: Array<String> = arrayOf(".ttf", ".otf"),
replaceDefaultBitmapFontLoader: Boolean = false
) {
setLoader<FreeTypeFontGenerator> { FreeTypeFontGeneratorLoader(fileResolver) }

val fontLoader = FreetypeFontLoader(fileResolver)
if (replaceDefaultBitmapFontLoader) {
setLoader<BitmapFont>(fontLoader)
setLoader<BitmapFont> { FreetypeFontLoader(fileResolver) }
} else {
fileExtensions.forEach { extension ->
setLoader<BitmapFont>(fontLoader, suffix = extension)
setLoader<BitmapFont>(suffix = extension) { FreetypeFontLoader(fileResolver) }
}
}
}

/**
* Allows to customize parameters of a loaded FreeType font.
* @param file path to the FreeType font file.
* @param setup should specify font parameters. Will be invoked on a new instance of [FreeTypeFontParameter]. Inlined.
* @return fully loaded BitmapFont. Note that this method will suspend the current coroutine to perform asynchronous
* font loading.
*
* [path] is the file path to the FreeType font file.
* Must be compatible with the [AssetStorage.fileResolver].
*
* [setup] can be used to specify and customize the parameters of the loaded font.
* It will be inlined and invoked on a [FreeTypeFontParameter].
*
* Returns the result of font loading. See [AssetStorage.load] for lists of possible outcomes.
*/
suspend inline fun AssetStorage.loadFreeTypeFont(
file: String,
setup: FreeTypeFontParameter.() -> Unit = {}): BitmapFont =
load<BitmapFont>(file, parameters = freeTypeFontParameters(file, setup))
path: String,
setup: FreeTypeFontParameter.() -> Unit = {}
): BitmapFont =
load<BitmapFont>(path, parameters = freeTypeFontParameters(path, setup))
Loading

0 comments on commit f0995bf

Please sign in to comment.