sourceSets.main.java.srcDirs = ["src/"] import arc.files.Fi import arc.graphics.Color import arc.graphics.Pixmap import arc.packer.TexturePacker import arc.struct.IntIntMap import arc.struct.IntMap import arc.util.async.Threads import java.util.concurrent.ExecutorService import java.util.concurrent.Executors def genFolder = "../core/assets-raw/sprites_out/generated/" def doAntialias = !project.hasProperty("disableAntialias") def colorMap = new IntMap>(), colorIndexMap = new IntIntMap() //on my machine, I have a native Nim AA implementation that is ~10x faster //it's not compiled for other platforms so they don't get it def useFastAA = project.hasProperty("fastAA") || System.getProperty("user.name") == "anuke" def transformColors = { List> list -> list.each{ colors -> def newColors = [] colors.each{ hexc -> newColors += Color.valueOf(hexc) } newColors.each{ color -> colorMap.put(color.rgba(), newColors) colorIndexMap.put(color.rgba(), newColors.indexOf(color)) } } } //TODO implementing this in gradle is a bad idea //d4816b transformColors([["a387ea", "8a73c6", "5c5e9f"], ["6e7080", "989aa4", "b0bac0"], ["bc5452", "ea8878", "feb380"], ["de9458", "f8c266", "ffe18f"], ["feb380", "ea8878", "bc5452"], ["d4816b", "eab678", "ffd37f"], ["ffffff", "dcc6c6", "9d7f7f"], ["df7646", "b23a4d", "752249"], ["3c3837", "515151", "646567"]]) def antialias = { File file -> if(!doAntialias) return if(useFastAA){ "antialias ${file.absolutePath}".execute().waitFor() return } def image = new Pixmap(new Fi(file)) def out = image.copy() def getRGB = { int ix, int iy -> return image.getRaw(Math.max(Math.min(ix, image.width - 1), 0), Math.max(Math.min(iy, image.height - 1), 0)) } def color = new Color() def sum = new Color() def suma = new Color() int[] p = new int[9] for(int x = 0; x < image.width; x++){ for(int y = 0; y < image.height; y++){ int A = getRGB(x - 1, y + 1), B = getRGB(x, y + 1), C = getRGB(x + 1, y + 1), D = getRGB(x - 1, y), E = getRGB(x, y), F = getRGB(x + 1, y), G = getRGB(x - 1, y - 1), H = getRGB(x, y - 1), I = getRGB(x + 1, y - 1) Arrays.fill(p, E) if(D == B && D != H && B != F) p[0] = D if((D == B && D != H && B != F && E != C) || (B == F && B != D && F != H && E != A)) p[1] = B if(B == F && B != D && F != H) p[2] = F if((H == D && H != F && D != B && E != A) || (D == B && D != H && B != F && E != G)) p[3] = D if((B == F && B != D && F != H && E != I) || (F == H && F != B && H != D && E != C)) p[5] = F if(H == D && H != F && D != B) p[6] = D if((F == H && F != B && H != D && E != G) || (H == D && H != F && D != B && E != I)) p[7] = H if(F == H && F != B && H != D) p[8] = F suma.set(0) for(int val : p){ color.rgba8888(val) suma.r += color.r * color.a suma.g += color.g * color.a suma.b += color.b * color.a suma.a += color.a } float fm = suma.a <= 0.001f ? 0f : (float)(1f / suma.a) suma.mul(fm, fm, fm, fm) float total = 0 sum.set(0) for(int val : p){ color.rgba8888(val) float a = color.a color.lerp(suma, (float) (1f - a)) sum.r += color.r sum.g += color.g sum.b += color.b sum.a += a total += 1f } fm = (float)(1f / total) sum.mul(fm, fm, fm, fm) out.setRaw(x, y, sum.rgba8888()) sum.set(0) } } image.dispose() out.dispose() new Fi(file).writePng(out) } def tileImage = { File file -> def image = new Pixmap(new Fi(file)) for(x in 0..image.width-1){ for(y in 0..image.height-1){ if(x > (image.height - 1 - y)){ def rx = image.height - 1 - y def ry = x image.setRaw(x, y, image.getRaw(rx, image.height - 1 - ry)) } } } def result = new Pixmap(image.width * 2, image.height * 2) result.draw(image.flipX(), 0, 0) result.draw(image, image.width, 0) result.draw(image.flipX().flipY(), 0, image.height) result.draw(image.flipY(), image.width, image.height) for(x in 0..result.width-1){ for(y in 0..result.height-1){ int p = result.getRaw(x, y) if(x <= y){ List list = colorMap.get(p) int index = colorIndexMap.get(p, -1) if(index != -1){ int resultIndex = (x == y ? 1 : index == 2 ? 0 : index == 0 ? 2 : 1); result.setRaw(x, y, list[resultIndex].rgba()) } } } } new Fi(file).writePng(result) result.dispose() image.dispose() } task antialiasImages(){ doLast{ for(def img : project.getProperty("images").split(",")){ println(project.getProperty("startdir") + "/" + img) antialias(new File(project.getProperty("startdir") + "/" + img)) } } } task tileImages(){ doLast{ for(def img : project.getProperty("images").split(",")){ println(project.getProperty("startdir") + "/" + img) tileImage(new File(project.getProperty("startdir") + "/" + img)) } } } task pack(dependsOn: [classes, configurations.runtimeClasspath]){ doLast{ //cleanup old sprites delete{ delete "../core/assets-raw/sprites_out/" } //copy in new sprites copy{ from "../core/assets-raw/sprites/" into "../core/assets-raw/sprites_out/" } //run generation task; generate all needed sprites file(genFolder).mkdirs() javaexec{ main = "mindustry.tools.ImagePacker" classpath = sourceSets.main.runtimeClasspath workingDir = genFolder } copy{ from "../core/assets-raw/sprites_out/ui/icons" into "../core/assets-raw/sprites_out/ui/" } delete{ delete "../core/assets-raw/sprites_out/ui/icons" } ExecutorService executor = Executors.newFixedThreadPool(16) long ms = System.currentTimeMillis() //antialias everything except UI elements fileTree(dir: new File(rootDir, 'core/assets-raw/sprites_out/').absolutePath, include: "**/*.png").visit{ file -> if(file.isDirectory() || (file.toString().replace("\\", "/").contains("/ui/") && file.toString().startsWith("icon-")) || file.toString().contains(".9.png")) return executor.submit{ antialias(file.file) } } Threads.await(executor) println "Time taken for AA: ${(System.currentTimeMillis() - ms) / 1000f}" println("\n\nPacking normal 4096 sprites...\n\n") //pack normal sprites TexturePacker.process(new File(rootDir, "core/assets-raw/sprites_out/").absolutePath, new File(rootDir, "core/assets/sprites/").absolutePath, "sprites.aatls") println("\n\nPacking fallback 2048 sprites...\n\n") //replace config file contents fileTree(dir: '../core/assets-raw/sprites_out/', include: "**/*.json").visit{ file -> if(!file.isDirectory()) file.file.text = file.file.text.replace("4096", "2048") } //pack fallback 2048x2048 sprites TexturePacker.process(new File(rootDir, "core/assets-raw/sprites_out/").absolutePath, new File(rootDir, "core/assets/sprites/fallback/").absolutePath, "sprites.aatls") } } task genSprites(dependsOn: classes, type: JavaExec){ finalizedBy 'antialiasGen' main = "mindustry.tools.ImagePacker" classpath = sourceSets.main.runtimeClasspath standardInput = System.in workingDir = genFolder } task updateBundles(dependsOn: classes, type: JavaExec){ file(genFolder).mkdirs() main = "mindustry.tools.BundleLauncher" classpath = sourceSets.main.runtimeClasspath standardInput = System.in workingDir = "../core/assets/bundles/" } task fontgen(dependsOn: classes, type: JavaExec){ main = "mindustry.tools.FontGenerator" classpath = sourceSets.main.runtimeClasspath standardInput = System.in workingDir = "../" } task icongen(dependsOn: classes, type: JavaExec){ main = "mindustry.tools.IconConverter" classpath = sourceSets.main.runtimeClasspath standardInput = System.in workingDir = "../core/assets-raw" } task updateScripts(dependsOn: classes, type: JavaExec){ main = "mindustry.tools.ScriptMainGenerator" classpath = sourceSets.main.runtimeClasspath standardInput = System.in workingDir = "../" }