mirror of
https://github.com/yairm210/Unciv.git
synced 2025-01-31 01:44:45 +07:00
Added gradle task of Atlas texture packing for Android build (#8208)
* Added gradle task of Atlas texture packing for Android build * ImagePackers check also for creation date Co-authored-by: tunerzinc@gmail.com <vfylfhby>
This commit is contained in:
parent
dd5a242743
commit
0aa7c0e79b
@ -1,5 +1,6 @@
|
||||
import com.unciv.build.BuildConfig
|
||||
import java.util.*
|
||||
import com.unciv.build.AndroidImagePacker
|
||||
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
@ -75,6 +76,12 @@ android {
|
||||
buildToolsVersion = "32.0.0"
|
||||
}
|
||||
|
||||
task("texturePacker") {
|
||||
doFirst {
|
||||
logger.info("Calling TexturePacker")
|
||||
AndroidImagePacker.packImages(projectDir.path,false)
|
||||
}
|
||||
}
|
||||
|
||||
// called every time gradle gets executed, takes the native dependencies of
|
||||
// the natives configuration, and extracts them to the proper libs/ folders
|
||||
@ -96,6 +103,7 @@ task("copyAndroidNatives") {
|
||||
}
|
||||
}
|
||||
}
|
||||
dependsOn("texturePacker")
|
||||
}
|
||||
|
||||
tasks.whenTaskAdded {
|
||||
|
@ -4,4 +4,10 @@ plugins {
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("com.badlogicgames.gdx:gdx-tools:1.11.0") {
|
||||
exclude("com.badlogicgames.gdx", "gdx-backend-lwjgl")
|
||||
}
|
||||
}
|
||||
|
132
buildSrc/src/main/kotlin/AndroidImagePacker.kt
Normal file
132
buildSrc/src/main/kotlin/AndroidImagePacker.kt
Normal file
@ -0,0 +1,132 @@
|
||||
package com.unciv.build
|
||||
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.tools.texturepacker.TexturePacker
|
||||
import com.badlogic.gdx.utils.Json
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.attribute.BasicFileAttributes
|
||||
|
||||
/**
|
||||
* Entry point: _ImagePacker.[packImages] ()_
|
||||
*
|
||||
* Re-packs our texture assets into atlas + png File pairs, which will be loaded by the game.
|
||||
* With the exception of the ExtraImages folder and the Font system these are the only
|
||||
* graphics used (The source Image folders are unused at run time except here).
|
||||
*
|
||||
* [TexturePacker] documentation is [here](https://github.com/libgdx/libgdx/wiki/Texture-packer)
|
||||
*/
|
||||
object AndroidImagePacker {
|
||||
private fun getDefaultSettings() = TexturePacker.Settings().apply {
|
||||
// Apparently some chipsets, like NVIDIA Tegra 3 graphics chipset (used in Asus TF700T tablet),
|
||||
// don't support non-power-of-two texture sizes - kudos @yuroller!
|
||||
// https://github.com/yairm210/Unciv/issues/1340
|
||||
|
||||
/**
|
||||
* These should be as big as possible in order to accommodate ALL the images together in one big file.
|
||||
* Why? Because the rendering function of the main screen renders all the images consecutively, and every time it needs to switch between textures,
|
||||
* this causes a delay, leading to horrible lag if there are enough switches.
|
||||
* The cost of this specific solution is that the entire game.png needs be be kept in-memory constantly.
|
||||
* Now here we come to what Fred Colon would call an Imp Arse.
|
||||
* On the one hand, certain tilesets (ahem 5hex ahem) are really big.
|
||||
* You wouldn't believe how hugely mindbogglingly big they are. So theoretically we should want all of their images to be together.
|
||||
* HOWEVER certain chipsets (see https://github.com/yairm210/Unciv/issues/3330) only seem to support to up to 2048 width*height so this is maximum we can have.
|
||||
* Practically this means that big custom tilesets will have to reload the texture a lot when covering the map and so the
|
||||
* panning on the map will tend to lag a lot :(
|
||||
*
|
||||
* TL;DR this should be 2048.
|
||||
*/
|
||||
maxWidth = 2048
|
||||
maxHeight = 2048
|
||||
|
||||
// Trying to disable the subdirectory combine lead to even worse results. Don't.
|
||||
combineSubdirectories = true
|
||||
pot = true // powers of two only for width/height
|
||||
fast = true // with pot on this just sorts by width
|
||||
// settings.rotation - do not set. Allows rotation, potentially packing tighter.
|
||||
// Proper rendering is mostly automatic - except borders which overwrite rotation.
|
||||
|
||||
// Set some additional padding and enable duplicatePadding to prevent image edges from bleeding into each other due to mipmapping
|
||||
paddingX = 8
|
||||
paddingY = 8
|
||||
duplicatePadding = true
|
||||
filterMin = Texture.TextureFilter.MipMapLinearLinear
|
||||
filterMag = Texture.TextureFilter.MipMapLinearLinear // I'm pretty sure this doesn't make sense for magnification, but setting it to Linear gives strange results
|
||||
}
|
||||
|
||||
fun packImages(workingPath: String, isRunFromJAR:Boolean) {
|
||||
val defaultSettings = getDefaultSettings()
|
||||
|
||||
// Scan for Image folders and build one atlas each
|
||||
packImagesPerMod(workingPath, "$workingPath/assets/", defaultSettings)
|
||||
|
||||
// pack for mods
|
||||
val modDirectory = File("mods")
|
||||
if (modDirectory.exists()) {
|
||||
for (mod in modDirectory.listFiles()!!) {
|
||||
if (!mod.isHidden) {
|
||||
try {
|
||||
packImagesPerMod(mod.path, mod.path, defaultSettings)
|
||||
} catch (ex: Throwable) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Scan multiple image folders and generate an atlas for each - if outdated
|
||||
private fun packImagesPerMod(input: String, output: String, defaultSettings: TexturePacker.Settings) {
|
||||
if (!File("$input${File.separator}Images").exists()) return // So we don't run this from within a fat JAR
|
||||
val atlasList = mutableListOf<String>()
|
||||
for ((file, packFileName) in imageFolders(input)) {
|
||||
atlasList += packFileName
|
||||
packImagesIfOutdated(defaultSettings, file, output, packFileName)
|
||||
}
|
||||
atlasList.remove("game")
|
||||
val listFile = File("$output${File.separator}Atlases.json")
|
||||
if (atlasList.isEmpty()) listFile.delete()
|
||||
else listFile.writeText(atlasList.sorted().joinToString(",","[","]"))
|
||||
}
|
||||
|
||||
// Process one Image folder, checking for atlas older than contained images first
|
||||
private fun packImagesIfOutdated(defaultSettings: TexturePacker.Settings, input: String, output: String, packFileName: String) {
|
||||
fun File.listTree(): Sequence<File> = when {
|
||||
this.isFile -> sequenceOf(this)
|
||||
this.isDirectory -> this.listFiles()!!.asSequence().flatMap { it.listTree() }
|
||||
else -> sequenceOf()
|
||||
}
|
||||
|
||||
// Check if outdated
|
||||
val atlasFile = File("$output${File.separator}$packFileName.atlas")
|
||||
if (atlasFile.exists() && File("$output${File.separator}$packFileName.png").exists()) {
|
||||
val atlasModTime = atlasFile.lastModified()
|
||||
if (File(input).listTree().none {
|
||||
val attr: BasicFileAttributes = Files.readAttributes(it.toPath(), BasicFileAttributes::class.java)
|
||||
val createdAt: Long = attr.creationTime().toMillis()
|
||||
it.extension in listOf("png", "jpg", "jpeg")
|
||||
&& (it.lastModified() > atlasModTime || createdAt > atlasModTime)
|
||||
}) return
|
||||
}
|
||||
|
||||
// An image folder can optionally have a TexturePacker settings file
|
||||
val settingsFile = File("$input${File.separator}TexturePacker.settings")
|
||||
val settings = if (settingsFile.exists())
|
||||
Json().fromJson(TexturePacker.Settings::class.java, settingsFile.reader())
|
||||
else defaultSettings
|
||||
|
||||
TexturePacker.process(settings, input, output, packFileName)
|
||||
}
|
||||
|
||||
// Iterator providing all Image folders to process with the destination atlas name
|
||||
private data class ImageFolderResult(val folder: String, val atlasName: String)
|
||||
private fun imageFolders(path: String) = sequence {
|
||||
val parent = File(path)
|
||||
for (folder in parent.listFiles()!!) {
|
||||
if (!folder.isDirectory) continue
|
||||
if (folder.nameWithoutExtension != "Images") continue
|
||||
val atlasName = if (folder.name == "Images") "game" else folder.extension
|
||||
yield(ImageFolderResult(folder.path, atlasName))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ import com.unciv.app.desktop.ImagePacker.packImages
|
||||
import com.unciv.utils.Log
|
||||
import com.unciv.utils.debug
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.attribute.BasicFileAttributes
|
||||
|
||||
/**
|
||||
* Entry point: _ImagePacker.[packImages] ()_
|
||||
@ -108,7 +110,12 @@ internal object ImagePacker {
|
||||
val atlasFile = File("$output${File.separator}$packFileName.atlas")
|
||||
if (atlasFile.exists() && File("$output${File.separator}$packFileName.png").exists()) {
|
||||
val atlasModTime = atlasFile.lastModified()
|
||||
if (File(input).listTree().none { it.extension in listOf("png", "jpg", "jpeg") && it.lastModified() > atlasModTime }) return
|
||||
if (File(input).listTree().none {
|
||||
val attr: BasicFileAttributes = Files.readAttributes(it.toPath(), BasicFileAttributes::class.java)
|
||||
val createdAt: Long = attr.creationTime().toMillis()
|
||||
it.extension in listOf("png", "jpg", "jpeg")
|
||||
&& (it.lastModified() > atlasModTime || createdAt > atlasModTime)
|
||||
}) return
|
||||
}
|
||||
|
||||
// An image folder can optionally have a TexturePacker settings file
|
||||
|
Loading…
Reference in New Issue
Block a user