Stitcher.java
net.minecraft.client.renderer.texture.Stitcher
信息
- 全限定名:net.minecraft.client.renderer.texture.Stitcher
- 类型:public class
- 包:net.minecraft.client.renderer.texture
- 源码路径:src/main/java/net/minecraft/client/renderer/texture/Stitcher.java
- 起始行号:L14
- 职责:
TODO
字段/常量
-
HOLDER_COMPARATOR- 类型:
Comparator<Stitcher.Holder<?>> - 修饰符:
private static final - 源码定位:
L15 - 说明:
TODO
- 类型:
-
mipLevel- 类型:
int - 修饰符:
private final - 源码定位:
L18 - 说明:
TODO
- 类型:
-
texturesToBeStitched- 类型:
List<Stitcher.Holder<T>> - 修饰符:
private final - 源码定位:
L19 - 说明:
TODO
- 类型:
-
storage- 类型:
List<Stitcher.Region<T>> - 修饰符:
private final - 源码定位:
L20 - 说明:
TODO
- 类型:
-
storageX- 类型:
int - 修饰符:
private - 源码定位:
L21 - 说明:
TODO
- 类型:
-
storageY- 类型:
int - 修饰符:
private - 源码定位:
L22 - 说明:
TODO
- 类型:
-
maxWidth- 类型:
int - 修饰符:
private final - 源码定位:
L23 - 说明:
TODO
- 类型:
-
maxHeight- 类型:
int - 修饰符:
private final - 源码定位:
L24 - 说明:
TODO
- 类型:
-
padding- 类型:
int - 修饰符:
private final - 源码定位:
L25 - 说明:
TODO
- 类型:
内部类/嵌套类型
-
net.minecraft.client.renderer.texture.Stitcher.Entry- 类型:
interface - 修饰符:
public - 源码定位:
L121 - 说明:
TODO
- 类型:
-
net.minecraft.client.renderer.texture.Stitcher.Holder- 类型:
record - 修饰符:
private - 源码定位:
L130 - 说明:
TODO
- 类型:
-
net.minecraft.client.renderer.texture.Stitcher.Region- 类型:
class - 修饰符:
public static - 源码定位:
L134 - 说明:
TODO
- 类型:
-
net.minecraft.client.renderer.texture.Stitcher.SpriteLoader- 类型:
interface - 修饰符:
public - 源码定位:
L233 - 说明:
TODO
- 类型:
构造器
public Stitcher(int maxWidth, int maxHeight, int mipLevel, int anisotropyBit) @ L27
- 构造器名:Stitcher
- 源码定位:L27
- 修饰符:public
参数:
- maxWidth: int
- maxHeight: int
- mipLevel: int
- anisotropyBit: int
说明:
TODO
方法
下面的方法块按源码顺序生成。
public int getWidth() @ L34
- 方法名:getWidth
- 源码定位:L34
- 返回类型:int
- 修饰符:public
参数:
- 无
说明:
TODO
public int getHeight() @ L38
- 方法名:getHeight
- 源码定位:L38
- 返回类型:int
- 修饰符:public
参数:
- 无
说明:
TODO
public void registerSprite(T entry) @ L42
- 方法名:registerSprite
- 源码定位:L42
- 返回类型:void
- 修饰符:public
参数:
- entry: T
说明:
TODO
public void stitch() @ L51
- 方法名:stitch
- 源码定位:L51
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
public void gatherSprites(Stitcher.SpriteLoader<T> loader) @ L62
- 方法名:gatherSprites
- 源码定位:L62
- 返回类型:void
- 修饰符:public
参数:
- loader: Stitcher.SpriteLoader
说明:
TODO
private static int smallestFittingMinTexel(int input, int maxMipLevel) @ L68
- 方法名:smallestFittingMinTexel
- 源码定位:L68
- 返回类型:int
- 修饰符:private static
参数:
- input: int
- maxMipLevel: int
说明:
TODO
private boolean addToStorage(Stitcher.Holder<T> holder) @ L72
- 方法名:addToStorage
- 源码定位:L72
- 返回类型:boolean
- 修饰符:private
参数:
- holder: Stitcher.Holder
说明:
TODO
private boolean expand(Stitcher.Holder<T> holder) @ L82
- 方法名:expand
- 源码定位:L82
- 返回类型:boolean
- 修饰符:private
参数:
- holder: Stitcher.Holder
说明:
TODO
代码
@OnlyIn(Dist.CLIENT)
public class Stitcher<T extends Stitcher.Entry> {
private static final Comparator<Stitcher.Holder<?>> HOLDER_COMPARATOR = Comparator.<Stitcher.Holder<?>, Integer>comparing(h -> -h.height)
.thenComparing(h -> -h.width)
.thenComparing(h -> h.entry.name());
private final int mipLevel;
private final List<Stitcher.Holder<T>> texturesToBeStitched = new ArrayList<>();
private final List<Stitcher.Region<T>> storage = new ArrayList<>();
private int storageX;
private int storageY;
private final int maxWidth;
private final int maxHeight;
private final int padding;
public Stitcher(int maxWidth, int maxHeight, int mipLevel, int anisotropyBit) {
this.mipLevel = mipLevel;
this.maxWidth = maxWidth;
this.maxHeight = maxHeight;
this.padding = 1 << mipLevel << Mth.clamp(anisotropyBit - 1, 0, 4);
}
public int getWidth() {
return this.storageX;
}
public int getHeight() {
return this.storageY;
}
public void registerSprite(T entry) {
Stitcher.Holder<T> holder = new Stitcher.Holder<>(
entry,
smallestFittingMinTexel(entry.width() + this.padding * 2, this.mipLevel),
smallestFittingMinTexel(entry.height() + this.padding * 2, this.mipLevel)
);
this.texturesToBeStitched.add(holder);
}
public void stitch() {
List<Stitcher.Holder<T>> holders = new ArrayList<>(this.texturesToBeStitched);
holders.sort(HOLDER_COMPARATOR);
for (Stitcher.Holder<T> holder : holders) {
if (!this.addToStorage(holder)) {
throw new StitcherException(holder.entry, holders.stream().map(h -> h.entry).collect(ImmutableList.toImmutableList()));
}
}
}
public void gatherSprites(Stitcher.SpriteLoader<T> loader) {
for (Stitcher.Region<T> topRegion : this.storage) {
topRegion.walk(loader, this.padding);
}
}
private static int smallestFittingMinTexel(int input, int maxMipLevel) {
return (input >> maxMipLevel) + ((input & (1 << maxMipLevel) - 1) == 0 ? 0 : 1) << maxMipLevel;
}
private boolean addToStorage(Stitcher.Holder<T> holder) {
for (Stitcher.Region<T> region : this.storage) {
if (region.add(holder)) {
return true;
}
}
return this.expand(holder);
}
private boolean expand(Stitcher.Holder<T> holder) {
int xCurrentSize = Mth.smallestEncompassingPowerOfTwo(this.storageX);
int yCurrentSize = Mth.smallestEncompassingPowerOfTwo(this.storageY);
int xNewSize = Mth.smallestEncompassingPowerOfTwo(this.storageX + holder.width);
int yNewSize = Mth.smallestEncompassingPowerOfTwo(this.storageY + holder.height);
boolean xCanGrow = xNewSize <= this.maxWidth;
boolean yCanGrow = yNewSize <= this.maxHeight;
if (!xCanGrow && !yCanGrow) {
return false;
} else {
boolean xWillGrow = xCanGrow && xCurrentSize != xNewSize;
boolean yWillGrow = yCanGrow && yCurrentSize != yNewSize;
boolean growOnX;
if (xWillGrow ^ yWillGrow) {
growOnX = xWillGrow;
} else {
growOnX = xCanGrow && xCurrentSize <= yCurrentSize;
}
Stitcher.Region<T> slot;
if (growOnX) {
if (this.storageY == 0) {
this.storageY = yNewSize;
}
slot = new Stitcher.Region<>(this.storageX, 0, xNewSize - this.storageX, this.storageY);
this.storageX = xNewSize;
} else {
slot = new Stitcher.Region<>(0, this.storageY, this.storageX, yNewSize - this.storageY);
this.storageY = yNewSize;
}
slot.add(holder);
this.storage.add(slot);
return true;
}
}
@OnlyIn(Dist.CLIENT)
public interface Entry {
int width();
int height();
Identifier name();
}
@OnlyIn(Dist.CLIENT)
private record Holder<T extends Stitcher.Entry>(T entry, int width, int height) {
}
@OnlyIn(Dist.CLIENT)
public static class Region<T extends Stitcher.Entry> {
private final int originX;
private final int originY;
private final int width;
private final int height;
private @Nullable List<Stitcher.Region<T>> subSlots;
private Stitcher.@Nullable Holder<T> holder;
public Region(int originX, int originY, int width, int height) {
this.originX = originX;
this.originY = originY;
this.width = width;
this.height = height;
}
public int getX() {
return this.originX;
}
public int getY() {
return this.originY;
}
public boolean add(Stitcher.Holder<T> holder) {
if (this.holder != null) {
return false;
} else {
int textureWidth = holder.width;
int textureHeight = holder.height;
if (textureWidth <= this.width && textureHeight <= this.height) {
if (textureWidth == this.width && textureHeight == this.height) {
this.holder = holder;
return true;
} else {
if (this.subSlots == null) {
this.subSlots = new ArrayList<>(1);
this.subSlots.add(new Stitcher.Region<>(this.originX, this.originY, textureWidth, textureHeight));
int spareWidth = this.width - textureWidth;
int spareHeight = this.height - textureHeight;
if (spareHeight > 0 && spareWidth > 0) {
int right = Math.max(this.height, spareWidth);
int bottom = Math.max(this.width, spareHeight);
if (right >= bottom) {
this.subSlots.add(new Stitcher.Region<>(this.originX, this.originY + textureHeight, textureWidth, spareHeight));
this.subSlots.add(new Stitcher.Region<>(this.originX + textureWidth, this.originY, spareWidth, this.height));
} else {
this.subSlots.add(new Stitcher.Region<>(this.originX + textureWidth, this.originY, spareWidth, textureHeight));
this.subSlots.add(new Stitcher.Region<>(this.originX, this.originY + textureHeight, this.width, spareHeight));
}
} else if (spareWidth == 0) {
this.subSlots.add(new Stitcher.Region<>(this.originX, this.originY + textureHeight, textureWidth, spareHeight));
} else if (spareHeight == 0) {
this.subSlots.add(new Stitcher.Region<>(this.originX + textureWidth, this.originY, spareWidth, textureHeight));
}
}
for (Stitcher.Region<T> subSlot : this.subSlots) {
if (subSlot.add(holder)) {
return true;
}
}
return false;
}
} else {
return false;
}
}
}
public void walk(Stitcher.SpriteLoader<T> output, int padding) {
if (this.holder != null) {
output.load(this.holder.entry, this.getX(), this.getY(), padding);
} else if (this.subSlots != null) {
for (Stitcher.Region<T> subSlot : this.subSlots) {
subSlot.walk(output, padding);
}
}
}
@Override
public String toString() {
return "Slot{originX="
+ this.originX
+ ", originY="
+ this.originY
+ ", width="
+ this.width
+ ", height="
+ this.height
+ ", texture="
+ this.holder
+ ", subSlots="
+ this.subSlots
+ "}";
}
}
@OnlyIn(Dist.CLIENT)
public interface SpriteLoader<T extends Stitcher.Entry> {
void load(T entry, int x, int z, int padding);
}
}引用的其他类
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
StitcherException()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Mth.clamp(), Mth.smallestEncompassingPowerOfTwo()
- 引用位置: