-
Notifications
You must be signed in to change notification settings - Fork 56
Texture Manipulation
Open a texture, take its colors apart, and build a new one out of them, in code, at load time.
This is what feeds Runtime Resource Packs. The usual job is "make a version of this texture in every wood color that's installed": extract the palette of the target wood, then repaint your template with it.
The pieces:
-
TextureImage, aNativeImageplus its mcmeta, so animated textures keep working. Read and write pixels per frame, copy, crop, mask, rotate, resize, grayscale, overlay, or turn a still into an animation. -
Palette, the colors of an image sorted by luminance, with everything you need to reshape it: add a brighter color, add one in between, merge the two closest, match a target size or luminance step. Colors are the ones from Colors, so you can work in HSL or LAB and come back. -
Respriter, which keeps the shape of one texture and swaps in the colors of a palette. -
TextureCollager, which copies rectangles between images with flips, rotations and scaling. -
RPUtils, which digs a block's actual texture path out of its models, since you rarely know it up front.
try (TextureImage stone = TextureImage.open(manager, ResourceLocation.parse("block/stone"));
TextureImage deepslate = TextureImage.open(manager, ResourceLocation.parse("block/deepslate"))) {
// keeps the shape of stone, takes colors from whatever you feed it
Respriter respriter = Respriter.of(stone);
Palette palette = Palette.fromImage(deepslate);
palette.remove(palette.getDarkest());
if (palette.getLuminanceSpan() < 0.2) palette.increaseUp();
TextureImage recolored = respriter.recolor(palette);
recolored.setFramePixel(0, 1, 1, 0xff0000ff);
return recolored; // caller closes it
}Finding a texture you don't know the path of:
ResourceLocation tex = RPUtils.findFirstBlockTextureLocation(manager, Blocks.DIAMOND_BLOCK);Collaging, built once and applied many times:
TextureCollager collager = TextureCollager.builder(16, 16, 16, 16)
.copyFrom(6, 6, 4, 4).to(12, 0).flippedX()
.copyFrom(0, 0, 4, 5).to(2, 3).rotated(Rotation.CLOCKWISE_90)
.build();
collager.apply(emerald, myImage);Warning
TextureImage holds native memory. Always try with resources, or hand it to
ResourceSink.addAndCloseTexture(...) which closes it for you. Leaks here are real leaks.
Examples: TextureUtilsExample, PaletteExample
SpriteUtils can guess a sign or wooden item palette from a planks texture
(extrapolateSignBlockPalette, extrapolateWoodItemPalette), which is how wood variants of complex
textures get generated. It also has reduceColors and mergeSimilarColors.
KMeans clusters colors when plain palette extraction is too coarse.
Basics Platform Helpers Registration Networking Events Configs Config Screen
Resources Runtime Resource Packs Texture Manipulation Resource Helpers Block Set API
Client Custom Models Item Rendering Rendered Textures Post Shaders GUI Toolkit Colors
World Block and Item Interfaces Additional Item Placements Improved Entities Fake Levels World Data Dispenser Behaviors
Utilities Codec Utilities Misc Helpers Commands
Datapacks Villagers Soft Fluids Map Markers Spawn Boxes Global Datapack Folder