Files
BetterLeavesLite/src/texture_generator.py
2025-07-20 16:41:26 +02:00

78 lines
4.0 KiB
Python

import json
import os
import random
from PIL import Image
# Local imports
from src.texturepack_utils import scanPacksForTexture
from src.utilities import printOverride
def generateTexture(root, infile, useProgrammerArt=False):
outfolder = root.replace("assets", "").replace("input", "assets")
os.makedirs(outfolder, exist_ok=True)
# Check for texture stitching data
textureMap = createTextureMap(root, infile, useProgrammerArt)
root = scanPacksForTexture(root, infile)
if useProgrammerArt: root = scanPacksForTexture(root, infile, "./input/programmer_art")
outfile = os.path.splitext(os.path.join(outfolder, infile))[0] + ".png"
if infile != outfile:
try:
stitchTexture(textureMap, root, infile, outfile)
except IOError:
print("Error while generating texture for '%s'" % infile)
def createTextureMap(root, infile, useProgrammerArt):
textureMap = {}
if os.path.isfile(os.path.join(root, infile.replace(".png", ".betterleaves.json"))):
with open(os.path.join(root, infile.replace(".png", ".betterleaves.json")), "r") as f:
json_data = json.load(f)
if "textureStitching" in json_data:
printOverride("Using texture stitching data from: " + f.name)
# Create texture map from stitching data
for key, value in json_data["textureStitching"].items():
if "-" in key:
for i in range(int(key.split("-")[0]), int(key.split("-")[1])+1): textureMap[str(i)] = value
else: textureMap[key] = value
# Turn texture map into absolute paths
for key, value in textureMap.items():
textureRoot = f"./input/assets/{value.split(':')[0]}/textures/"
textureFile = value.split(":")[1] + ".png"
if "/" in textureFile:
textureRoot += textureFile.rsplit("/")[0]
textureFile = textureFile[len(textureFile.rsplit("/")[0])+1:] # The rest of the string, starting behind the first '/'
textureRoot = scanPacksForTexture(textureRoot, textureFile)
if useProgrammerArt: root = scanPacksForTexture(textureRoot, textureFile, "./input/programmer_art")
textureMap[key] = os.path.join(textureRoot, textureFile)
return textureMap
def stitchTexture(textureMap, root, infile, outfile):
# First, let's open the regular texture
vanilla = Image.open(os.path.join(root, infile))
width, height = vanilla.size
# Second, let's generate a transparent texture that's twice the size
transparent = Image.new("RGBA", [int(2 * s) for s in vanilla.size], (255, 255, 255, 0))
out = transparent.copy()
# Now we paste the regular texture in a 3x3 grid, centered in the middle
for x in range(-1, 2):
for y in range(-1, 2):
texture = vanilla
index = (x + 2) + (y + 1) * 3 # Turns coordinates into a number from 1 to 9
if str(index) in textureMap: # Load texture from texture stitching map
texture = Image.open(textureMap[str(index)])
out.paste(texture, (int(width / 2 + width * x), int(height / 2 + height * y)))
# As the last step, we apply our custom mask to round the edges and smoothen things out
mask_location = f"input/masks/{width}px" # If possible, use a mask designed for the texture's size
if not os.path.isdir(mask_location) or len(os.listdir(mask_location)) == 0: mask_location = "input/masks/16px"
random.seed(infile) # Use the filename as a seed. This ensures we always get the same mask per block.
mask_location += f"/{random.choice(os.listdir(mask_location))}" # Choose a random mask to get some variation between the different types of leaves
mask = Image.open(mask_location).convert('L').resize(out.size, resample=Image.NEAREST)
out = Image.composite(out, transparent, mask)
# Finally, we save the texture to the assets folder
out.save(outfile, vanilla.format)