[WIP] start 1.15 port

reorganize packages to match Fabric version
use util classes from Fabric version
This commit is contained in:
octarine-noise
2021-05-01 13:52:21 +02:00
parent 9566ae8341
commit 09ccb83e8b
81 changed files with 1220 additions and 1011 deletions
@@ -0,0 +1,39 @@
package mods.betterfoliage.resource.generated
import mods.betterfoliage.resource.Identifier
import mods.betterfoliage.texture.loadSprite
import mods.betterfoliage.util.Atlas
import mods.betterfoliage.util.bytes
import net.minecraft.resources.IResourceManager
import java.awt.image.BufferedImage
import java.lang.Math.max
data class CenteredSprite(val sprite: Identifier, val atlas: Atlas = Atlas.BLOCKS, val aspectHeight: Int = 1, val aspectWidth: Int = 1) {
fun register(pack: GeneratedBlockTexturePack) = pack.register(this, this::draw)
fun draw(resourceManager: IResourceManager): ByteArray {
val baseTexture = resourceManager.loadSprite(atlas.wrap(sprite))
val frameWidth = baseTexture.width
val frameHeight = baseTexture.width * aspectHeight / aspectWidth
val frames = baseTexture.height / frameHeight
val size = max(frameWidth, frameHeight)
val resultTexture = BufferedImage(size, size * frames, BufferedImage.TYPE_4BYTE_ABGR)
val graphics = resultTexture.createGraphics()
// iterate all frames
for (frame in 0 until frames) {
val baseFrame = baseTexture.getSubimage(0, size * frame, frameWidth, frameHeight)
val resultFrame = BufferedImage(size, size, BufferedImage.TYPE_4BYTE_ABGR)
resultFrame.createGraphics().apply {
drawImage(baseFrame, (size - frameWidth) / 2, (size - frameHeight) / 2, null)
}
graphics.drawImage(resultFrame, 0, size * frame, null)
}
return resultTexture.bytes
}
}
@@ -0,0 +1,56 @@
package mods.betterfoliage.resource.generated
import mods.betterfoliage.resource.Identifier
import mods.betterfoliage.texture.blendRGB
import mods.betterfoliage.texture.loadSprite
import mods.betterfoliage.util.Atlas
import mods.betterfoliage.util.bytes
import mods.betterfoliage.util.get
import mods.betterfoliage.util.set
import mods.octarinecore.client.resource.*
import net.minecraft.resources.IResourceManager
import java.awt.image.BufferedImage
/**
* Generate Short Grass textures from [Blocks.tallgrass] block textures.
* The bottom 3/8 of the base texture is chopped off.
*
* @param[domain] Resource domain of generator
*/
data class GeneratedGrass(val sprite: Identifier, val isSnowed: Boolean, val atlas: Atlas = Atlas.BLOCKS) {
constructor(sprite: String, isSnowed: Boolean) : this(Identifier(sprite), isSnowed)
fun register(pack: GeneratedBlockTexturePack) = pack.register(this, this::draw)
fun draw(resourceManager: IResourceManager): ByteArray {
val baseTexture = resourceManager.loadSprite(atlas.wrap(sprite))
val result = BufferedImage(baseTexture.width, baseTexture.height, BufferedImage.TYPE_4BYTE_ABGR)
val graphics = result.createGraphics()
val size = baseTexture.width
val frames = baseTexture.height / size
// iterate all frames
for (frame in 0 until frames) {
val baseFrame = baseTexture.getSubimage(0, size * frame, size, size)
val grassFrame = BufferedImage(size, size, BufferedImage.TYPE_4BYTE_ABGR)
// draw bottom half of texture
grassFrame.createGraphics().apply {
drawImage(baseFrame, 0, 3 * size / 8, null)
}
// add to animated png
graphics.drawImage(grassFrame, 0, size * frame, null)
}
// blend with white if snowed
if (isSnowed) {
for (x in 0..result.width - 1) for (y in 0..result.height - 1) {
result[x, y] = blendRGB(result[x, y], 16777215, 2, 3)
}
}
return result.bytes
}
}
@@ -0,0 +1,93 @@
package mods.betterfoliage.resource.generated
import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.texture.loadSprite
import mods.betterfoliage.util.Atlas
import mods.betterfoliage.util.bytes
import mods.betterfoliage.util.get
import mods.betterfoliage.util.loadImage
import mods.betterfoliage.util.resourceManager
import mods.betterfoliage.util.set
import mods.octarinecore.client.resource.*
import net.minecraft.resources.IResource
import net.minecraft.resources.IResourceManager
import net.minecraft.util.ResourceLocation
import java.awt.image.BufferedImage
/**
* Generate round leaf textures from leaf block textures.
* The base texture is tiled 2x2, then parts of it are made transparent by applying a mask to the alpha channel.
*
* Different leaf types may have their own alpha mask.
*
* @param[domain] Resource domain of generator
*/
data class GeneratedLeaf(val sprite: ResourceLocation, val leafType: String, val atlas: Atlas = Atlas.BLOCKS) {
fun register(pack: GeneratedBlockTexturePack) = pack.register(this, this::draw)
fun draw(resourceManager: IResourceManager): ByteArray {
val baseTexture = resourceManager.loadSprite(atlas.wrap(sprite))
val size = baseTexture.width
val frames = baseTexture.height / size
val maskTexture = (getLeafMask(leafType, size * 2) ?: getLeafMask("default", size * 2))?.loadImage()
fun scale(i: Int) = i * maskTexture!!.width / (size * 2)
val leafTexture = BufferedImage(size * 2, size * 2 * frames, BufferedImage.TYPE_4BYTE_ABGR)
val graphics = leafTexture.createGraphics()
// iterate all frames
for (frame in 0 until frames) {
val baseFrame = baseTexture.getSubimage(0, size * frame, size, size)
val leafFrame = BufferedImage(size * 2, size * 2, BufferedImage.TYPE_4BYTE_ABGR)
// tile leaf texture 2x2
leafFrame.createGraphics().apply {
drawImage(baseFrame, 0, 0, null)
drawImage(baseFrame, 0, size, null)
drawImage(baseFrame, size, 0, null)
drawImage(baseFrame, size, size, null)
}
// overlay alpha mask
if (maskTexture != null) {
for (x in 0 until size * 2) for (y in 0 until size * 2) {
val basePixel = leafFrame[x, y].toLong() and 0xFFFFFFFFL
val maskPixel = maskTexture[scale(x), scale(y)].toLong() and 0xFF000000L or 0xFFFFFFL
leafFrame[x, y] = (basePixel and maskPixel).toInt()
}
}
// add to animated png
graphics.drawImage(leafFrame, 0, size * frame * 2, null)
}
return leafTexture.bytes
}
/**
* Get the alpha mask to use
*
* @param[type] Alpha mask type.
* @param[maxSize] Preferred mask size.
*/
fun getLeafMask(type: String, maxSize: Int) = getMultisizeTexture(maxSize) { size ->
ResourceLocation(BetterFoliageMod.MOD_ID, "textures/blocks/leafmask_${size}_${type}.png")
}
/**
* Get a texture resource when multiple sizes may exist.
*
* @param[maxSize] Maximum size to consider. This value is progressively halved when searching for smaller versions.
* @param[maskPath] Location of the texture of the given size
*
*/
fun getMultisizeTexture(maxSize: Int, maskPath: (Int)->ResourceLocation): IResource? {
var size = maxSize
val sizes = mutableListOf<Int>()
while(size > 2) { sizes.add(size); size /= 2 }
return sizes.map { resourceManager[maskPath(it)] }.filterNotNull().firstOrNull()
}
}
@@ -0,0 +1,90 @@
package mods.betterfoliage.resource.generated
import mods.betterfoliage.resource.Identifier
import mods.betterfoliage.util.Atlas
import mods.betterfoliage.util.HasLogger
import mods.betterfoliage.util.completedVoid
import mods.betterfoliage.util.map
import mods.octarinecore.client.resource.AsyncSpriteProvider
import mods.octarinecore.client.resource.AtlasFuture
import mods.octarinecore.client.resource.StitchPhases
import net.minecraft.client.renderer.model.ModelBakery
import net.minecraft.client.resources.ClientResourcePackInfo
import net.minecraft.resources.*
import net.minecraft.resources.ResourcePackType.CLIENT_RESOURCES
import net.minecraft.resources.data.IMetadataSectionSerializer
import net.minecraft.util.text.StringTextComponent
import org.apache.logging.log4j.Logger
import java.io.IOException
import java.util.*
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ExecutionException
import java.util.function.Predicate
import java.util.function.Supplier
/**
* [IResourcePack] containing generated resources
*
* @param[name] Name of the resource pack
* @param[generators] List of resource generators
*/
class GeneratedBlockTexturePack(val nameSpace: String, val packName: String, override val logger: Logger) : HasLogger, IResourcePack,
AsyncSpriteProvider<ModelBakery> {
override fun getName() = packName
override fun getResourceNamespaces(type: ResourcePackType) = setOf(nameSpace)
override fun <T : Any?> getMetadata(deserializer: IMetadataSectionSerializer<T>) = null
override fun getRootResourceStream(id: String) = null
override fun getAllResourceLocations(type: ResourcePackType, namespace:String, path: String, maxDepth: Int, filter: Predicate<String>) = emptyList<Identifier>()
override fun close() {}
protected var manager: CompletableFuture<IResourceManager>? = null
val identifiers = Collections.synchronizedMap(mutableMapOf<Any, Identifier>())
val resources = Collections.synchronizedMap(mutableMapOf<Identifier, CompletableFuture<ByteArray>>())
fun register(key: Any, func: (IResourceManager)->ByteArray): Identifier {
if (manager == null) throw IllegalStateException("Cannot register resources unless block textures are being reloaded")
identifiers[key]?.let { return it }
val id = Identifier(nameSpace, UUID.randomUUID().toString())
val resource = manager!!.map { func(it) }
identifiers[key] = id
resources[Atlas.BLOCKS.wrap(id)] = resource
log("generated resource $key -> $id")
return id
}
override fun getResourceStream(type: ResourcePackType, id: Identifier) =
if (type != CLIENT_RESOURCES) null else
try { resources[id]!!.get().inputStream() }
catch (e: ExecutionException) { (e.cause as? IOException)?.let { throw it } } // rethrow wrapped IOException if present
override fun resourceExists(type: ResourcePackType, id: Identifier) =
type == CLIENT_RESOURCES && resources.containsKey(id)
override fun setup(manager: IResourceManager, bakeryF: CompletableFuture<ModelBakery>, atlas: AtlasFuture): StitchPhases {
this.manager = CompletableFuture.completedFuture(manager)
return StitchPhases(
completedVoid(),
atlas.runAfter {
this.manager = null
identifiers.clear()
resources.clear()
}
)
}
val finder = object : IPackFinder {
val packInfo = ClientResourcePackInfo(
packName, true, Supplier { this@GeneratedBlockTexturePack },
StringTextComponent(packName),
StringTextComponent("Generated block textures resource pack"),
PackCompatibility.COMPATIBLE, ResourcePackInfo.Priority.TOP, true, null, true
)
override fun <T : ResourcePackInfo> addPackInfosToMap(nameToPackMap: MutableMap<String, T>, packInfoFactory: ResourcePackInfo.IFactory<T>) {
(nameToPackMap as MutableMap<String, ResourcePackInfo>).put(packName, packInfo)
}
}
}