Skip to content

Commit 3d40b19

Browse files
committed
Fix dynamic model loading and implement texture atlas scaling
Fixes #99
1 parent 1c84a50 commit 3d40b19

File tree

15 files changed

+353
-125
lines changed

15 files changed

+353
-125
lines changed

src/main/java/org/dimdev/vanillafix/dynamicresources/DynamicStitcher.java

Lines changed: 77 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,67 @@
11
package org.dimdev.vanillafix.dynamicresources;
22

33
import com.google.common.collect.Lists;
4-
import com.google.common.collect.Sets;
54
import net.minecraft.client.renderer.StitcherException;
65
import net.minecraft.client.renderer.texture.Stitcher.Holder;
76
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
87
import net.minecraft.util.math.MathHelper;
98

109
import java.util.List;
11-
import java.util.Set;
1210

1311
public class DynamicStitcher {
14-
private final int mipmapLevelStitcher;
15-
private final Set<Holder> setStitchHolders = Sets.newHashSetWithExpectedSize(256);
16-
private final List<Slot> stitchSlots = Lists.newArrayListWithCapacity(256);
12+
public static final int BASE_WIDTH = 32;
13+
public static final int BASE_HEIGHT = 32;
14+
15+
private final int mipmapLevels;
16+
private final List<Slot> slots = Lists.newArrayListWithCapacity(256);
1717
private int currentWidth;
1818
private int currentHeight;
1919
private final int maxWidth;
2020
private final int maxHeight;
21-
private final int maxTileDimension;
22-
23-
public DynamicStitcher(int maxWidthIn, int maxHeightIn, int maxTileDimensionIn, int mipmapLevelStitcherIn) {
24-
mipmapLevelStitcher = mipmapLevelStitcherIn;
25-
maxWidth = maxWidthIn;
26-
maxHeight = maxHeightIn;
27-
maxTileDimension = maxTileDimensionIn;
21+
private final int maxSpriteSize;
2822

29-
currentWidth = 512;
30-
currentHeight = 512;
31-
stitchSlots.add(new Slot(0, 0, currentWidth, currentHeight));
23+
public DynamicStitcher(int maxWidth, int maxHeight, int maxSpriteSize, int mipmapLevels) {
24+
this.mipmapLevels = mipmapLevels;
25+
this.maxWidth = maxWidth;
26+
this.maxHeight = maxHeight;
27+
this.maxSpriteSize = maxSpriteSize;
3228
}
3329

34-
public int getCurrentWidth() {
35-
return currentWidth;
30+
public int getImageWidth() {
31+
return Math.max(BASE_WIDTH, MathHelper.smallestEncompassingPowerOfTwo(currentWidth));
3632
}
3733

38-
public int getCurrentHeight() {
39-
return currentHeight;
34+
public int getImageHeight() {
35+
return Math.max(BASE_HEIGHT, MathHelper.smallestEncompassingPowerOfTwo(currentHeight));
4036
}
4137

4238
public void addSprite(TextureAtlasSprite sprite) {
43-
Holder holder = new Holder(sprite, mipmapLevelStitcher);
39+
Holder holder = new Holder(sprite, mipmapLevels);
4440

45-
if (maxTileDimension > 0) {
46-
holder.setNewDimension(maxTileDimension);
41+
if (maxSpriteSize > 0) {
42+
holder.setNewDimension(maxSpriteSize);
4743
}
4844

49-
setStitchHolders.add(holder);
50-
5145
Slot slot = allocateSlot(holder);
5246

5347
if (slot == null) {
54-
throw new StitcherException(null, String.format("Unable to fit: %s - size: %dx%d", holder.getAtlasSprite().getIconName(), holder.getAtlasSprite().getIconWidth(), holder.getAtlasSprite().getIconHeight()));
48+
throw new StitcherException(null, String.format("Unable to fit %s (size %dx%d)", sprite.getIconName(), sprite.getIconWidth(), sprite.getIconHeight()));
5549
}
5650

57-
currentWidth = MathHelper.smallestEncompassingPowerOfTwo(currentWidth);
58-
currentHeight = MathHelper.smallestEncompassingPowerOfTwo(currentHeight);
59-
60-
sprite.initSprite(currentWidth, currentHeight, slot.getOriginX(), slot.getOriginY(), holder.isRotated());
51+
sprite.initSprite(BASE_WIDTH, BASE_HEIGHT, slot.getOriginX(), slot.getOriginY(), holder.isRotated());
6152
}
6253

63-
public List<TextureAtlasSprite> getStichSlots() {
64-
List<Slot> slots = Lists.newArrayList();
54+
public List<TextureAtlasSprite> getAllSprites() {
55+
List<Slot> allSlots = Lists.newArrayList();
6556

66-
for (Slot stitchSlot : stitchSlots) {
67-
stitchSlot.getAllStitchSlots(slots);
57+
for (Slot slot : slots) {
58+
slot.getAllStitchSlots(allSlots);
6859
}
6960

7061
List<TextureAtlasSprite> sprites = Lists.newArrayList();
7162

72-
for (Slot slot : slots) {
73-
Holder holder = slot.getStitchHolder();
74-
TextureAtlasSprite sprite = holder.getAtlasSprite();
75-
sprite.initSprite(currentWidth, currentHeight, slot.getOriginX(), slot.getOriginY(), holder.isRotated());
76-
sprites.add(sprite);
63+
for (Slot slot : allSlots) {
64+
sprites.add(slot.getStitchHolder().getAtlasSprite());
7765
}
7866

7967
return sprites;
@@ -83,7 +71,7 @@ private Slot allocateSlot(Holder holder) {
8371
TextureAtlasSprite sprite = holder.getAtlasSprite();
8472
boolean notSquare = sprite.getIconWidth() != sprite.getIconHeight();
8573

86-
for (Slot stitchSlot : stitchSlots) {
74+
for (Slot stitchSlot : slots) {
8775
Slot slot = stitchSlot.addSlot(holder);
8876
if (slot != null) {
8977
return slot;
@@ -102,59 +90,63 @@ private Slot allocateSlot(Holder holder) {
10290
}
10391
}
10492

105-
// TODO: Fix this, expanding the atlas changes all previous UV coordinates
10693
return expandAndAllocateSlot(holder);
10794
}
10895

10996
private Slot expandAndAllocateSlot(Holder holder) {
110-
int i = Math.min(holder.getWidth(), holder.getHeight());
111-
int k = MathHelper.smallestEncompassingPowerOfTwo(currentWidth);
112-
int l = MathHelper.smallestEncompassingPowerOfTwo(currentHeight);
113-
int i1 = MathHelper.smallestEncompassingPowerOfTwo(currentWidth + i);
114-
int j1 = MathHelper.smallestEncompassingPowerOfTwo(currentHeight + i);
115-
boolean flag1 = i1 <= maxWidth;
116-
boolean flag2 = j1 <= maxHeight;
117-
118-
if (!flag1 && !flag2) {
97+
int smallestDimension = Math.min(holder.getWidth(), holder.getHeight());
98+
99+
int currentImageWidth = MathHelper.smallestEncompassingPowerOfTwo(currentWidth);
100+
int currentImageHeight = MathHelper.smallestEncompassingPowerOfTwo(currentHeight);
101+
102+
int increasedImageWidth = MathHelper.smallestEncompassingPowerOfTwo(currentWidth + smallestDimension);
103+
int increasedImageHeight = MathHelper.smallestEncompassingPowerOfTwo(currentHeight + smallestDimension);
104+
105+
boolean canExpandWidth = increasedImageWidth <= maxWidth;
106+
boolean canExpandHeight = increasedImageHeight <= maxHeight;
107+
108+
if (!canExpandWidth && !canExpandHeight) {
119109
return null;
120-
} else {
121-
boolean flag3 = flag1 && k != i1;
122-
boolean flag4 = flag2 && l != j1;
123-
boolean flag;
110+
}
124111

125-
if (flag3 ^ flag4) {
126-
flag = !flag3 && flag1; //Forge: Fix DynamicStitcher not expanding entire height before growing width, and {potentially} growing larger then the max size.
127-
} else {
128-
flag = flag1 && k <= l;
129-
}
112+
boolean imageWidthWouldIncrease = canExpandWidth && increasedImageWidth != currentImageWidth;
113+
boolean imageHeightWouldIncrease = canExpandHeight && increasedImageHeight != currentImageHeight;
130114

131-
Slot newSlot;
115+
boolean expandWidth = imageWidthWouldIncrease == imageHeightWouldIncrease
116+
? currentImageWidth <= currentImageHeight
117+
: !imageWidthWouldIncrease;
132118

133-
if (flag) {
134-
if (holder.getWidth() > holder.getHeight()) {
135-
holder.rotate();
136-
}
119+
expandWidth &= canExpandWidth;
137120

138-
if (currentHeight == 0) {
139-
currentHeight = holder.getHeight();
140-
}
121+
Slot newSlot;
122+
if (expandWidth) {
123+
if (holder.getWidth() > holder.getHeight()) {
124+
holder.rotate();
125+
}
141126

142-
if (currentWidth == 0) {
143-
currentWidth = holder.getWidth();
144-
}
127+
if (currentHeight == 0) {
128+
currentHeight = holder.getHeight();
129+
}
145130

146-
newSlot = new Slot(currentWidth, 0, holder.getWidth(), currentHeight);
147-
currentWidth += holder.getWidth();
148-
} else {
149-
newSlot = new Slot(0, currentHeight, currentWidth, holder.getHeight());
150-
currentHeight += holder.getHeight();
131+
if (currentWidth == 0) {
132+
currentWidth = holder.getWidth();
151133
}
152134

153-
Slot slot = newSlot.addSlot(holder);
154-
stitchSlots.add(newSlot);
135+
newSlot = new Slot(currentWidth, 0, holder.getWidth(), currentHeight);
136+
currentWidth += holder.getWidth();
137+
} else {
138+
// if (holder.getHeight() > holder.getWidth()) {
139+
// holder.rotate();
140+
// }
155141

156-
return slot;
142+
newSlot = new Slot(0, currentHeight, currentWidth, holder.getHeight());
143+
currentHeight += holder.getHeight();
157144
}
145+
146+
Slot slot = newSlot.addSlot(holder);
147+
slots.add(newSlot);
148+
149+
return slot;
158150
}
159151

160152
public static class Slot {
@@ -165,11 +157,11 @@ public static class Slot {
165157
private List<Slot> subSlots;
166158
private Holder holder;
167159

168-
public Slot(int originXIn, int originYIn, int widthIn, int heightIn) {
169-
originX = originXIn;
170-
originY = originYIn;
171-
width = widthIn;
172-
height = heightIn;
160+
public Slot(int originX, int originY, int width, int height) {
161+
this.originX = originX;
162+
this.originY = originY;
163+
this.width = width;
164+
this.height = height;
173165
}
174166

175167
public Holder getStitchHolder() {
@@ -233,15 +225,16 @@ public Slot addSlot(Holder holder) {
233225
}
234226

235227
return null;
228+
236229
}
237230
}
238231

239232
public void getAllStitchSlots(List<Slot> target) {
240233
if (holder != null) {
241234
target.add(this);
242235
} else if (subSlots != null) {
243-
for (Slot stitcher$slot : subSlots) {
244-
stitcher$slot.getAllStitchSlots(target);
236+
for (Slot slot : subSlots) {
237+
slot.getAllStitchSlots(target);
245238
}
246239
}
247240
}

0 commit comments

Comments
 (0)