Refactor Stitcher class to use TurboStitcher for improved performance
This commit is contained in:
parent
b06faea26e
commit
a8347a5126
|
@ -0,0 +1,27 @@
|
||||||
|
package net.hoosiertransfer.Argon.stitcher;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.texture.Stitcher;
|
||||||
|
|
||||||
|
public class HolderSlot extends SpriteSlot {
|
||||||
|
private final Stitcher.Holder holder;
|
||||||
|
|
||||||
|
public HolderSlot(Stitcher.Holder holder) {
|
||||||
|
this.holder = holder;
|
||||||
|
width = holder.getWidth();
|
||||||
|
height = holder.getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stitcher.Holder getHolder() {
|
||||||
|
return holder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Stitcher.Slot> getSlots(Rect2D parent) {
|
||||||
|
Stitcher.Slot slot = new Stitcher.Slot(x + parent.x, y + parent.y, width, height);
|
||||||
|
slot.insertHolder(holder);
|
||||||
|
return Collections.singletonList(slot);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package net.hoosiertransfer.Argon.stitcher;
|
||||||
|
|
||||||
|
public class Rect2D implements Comparable<Rect2D> {
|
||||||
|
public int x;
|
||||||
|
public int y;
|
||||||
|
public int width;
|
||||||
|
public int height;
|
||||||
|
|
||||||
|
public Rect2D() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rect2D(int x, int y, int width, int height) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Rect2D o) {
|
||||||
|
int ourArea = width * height;
|
||||||
|
int theirArea = o.width * o.height;
|
||||||
|
// will make sure that larger areas go first
|
||||||
|
return theirArea - ourArea;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package net.hoosiertransfer.Argon.stitcher;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.texture.Stitcher;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class SpriteSlot extends Rect2D {
|
||||||
|
public abstract List<Stitcher.Slot> getSlots(Rect2D parent);
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package net.hoosiertransfer.Argon.stitcher;
|
||||||
|
|
||||||
|
public enum StitcherState {
|
||||||
|
SETUP,
|
||||||
|
STITCHED,
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
package net.hoosiertransfer.Argon.stitcher;
|
||||||
|
|
||||||
|
public class TooBigException extends Exception {
|
||||||
|
}
|
|
@ -0,0 +1,177 @@
|
||||||
|
package net.hoosiertransfer.Argon.stitcher;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
|
||||||
|
import net.hoosiertransfer.Argon.stitcher.packing2d.Algorithm;
|
||||||
|
import net.hoosiertransfer.Argon.stitcher.packing2d.Packer;
|
||||||
|
import net.minecraft.client.renderer.texture.Stitcher;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
|
public class TurboStitcher extends SpriteSlot {
|
||||||
|
private final int maxWidth;
|
||||||
|
private final int maxHeight;
|
||||||
|
private final boolean forcePowerOf2;
|
||||||
|
private List<SpriteSlot> slots = new LinkedList<>();
|
||||||
|
private List<SpriteSlot> finalizedSlots = null;
|
||||||
|
private boolean needsSorting = false;
|
||||||
|
private int trackedArea = 0;
|
||||||
|
private StitcherState state = StitcherState.SETUP;
|
||||||
|
private static final boolean OPTIMAL_PACKING = true;
|
||||||
|
|
||||||
|
public TurboStitcher(int maxWidth, int maxHeight, boolean forcePowerOf2) {
|
||||||
|
this.maxHeight = maxHeight;
|
||||||
|
this.maxWidth = maxWidth;
|
||||||
|
this.forcePowerOf2 = forcePowerOf2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int nextPowerOfTwo(int number) {
|
||||||
|
number--;
|
||||||
|
number |= number >>> 1;
|
||||||
|
number |= number >>> 2;
|
||||||
|
number |= number >>> 4;
|
||||||
|
number |= number >>> 8;
|
||||||
|
number |= number >>> 16;
|
||||||
|
number++;
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSprite(Stitcher.Holder holder) {
|
||||||
|
addSprite(new HolderSlot(holder));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSprite(SpriteSlot rect) {
|
||||||
|
verifyState(StitcherState.SETUP);
|
||||||
|
slots.add(rect);
|
||||||
|
trackedArea += rect.width * rect.height;
|
||||||
|
needsSorting = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
state = StitcherState.SETUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dropFirst() {
|
||||||
|
verifyState(StitcherState.SETUP);
|
||||||
|
if (slots.size() > 0) {
|
||||||
|
SpriteSlot slot = slots.remove(0);
|
||||||
|
String name;
|
||||||
|
if (slot instanceof HolderSlot) {
|
||||||
|
name = ((HolderSlot) slot).getHolder().getAtlasSprite().getIconName();
|
||||||
|
} else {
|
||||||
|
name = "unknown";
|
||||||
|
}
|
||||||
|
trackedArea -= slot.width * slot.height;
|
||||||
|
} else
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void retainAllSprites(Set<ResourceLocation> theLocations) {
|
||||||
|
verifyState(StitcherState.SETUP);
|
||||||
|
Set<String> locationStrings = new HashSet<>();
|
||||||
|
for (ResourceLocation rl : theLocations)
|
||||||
|
locationStrings.add(rl.toString());
|
||||||
|
slots.removeIf(slot -> {
|
||||||
|
if (slot instanceof HolderSlot) {
|
||||||
|
String spriteName = ((HolderSlot) slot).getHolder().getAtlasSprite().getIconName();
|
||||||
|
// drop textures that are:
|
||||||
|
// - not in the desired list of locations
|
||||||
|
if (!locationStrings.contains(spriteName)) {
|
||||||
|
trackedArea -= slot.width * slot.height;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stitch() throws TooBigException {
|
||||||
|
verifyState(StitcherState.SETUP);
|
||||||
|
width = 0;
|
||||||
|
height = 0;
|
||||||
|
if (slots.size() == 0) {
|
||||||
|
state = StitcherState.STITCHED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// ensure we have largest sprites first
|
||||||
|
if (needsSorting) {
|
||||||
|
Collections.sort(slots);
|
||||||
|
needsSorting = false;
|
||||||
|
}
|
||||||
|
if (trackedArea > (maxWidth * maxHeight)) {
|
||||||
|
throw new TooBigException();
|
||||||
|
}
|
||||||
|
// start with a really simple check, if the total area is larger than we could
|
||||||
|
// handle, we know this will fail
|
||||||
|
for (SpriteSlot slot : slots) {
|
||||||
|
width = Math.max(width, slot.width);
|
||||||
|
}
|
||||||
|
if (forcePowerOf2 || !OPTIMAL_PACKING) {
|
||||||
|
width = nextPowerOfTwo(width);
|
||||||
|
}
|
||||||
|
if (width > maxWidth) {
|
||||||
|
throw new TooBigException();
|
||||||
|
}
|
||||||
|
width = Math.max(width >>> 1, 1);
|
||||||
|
List<SpriteSlot> packedSlots;
|
||||||
|
List<SpriteSlot> toPack = new ArrayList<>(slots);
|
||||||
|
do {
|
||||||
|
if (width == maxWidth) {
|
||||||
|
throw new TooBigException();
|
||||||
|
}
|
||||||
|
if (forcePowerOf2 || !OPTIMAL_PACKING) {
|
||||||
|
width *= 2;
|
||||||
|
} else {
|
||||||
|
width += Math.min(width, 16);
|
||||||
|
}
|
||||||
|
if (width > maxWidth) {
|
||||||
|
width = maxWidth;
|
||||||
|
}
|
||||||
|
packedSlots = Packer.pack(toPack, Algorithm.FIRST_FIT_DECREASING_HEIGHT, width);
|
||||||
|
height = 0;
|
||||||
|
for (SpriteSlot sprite : packedSlots) {
|
||||||
|
height = Math.max(height, sprite.y + sprite.height);
|
||||||
|
}
|
||||||
|
if (forcePowerOf2) {
|
||||||
|
height = nextPowerOfTwo(height);
|
||||||
|
}
|
||||||
|
} while (height > maxHeight || height > width);
|
||||||
|
finalizedSlots = packedSlots;
|
||||||
|
state = StitcherState.STITCHED;
|
||||||
|
// TextureCollector.weaklyCollectedTextures = ImmutableSet.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Stitcher.Slot> getSlots() {
|
||||||
|
return getSlots(new Rect2D());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Stitcher.Slot> getSlots(Rect2D parent) {
|
||||||
|
verifyState(StitcherState.STITCHED);
|
||||||
|
ArrayList<Stitcher.Slot> mineSlots = new ArrayList<Stitcher.Slot>();
|
||||||
|
Rect2D offset = new Rect2D(x + parent.x, y + parent.y, width, height);
|
||||||
|
for (SpriteSlot slot : finalizedSlots) {
|
||||||
|
mineSlots.addAll(slot.getSlots(offset));
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* for(Stitcher.Slot slot : mineSlots) {
|
||||||
|
* System.out.println(slot.getStitchHolder().getAtlasSprite().getIconName());
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
return mineSlots;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyState(StitcherState... allowedStates) {
|
||||||
|
boolean ok = false;
|
||||||
|
for (StitcherState state : allowedStates) {
|
||||||
|
if (state == this.state) {
|
||||||
|
ok = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ok) {
|
||||||
|
throw new IllegalStateException("Cold not execute operation: invalid state");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package net.hoosiertransfer.Argon.stitcher;
|
||||||
|
|
||||||
|
public class WrongDimensionException extends RuntimeException {
|
||||||
|
public static WrongDimensionException INSTANCE = new WrongDimensionException();
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package net.hoosiertransfer.Argon.stitcher.packing2d;
|
||||||
|
|
||||||
|
public enum Algorithm {
|
||||||
|
FIRST_FIT_DECREASING_HEIGHT,
|
||||||
|
BEST_FIT_DECREASING_HEIGHT
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package net.hoosiertransfer.Argon.stitcher.packing2d;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.hoosiertransfer.Argon.stitcher.Rect2D;
|
||||||
|
|
||||||
|
public abstract class Packer<T extends Rect2D> {
|
||||||
|
final int stripWidth;
|
||||||
|
final List<T> rectangles;
|
||||||
|
|
||||||
|
Packer(int stripWidth, List<T> rectangles) {
|
||||||
|
this.stripWidth = stripWidth;
|
||||||
|
this.rectangles = rectangles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <U extends Rect2D> List<U> pack(List<U> rectangles, Algorithm algorithm, int stripWidth) {
|
||||||
|
Packer<U> packer;
|
||||||
|
switch (algorithm) {
|
||||||
|
case FIRST_FIT_DECREASING_HEIGHT:
|
||||||
|
packer = new PackerFFDH<>(stripWidth, rectangles);
|
||||||
|
return packer.pack();
|
||||||
|
case BEST_FIT_DECREASING_HEIGHT:
|
||||||
|
packer = new PackerBFDH<>(stripWidth, rectangles);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
return packer.pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract List<T> pack();
|
||||||
|
|
||||||
|
void sortByNonIncreasingHeight(List<T> rectangles) {
|
||||||
|
rectangles.sort(Comparator.<T>comparingInt((rect) -> rect.height).reversed());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package net.hoosiertransfer.Argon.stitcher.packing2d;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.hoosiertransfer.Argon.stitcher.Rect2D;
|
||||||
|
|
||||||
|
public class PackerBFDH<T extends Rect2D> extends Packer<T> {
|
||||||
|
private final List<StripLevel> levels;
|
||||||
|
|
||||||
|
public PackerBFDH(int stripWidth, List<T> rectangles) {
|
||||||
|
super(stripWidth, rectangles);
|
||||||
|
levels = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<T> pack() {
|
||||||
|
int top = 0;
|
||||||
|
sortByNonIncreasingHeight(rectangles);
|
||||||
|
for (T r : rectangles) {
|
||||||
|
StripLevel levelWithSmallestResidual = null;
|
||||||
|
for (StripLevel level : levels) {
|
||||||
|
if (!level.canFit(r)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (levelWithSmallestResidual != null &&
|
||||||
|
levelWithSmallestResidual.availableWidth() > level.availableWidth()) {
|
||||||
|
levelWithSmallestResidual = level;
|
||||||
|
} else if (levelWithSmallestResidual == null) {
|
||||||
|
levelWithSmallestResidual = level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (levelWithSmallestResidual == null) {
|
||||||
|
StripLevel level = new StripLevel(stripWidth, top);
|
||||||
|
level.fitRectangle(r);
|
||||||
|
levels.add(level);
|
||||||
|
top += r.height;
|
||||||
|
} else {
|
||||||
|
StripLevel newLevel = levelWithSmallestResidual.fitRectangle(r);
|
||||||
|
if (newLevel != null) {
|
||||||
|
levels.add(levels.indexOf(levelWithSmallestResidual) + 1, newLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return rectangles;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package net.hoosiertransfer.Argon.stitcher.packing2d;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.hoosiertransfer.Argon.stitcher.Rect2D;
|
||||||
|
|
||||||
|
class PackerFFDH<T extends Rect2D> extends Packer<T> {
|
||||||
|
private final List<StripLevel> levels = new ArrayList<>(1);
|
||||||
|
private int top = 0;
|
||||||
|
|
||||||
|
public PackerFFDH(int stripWidth, List<T> rectangles) {
|
||||||
|
super(stripWidth, rectangles);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<T> pack() {
|
||||||
|
sortByNonIncreasingHeight(rectangles);
|
||||||
|
for (T r : rectangles) {
|
||||||
|
boolean fitsOnALevel = false;
|
||||||
|
for (int i = 0; i < levels.size(); i++) {
|
||||||
|
StripLevel level = levels.get(i);
|
||||||
|
fitsOnALevel = level.checkFitRectangle(r);
|
||||||
|
if (!fitsOnALevel) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
StripLevel newStrip = level.fitRectangle(r);
|
||||||
|
if (newStrip != null) {
|
||||||
|
levels.add(0, newStrip);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (fitsOnALevel) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
StripLevel level = new StripLevel(stripWidth, top);
|
||||||
|
level.fitRectangle(r);
|
||||||
|
levels.add(level);
|
||||||
|
top += r.height;
|
||||||
|
}
|
||||||
|
return rectangles;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package net.hoosiertransfer.Argon.stitcher.packing2d;
|
||||||
|
|
||||||
|
import net.hoosiertransfer.Argon.stitcher.Rect2D;
|
||||||
|
|
||||||
|
class StripLevel {
|
||||||
|
private final int width;
|
||||||
|
private final int top;
|
||||||
|
private int availableWidth;
|
||||||
|
private int tallest = -1;
|
||||||
|
|
||||||
|
StripLevel(int width, int top) {
|
||||||
|
this.width = width;
|
||||||
|
this.availableWidth = width;
|
||||||
|
this.top = top;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean checkFitRectangle(Rect2D r) {
|
||||||
|
return (tallest < 0 || r.height <= tallest) && r.width <= availableWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
StripLevel fitRectangle(Rect2D r) {
|
||||||
|
if (tallest >= 0 && r.height > tallest) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
StripLevel newStrip = null;
|
||||||
|
int leftOver = availableWidth - r.width;
|
||||||
|
if (leftOver >= 0) {
|
||||||
|
r.x = width - availableWidth;
|
||||||
|
r.y = top;
|
||||||
|
if (tallest == -1) {
|
||||||
|
tallest = r.height;
|
||||||
|
}
|
||||||
|
if (r.height < tallest) {
|
||||||
|
newStrip = new StripLevel(width, top + r.height);
|
||||||
|
newStrip.availableWidth = availableWidth;
|
||||||
|
newStrip.tallest = tallest - r.height;
|
||||||
|
tallest = r.height;
|
||||||
|
}
|
||||||
|
availableWidth = leftOver;
|
||||||
|
}
|
||||||
|
return newStrip;
|
||||||
|
}
|
||||||
|
|
||||||
|
int availableWidth() {
|
||||||
|
return availableWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean canFit(Rect2D r) {
|
||||||
|
return availableWidth - r.width >= 0 && (tallest < 0 || r.height <= tallest);
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,14 +26,21 @@ import net.minecraft.util.ResourceLocation;
|
||||||
/**
|
/**
|
||||||
* Copyright (c) 2022 lax1dude. All Rights Reserved.
|
* Copyright (c) 2022 lax1dude. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
* DISCLAIMED.
|
||||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
* DIRECT,
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
* (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE)
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
|
@ -151,7 +158,7 @@ public class EaglerTextureAtlasSprite {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateAnimation(IFramebufferGL[] copyColorFramebuffer) {
|
public void updateAnimation(IFramebufferGL[] copyColorFramebuffer) {
|
||||||
if(animationCache == null) {
|
if (animationCache == null) {
|
||||||
throw new IllegalStateException("Animation cache for '" + this.iconName + "' was never baked!");
|
throw new IllegalStateException("Animation cache for '" + this.iconName + "' was never baked!");
|
||||||
}
|
}
|
||||||
++this.tickCounter;
|
++this.tickCounter;
|
||||||
|
@ -163,16 +170,19 @@ public class EaglerTextureAtlasSprite {
|
||||||
this.tickCounter = 0;
|
this.tickCounter = 0;
|
||||||
int k = this.animationMetadata.getFrameIndex(this.frameCounter);
|
int k = this.animationMetadata.getFrameIndex(this.frameCounter);
|
||||||
if (i != k && k >= 0 && k < this.framesTextureData.size()) {
|
if (i != k && k >= 0 && k < this.framesTextureData.size()) {
|
||||||
animationCache.copyFrameLevelsToTex2D(k, this.originX, this.originY, this.width, this.height, copyColorFramebuffer);
|
animationCache.copyFrameLevelsToTex2D(k, this.originX, this.originY, this.width, this.height,
|
||||||
|
copyColorFramebuffer);
|
||||||
}
|
}
|
||||||
} else if (this.animationMetadata.isInterpolate()) {
|
} else if (this.animationMetadata.isInterpolate()) {
|
||||||
float f = 1.0f - (float) this.tickCounter / (float) this.animationMetadata.getFrameTimeSingle(this.frameCounter);
|
float f = 1.0f
|
||||||
|
- (float) this.tickCounter / (float) this.animationMetadata.getFrameTimeSingle(this.frameCounter);
|
||||||
int i = this.animationMetadata.getFrameIndex(this.frameCounter);
|
int i = this.animationMetadata.getFrameIndex(this.frameCounter);
|
||||||
int j = this.animationMetadata.getFrameCount() == 0 ? this.framesTextureData.size()
|
int j = this.animationMetadata.getFrameCount() == 0 ? this.framesTextureData.size()
|
||||||
: this.animationMetadata.getFrameCount();
|
: this.animationMetadata.getFrameCount();
|
||||||
int k = this.animationMetadata.getFrameIndex((this.frameCounter + 1) % j);
|
int k = this.animationMetadata.getFrameIndex((this.frameCounter + 1) % j);
|
||||||
if (i != k && k >= 0 && k < this.framesTextureData.size()) {
|
if (i != k && k >= 0 && k < this.framesTextureData.size()) {
|
||||||
animationCache.copyInterpolatedFrameLevelsToTex2D(i, k, f, this.originX, this.originY, this.width, this.height, copyColorFramebuffer);
|
animationCache.copyInterpolatedFrameLevelsToTex2D(i, k, f, this.originX, this.originY, this.width,
|
||||||
|
this.height, copyColorFramebuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -295,9 +305,9 @@ public class EaglerTextureAtlasSprite {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bakeAnimationCache() {
|
public void bakeAnimationCache() {
|
||||||
if(animationMetadata != null) {
|
if (animationMetadata != null) {
|
||||||
int mipLevels = framesTextureData.get(0).length;
|
int mipLevels = framesTextureData.get(0).length;
|
||||||
if(animationCache == null) {
|
if (animationCache == null) {
|
||||||
animationCache = new TextureAnimationCache(width, height, mipLevels);
|
animationCache = new TextureAnimationCache(width, height, mipLevels);
|
||||||
}
|
}
|
||||||
animationCache.initialize(framesTextureData);
|
animationCache.initialize(framesTextureData);
|
||||||
|
@ -328,7 +338,7 @@ public class EaglerTextureAtlasSprite {
|
||||||
|
|
||||||
public void clearFramesTextureData() {
|
public void clearFramesTextureData() {
|
||||||
this.framesTextureData.clear();
|
this.framesTextureData.clear();
|
||||||
if(this.animationCache != null) {
|
if (this.animationCache != null) {
|
||||||
this.animationCache.free();
|
this.animationCache.free();
|
||||||
this.animationCache = null;
|
this.animationCache = null;
|
||||||
}
|
}
|
||||||
|
@ -347,7 +357,7 @@ public class EaglerTextureAtlasSprite {
|
||||||
this.setFramesTextureData(Lists.newArrayList());
|
this.setFramesTextureData(Lists.newArrayList());
|
||||||
this.frameCounter = 0;
|
this.frameCounter = 0;
|
||||||
this.tickCounter = 0;
|
this.tickCounter = 0;
|
||||||
if(this.animationCache != null) {
|
if (this.animationCache != null) {
|
||||||
this.animationCache.free();
|
this.animationCache.free();
|
||||||
this.animationCache = null;
|
this.animationCache = null;
|
||||||
}
|
}
|
||||||
|
@ -365,16 +375,17 @@ public class EaglerTextureAtlasSprite {
|
||||||
Throwable t = new UnsupportedOperationException("PBR is not enabled");
|
Throwable t = new UnsupportedOperationException("PBR is not enabled");
|
||||||
try {
|
try {
|
||||||
throw t;
|
throw t;
|
||||||
}catch(Throwable tt) {
|
} catch (Throwable tt) {
|
||||||
logger.error(t);
|
logger.error(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateAnimationPBR(IFramebufferGL[] copyColorFramebuffer, IFramebufferGL[] copyMaterialFramebuffer, int materialTexOffset) {
|
public void updateAnimationPBR(IFramebufferGL[] copyColorFramebuffer, IFramebufferGL[] copyMaterialFramebuffer,
|
||||||
|
int materialTexOffset) {
|
||||||
Throwable t = new UnsupportedOperationException("PBR is not enabled");
|
Throwable t = new UnsupportedOperationException("PBR is not enabled");
|
||||||
try {
|
try {
|
||||||
throw t;
|
throw t;
|
||||||
}catch(Throwable tt) {
|
} catch (Throwable tt) {
|
||||||
logger.error(t);
|
logger.error(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package net.minecraft.client.renderer.texture;
|
package net.minecraft.client.renderer.texture;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import net.lax1dude.eaglercraft.v1_8.HString;
|
import net.hoosiertransfer.Argon.stitcher.TooBigException;
|
||||||
|
import net.hoosiertransfer.Argon.stitcher.TurboStitcher;
|
||||||
import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerTextureAtlasSprite;
|
import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerTextureAtlasSprite;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
@ -13,6 +13,7 @@ import com.google.common.collect.Sets;
|
||||||
|
|
||||||
import net.minecraft.client.renderer.StitcherException;
|
import net.minecraft.client.renderer.StitcherException;
|
||||||
import net.minecraft.util.MathHelper;
|
import net.minecraft.util.MathHelper;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* +
|
* +
|
||||||
|
@ -54,12 +55,16 @@ public class Stitcher {
|
||||||
private final boolean forcePowerOf2;
|
private final boolean forcePowerOf2;
|
||||||
private final int maxTileDimension;
|
private final int maxTileDimension;
|
||||||
|
|
||||||
|
private TurboStitcher masterStitcher;
|
||||||
|
private List<Stitcher.Holder> holdersToReadd = new ArrayList<>();
|
||||||
|
|
||||||
public Stitcher(int maxTextureWidth, int maxTextureHeight, boolean parFlag, int parInt1, int mipmapLevel) {
|
public Stitcher(int maxTextureWidth, int maxTextureHeight, boolean parFlag, int parInt1, int mipmapLevel) {
|
||||||
this.mipmapLevelStitcher = mipmapLevel;
|
this.mipmapLevelStitcher = mipmapLevel;
|
||||||
this.maxWidth = maxTextureWidth;
|
this.maxWidth = maxTextureWidth;
|
||||||
this.maxHeight = maxTextureHeight;
|
this.maxHeight = maxTextureHeight;
|
||||||
this.forcePowerOf2 = parFlag;
|
this.forcePowerOf2 = parFlag;
|
||||||
this.maxTileDimension = parInt1;
|
this.maxTileDimension = parInt1;
|
||||||
|
masterStitcher = new TurboStitcher(maxTextureWidth, maxTextureHeight, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCurrentWidth() {
|
public int getCurrentWidth() {
|
||||||
|
@ -75,31 +80,32 @@ public class Stitcher {
|
||||||
if (this.maxTileDimension > 0) {
|
if (this.maxTileDimension > 0) {
|
||||||
stitcher$holder.setNewDimension(this.maxTileDimension);
|
stitcher$holder.setNewDimension(this.maxTileDimension);
|
||||||
}
|
}
|
||||||
|
masterStitcher.addSprite(stitcher$holder);
|
||||||
|
holdersToReadd.add(stitcher$holder);
|
||||||
this.setStitchHolders.add(stitcher$holder);
|
this.setStitchHolders.add(stitcher$holder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doStitch() {
|
public void doStitch() {
|
||||||
Stitcher.Holder[] astitcher$holder = (Stitcher.Holder[]) this.setStitchHolders
|
try {
|
||||||
.toArray(new Stitcher.Holder[this.setStitchHolders.size()]);
|
masterStitcher.stitch();
|
||||||
Arrays.sort(astitcher$holder);
|
currentWidth = masterStitcher.width;
|
||||||
|
currentHeight = masterStitcher.height;
|
||||||
for (int i = 0; i < astitcher$holder.length; ++i) {
|
stitchSlots.clear();
|
||||||
Stitcher.Holder stitcher$holder = astitcher$holder[i];
|
stitchSlots.addAll(masterStitcher.getSlots());
|
||||||
if (!this.allocateSlot(stitcher$holder)) {
|
} catch (TooBigException ignored) {
|
||||||
String s = HString.format("Unable to fit: %s - size: %dx%d - Maybe try a lowerresolution resourcepack?",
|
throw new StitcherException(null,
|
||||||
new Object[] { stitcher$holder.getAtlasSprite().getIconName(),
|
"Unable to fit all textures into atlas. Maybe try a lower resolution resourcepack?");
|
||||||
Integer.valueOf(stitcher$holder.getAtlasSprite().getIconWidth()),
|
} finally {
|
||||||
Integer.valueOf(stitcher$holder.getAtlasSprite().getIconHeight()) });
|
masterStitcher.reset();
|
||||||
throw new StitcherException(stitcher$holder, s);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this.forcePowerOf2) {
|
public void dropLargestSprite() {
|
||||||
this.currentWidth = MathHelper.roundUpToPowerOfTwo(this.currentWidth);
|
masterStitcher.dropFirst();
|
||||||
this.currentHeight = MathHelper.roundUpToPowerOfTwo(this.currentHeight);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
public void retainAllSprites(Set<ResourceLocation> spriteLocations) {
|
||||||
|
masterStitcher.retainAllSprites(spriteLocations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<EaglerTextureAtlasSprite> getStichSlots() {
|
public List<EaglerTextureAtlasSprite> getStichSlots() {
|
||||||
|
@ -306,6 +312,10 @@ public class Stitcher {
|
||||||
return this.holder;
|
return this.holder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void insertHolder(Stitcher.Holder holder) {
|
||||||
|
this.holder = holder;
|
||||||
|
}
|
||||||
|
|
||||||
public int getOriginX() {
|
public int getOriginX() {
|
||||||
return this.originX;
|
return this.originX;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue