1
0
mirror of https://github.com/GeyserMC/Rainbow.git synced 2025-12-19 14:59:16 +00:00

Clear stitched texture memory data before writing, don't stitch duplicate textures

This commit is contained in:
Eclipse
2025-10-16 06:03:39 +00:00
parent 0ccc78e827
commit 0c4a877220
2 changed files with 3 additions and 65 deletions

View File

@@ -1,33 +1,14 @@
package org.geysermc.rainbow.client;
import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.brigadier.arguments.StringArgumentType;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.command.v2.ArgumentTypeRegistry;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.Util;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.SpriteContents;
import net.minecraft.client.renderer.texture.SpriteLoader;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.metadata.animation.FrameSize;
import net.minecraft.commands.synchronization.SingletonArgumentInfo;
import net.minecraft.data.AtlasIds;
import net.minecraft.resources.ResourceLocation;
import org.geysermc.rainbow.Rainbow;
import org.geysermc.rainbow.client.command.CommandSuggestionsArgumentType;
import org.geysermc.rainbow.client.command.PackGeneratorCommand;
import org.geysermc.rainbow.client.mapper.PackMapper;
import org.geysermc.rainbow.mixin.SpriteContentsAccessor;
import org.geysermc.rainbow.mixin.SpriteLoaderAccessor;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
public class RainbowClient implements ClientModInitializer {
@@ -37,53 +18,10 @@ public class RainbowClient implements ClientModInitializer {
// TODO export language overrides
@Override
public void onInitializeClient() {
ClientCommandRegistrationCallback.EVENT.register((dispatcher, buildContext) -> {
PackGeneratorCommand.register(dispatcher, packManager, packMapper);
dispatcher.register(
ClientCommandManager.literal("DEBUGTEST")
.then(ClientCommandManager.argument("textures", StringArgumentType.greedyString())
.executes(context -> {
SpriteLoader spriteLoader = new SpriteLoader(AtlasIds.BLOCKS, 1024, 16, 16);
List<SpriteContents> sprites = Arrays.stream(StringArgumentType.getString(context, "textures").split(" "))
.map(ResourceLocation::tryParse)
.map(RainbowClient::readSpriteContents)
.toList();
SpriteLoader.Preparations preparations = ((SpriteLoaderAccessor) spriteLoader).invokeStitch(sprites, 0, Util.backgroundExecutor());
try (NativeImage stitched = stitchTextureAtlas(preparations)) {
stitched.writeToFile(FabricLoader.getInstance().getGameDir().resolve("test.png"));
} catch (IOException exception) {
throw new RuntimeException(exception);
}
return 0;
})
)
);
});
ClientCommandRegistrationCallback.EVENT.register((dispatcher, buildContext) -> PackGeneratorCommand.register(dispatcher, packManager, packMapper));
ClientTickEvents.START_CLIENT_TICK.register(packMapper::tick);
ArgumentTypeRegistry.registerArgumentType(Rainbow.getModdedLocation("command_suggestions"),
CommandSuggestionsArgumentType.class, SingletonArgumentInfo.contextFree(CommandSuggestionsArgumentType::new));
}
private static SpriteContents readSpriteContents(ResourceLocation location) {
try (InputStream textureStream = Minecraft.getInstance().getResourceManager().open(location.withPath(path -> "textures/" + path + ".png"))) {
NativeImage texture = NativeImage.read(textureStream);
return new SpriteContents(location, new FrameSize(texture.getWidth(), texture.getHeight()), texture);
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
private static NativeImage stitchTextureAtlas(SpriteLoader.Preparations preparations) {
NativeImage stitched = new NativeImage(preparations.width(), preparations.height(), false);
for (TextureAtlasSprite sprite : preparations.regions().values()) {
try (SpriteContents contents = sprite.contents()) {
((SpriteContentsAccessor) contents).getOriginalImage().copyRect(stitched, 0, 0,
sprite.getX(), sprite.getY(), contents.width(), contents.height(), false, false);
}
}
return stitched;
}
}

View File

@@ -48,7 +48,7 @@ public record StitchedTextures(Map<String, TextureAtlasSprite> sprites, Supplier
// Atlas ID doesn't matter much here, but BLOCKS is the most appropriate
// Not sure if 1024 should be the max supported texture size, but it seems to work
SpriteLoader spriteLoader = new SpriteLoader(AtlasIds.BLOCKS, 1024, 16, 16);
List<SpriteContents> sprites = textures.map(StitchedTextures::readSpriteContents).toList();
List<SpriteContents> sprites = textures.distinct().map(StitchedTextures::readSpriteContents).toList();
return ((SpriteLoaderAccessor) spriteLoader).invokeStitch(sprites, 0, Util.backgroundExecutor());
}
@@ -65,7 +65,7 @@ public record StitchedTextures(Map<String, TextureAtlasSprite> sprites, Supplier
}
private static NativeImage stitchTextureAtlas(SpriteLoader.Preparations preparations) {
NativeImage stitched = new NativeImage(preparations.width(), preparations.height(), false);
NativeImage stitched = new NativeImage(preparations.width(), preparations.height(), true);
for (TextureAtlasSprite sprite : preparations.regions().values()) {
try (SpriteContents contents = sprite.contents()) {
((SpriteContentsAccessor) contents).getOriginalImage().copyRect(stitched, 0, 0,