Port faster texture stitching by SuperCoder79
This commit is contained in:
parent
749c4e1d9d
commit
cb6399e820
|
|
@ -44,6 +44,7 @@ public class ModernFixEarlyConfig {
|
|||
this.addMixinRule("perf.cache_model_materials", true);
|
||||
this.addMixinRule("perf.datapack_reload_exceptions", true);
|
||||
this.addMixinRule("perf.async_locator", true);
|
||||
this.addMixinRule("perf.faster_texture_stitching", true);
|
||||
this.addMixinRule("perf.kubejs", true);
|
||||
/* Keep this off if JEI isn't installed to prevent breaking vanilla gameplay */
|
||||
this.addMixinRule("perf.blast_search_trees", FMLLoader.getLoadingModList().getModFileById("jei") != null);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
package org.embeddedt.modernfix.mixin.perf.faster_texture_stitching;
|
||||
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import net.minecraft.client.renderer.texture.Stitcher;
|
||||
import org.embeddedt.modernfix.textures.StbStitcher;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Mixin(Stitcher.class)
|
||||
public class StitcherMixin {
|
||||
@Shadow @Final private Set<Stitcher.Holder> texturesToBeStitched;
|
||||
|
||||
@Shadow private int storageX;
|
||||
|
||||
@Shadow private int storageY;
|
||||
|
||||
@Shadow @Final private static Comparator<Stitcher.Holder> HOLDER_COMPARATOR;
|
||||
private List<StbStitcher.LoadableSpriteInfo> loadableSpriteInfos;
|
||||
|
||||
/**
|
||||
* @author embeddedt, SuperCoder79
|
||||
* @reason Use improved STB stitcher instead of the vanilla implementation, for performance
|
||||
*/
|
||||
@Overwrite
|
||||
public void stitch() {
|
||||
ObjectArrayList<Stitcher.Holder> holderList = new ObjectArrayList<>(this.texturesToBeStitched);
|
||||
holderList.sort(HOLDER_COMPARATOR);
|
||||
Stitcher.Holder[] aholder = holderList.toArray(new Stitcher.Holder[0]);
|
||||
|
||||
Pair<Pair<Integer, Integer>, List<StbStitcher.LoadableSpriteInfo>> packingInfo = StbStitcher.packRects(aholder);
|
||||
this.storageX = packingInfo.getFirst().getFirst();
|
||||
this.storageY = packingInfo.getFirst().getSecond();
|
||||
this.loadableSpriteInfos = packingInfo.getSecond();
|
||||
}
|
||||
|
||||
/**
|
||||
* @author embeddedt, SuperCoder79
|
||||
* @reason We setup the image ourselves in the StbStitcher, so we just feed this information back into the vanilla code
|
||||
*/
|
||||
@Overwrite
|
||||
public void gatherSprites(Stitcher.SpriteLoader spriteLoader) {
|
||||
for(StbStitcher.LoadableSpriteInfo info : loadableSpriteInfos) {
|
||||
spriteLoader.load(info.info, info.width, info.height, info.x, info.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
package org.embeddedt.modernfix.textures;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import net.minecraft.client.renderer.texture.Stitcher;
|
||||
import net.minecraft.client.renderer.texture.StitcherException;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.util.Mth;
|
||||
import org.lwjgl.stb.STBRPContext;
|
||||
import org.lwjgl.stb.STBRPNode;
|
||||
import org.lwjgl.stb.STBRPRect;
|
||||
import org.lwjgl.stb.STBRectPack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/* Source: https://github.com/GTNewHorizons/lwjgl3ify/blob/f21364cd3d178aef863458a2faa1f5718a4e350d/src/main/java/me/eigenraven/lwjgl3ify/textures/StbStitcher.java */
|
||||
public class StbStitcher {
|
||||
public static Pair<Pair<Integer, Integer>, List<LoadableSpriteInfo>> packRects(Stitcher.Holder[] holders) {
|
||||
int holderSize = holders.length;
|
||||
|
||||
List<LoadableSpriteInfo> infoList = new ArrayList<>();
|
||||
|
||||
// Allocate memory for the rectangles and the context
|
||||
try (STBRPRect.Buffer rectBuf = STBRPRect.malloc(holderSize);
|
||||
STBRPContext ctx = STBRPContext.malloc(); ) {
|
||||
|
||||
// Initialize the rectangles that we'll be using in the calculation
|
||||
// While that's happening, sum up the area needed to fit all of the images
|
||||
int sqSize = 0;
|
||||
for (int j = 0; j < holderSize; ++j) {
|
||||
Stitcher.Holder holder = holders[j];
|
||||
|
||||
int width = holder.width;
|
||||
int height = holder.height;
|
||||
|
||||
// The ID here is just the array index, for easy lookup later
|
||||
rectBuf.get(j).set(j, (short)width, (short)height, (short)0, (short)0, false);
|
||||
|
||||
sqSize += (width * height);
|
||||
}
|
||||
|
||||
int size = Mth.smallestEncompassingPowerOfTwo((int) Math.sqrt(sqSize));
|
||||
int width = size * 2; // needed to fix weirdness in 1.16
|
||||
int height = size;
|
||||
|
||||
// Internal node structure needed for STB
|
||||
try (STBRPNode.Buffer nodes = STBRPNode.malloc(width + 10)) {
|
||||
// Initialize the rect packer
|
||||
STBRectPack.stbrp_init_target(ctx, width, height, nodes);
|
||||
|
||||
// Perform rectangle packing
|
||||
STBRectPack.stbrp_pack_rects(ctx, rectBuf);
|
||||
|
||||
for (STBRPRect rect : rectBuf) {
|
||||
Stitcher.Holder holder = holders[rect.id()];
|
||||
|
||||
// Ensure that everything is properly packed!
|
||||
if (!rect.was_packed()) {
|
||||
throw new StitcherException(holder.spriteInfo,
|
||||
Stream.of(holders).map(arg -> arg.spriteInfo).collect(ImmutableList.toImmutableList()));
|
||||
}
|
||||
|
||||
// Initialize the sprite now with the position and size that we've calculated so far
|
||||
infoList.add(new LoadableSpriteInfo(holder.spriteInfo, width, height, rect.x(), rect.y()));
|
||||
//holder.spriteInfo.initSprite(size, size, rect.x(), rect.y(), false);
|
||||
}
|
||||
|
||||
return Pair.of(Pair.of(width, height), infoList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class LoadableSpriteInfo {
|
||||
public final TextureAtlasSprite.Info info;
|
||||
public final int width;
|
||||
public final int height;
|
||||
public final int x;
|
||||
public final int y;
|
||||
|
||||
LoadableSpriteInfo(TextureAtlasSprite.Info info, int width, int height, int x, int y) {
|
||||
this.info = info;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,4 +4,5 @@ public net.minecraft.client.renderer.RenderType$CompositeRenderType <init>(Ljava
|
|||
public net.minecraft.world.level.block.state.BlockBehaviour$BlockStateBase$Cache
|
||||
public net.minecraft.world.phys.shapes.VoxelShape <init>(Lnet/minecraft/util/math/shapes/VoxelShapePart;)V # <init>
|
||||
public net.minecraft.client.resources.model.ModelBakery$BlockStateDefinitionException
|
||||
public net.minecraft.client.renderer.model.ModelBakery field_217849_F # unbakedCache
|
||||
public net.minecraft.client.renderer.model.ModelBakery field_217849_F # unbakedCache
|
||||
public net.minecraft.client.renderer.texture.Stitcher$Holder
|
||||
|
|
@ -81,6 +81,7 @@
|
|||
"perf.faster_baking.ModelManagerMixin",
|
||||
"perf.cache_model_materials.VanillaModelMixin",
|
||||
"perf.cache_model_materials.MultipartMixin",
|
||||
"perf.faster_texture_stitching.StitcherMixin",
|
||||
"bugfix.packet_leak.ClientPlayNetHandlerMixin",
|
||||
"bugfix.packet_leak.SCustomPayloadPlayPacketMixin"
|
||||
],
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user