Skip to content

Commit

Permalink
Fix everything, it's all ready to go, also autoscrolling works! :DDDDD
Browse files Browse the repository at this point in the history
  • Loading branch information
ByThePowerOfScience committed Oct 28, 2024
1 parent 6a4c0d8 commit d7e452c
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 112 deletions.
49 changes: 27 additions & 22 deletions src/main/java/btpos/tools/mclowrespackgenerator/ArgHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@
import java.util.stream.Collectors;

public class ArgHandler {
private final boolean isHeadless;

public ArgHandler(boolean isHeadless) {
this.isHeadless = isHeadless;
}

public Args getArgs(String[] args) {
if (isHeadless)
return checkCliArgs(args);
else
return getUIArgs();
}

public Args checkCliArgs(String[] args) throws ParseException {
Option inputFilesOption = Option.builder("i")
.required()
Expand All @@ -35,12 +48,13 @@ public Args checkCliArgs(String[] args) throws ParseException {
.type(File.class)
.build();

Option widthOption = Option.builder("m")
.longOpt("max-scale")
.desc("Maximum size (in pixels) of block and item textures. Accounts for animated textures.\nIf unset, downscales to the minimum size required for the GPU to be able to load all textures.")
.hasArg()
.type(Integer.class)
.build();
Option sizeOption = Option.builder("s")
.longOpt("max-size")
.desc("Maximum size (in pixels) of block and item textures. Accounts for animated textures.\n" +
"If unset, downscales all textures to the minimum size required for the GPU to be able to load the texture atlas.")
.hasArg()
.type(Integer.class)
.build();

Option formatOption = Option.builder("p")
.longOpt("pack-format")
Expand All @@ -51,16 +65,14 @@ public Args checkCliArgs(String[] args) throws ParseException {

Options o = new Options().addOption(inputFilesOption)
.addOption(outputFileOption)
.addOption(widthOption)
.addOption(sizeOption)
.addOption(formatOption);

CommandLine parsed = new DefaultParser().parse(o, args);

return new Args(
parsed.getParsedOptionValue(widthOption),
Optional.ofNullable(parsed.getOptionValues(inputFilesOption))
.map(names -> Arrays.stream(names).map(File::new).collect(Collectors.toList()))
.orElse(null),
parsed.getParsedOptionValue(sizeOption, (Integer) null),
Arrays.stream(parsed.getOptionValues(inputFilesOption)).map(File::new).collect(Collectors.toList()),
parsed.getParsedOptionValue(outputFileOption, new File("downscaled.zip"))
);
}
Expand All @@ -70,20 +82,13 @@ public Args getUIArgs() {

File outputFile = getOutputFile();

int autoscale = JOptionPane.showOptionDialog(
null,
"Autoscale textures?",
"",
JOptionPane.YES_NO_OPTION,
JOptionPane.PLAIN_MESSAGE,
null,
null,
null
);
int autoscale = JOptionPane.showConfirmDialog(null, "Autoscale textures?");

Integer maxScale = null;
if (autoscale != JOptionPane.YES_OPTION) {
if (autoscale == JOptionPane.NO_OPTION) {
maxScale = getWidth();
} else if (autoscale == JOptionPane.CANCEL_OPTION) {
System.exit(0);
}

return new Args(maxScale, inputFiles, outputFile);
Expand Down
144 changes: 64 additions & 80 deletions src/main/java/btpos/tools/mclowrespackgenerator/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@
import org.apache.commons.io.file.PathUtils;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
Expand All @@ -36,50 +32,31 @@

public class Main {

private Args args;
private static final Path outDirectory = Files.createTempDirectory("mcdownscaler");
private static Args args;

private static final boolean IS_HEADLESS = java.awt.GraphicsEnvironment.isHeadless();

private static final int MAX_ATLAS_SIZE = 16384 * 16384;

private static final String packmcmeta = "{\n\t\"pack\":{\n\t\t\"pack_format\": 15,\n\t\t \"description\": \"Compressed textures\"\n\t}\n}";

private static final UserInterfaceHandler uiHandler = UserInterfaceHandler.get(IS_HEADLESS);

public static void main(String[] argsIn) {
try {
if (System.getProperty("os.name").toLowerCase().contains("windows"))
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ignored) {
}
uiHandler.onStart();

args = new ArgHandler(IS_HEADLESS).getArgs(argsIn);

JFrame jFrame;
if (!IS_HEADLESS) {
jFrame = UIGenerators.getConsolePanel();

EventQueue.invokeLater(() -> jFrame.setVisible(true));
} else {
jFrame = null;
if (args.outputFile.exists()) {
args.outputFile.createNewFile();
}

new Main().fileLogic(argsIn);

if (jFrame != null)
jFrame.dispose();
doCompression();
}


public void fileLogic(String[] argsIn) {
ArgHandler argHandler = new ArgHandler();
if (IS_HEADLESS)
args = argHandler.checkCliArgs(argsIn);
else
args = argHandler.getUIArgs();

args.outputFile.createNewFile();

final Path outDirectory = Files.createTempDirectory("mcdownscaler");

public static void doCompression() {
try {
List<Pair<String, Supplier<InputStream>>> name_to_stream = args.inputFiles.stream()
.map(file -> catcher(() -> new ZipFile(file), null, e -> Util.fileBad(file.getName(), e)))
Expand All @@ -92,66 +69,41 @@ public void fileLogic(String[] argsIn) {
})
.collect(Collectors.toList());

PriorityQueue<Pair<Integer, Pair<String, Supplier<InputStream>>>> texturesHeap = new PriorityQueue<>(Comparator.comparingInt(Pair<Integer, Pair<String, Supplier<InputStream>>>::getLeft).reversed());
// max heap of total size in pixels
PriorityQueue<TextureEntry> texturesHeap = new PriorityQueue<>(Comparator.comparingInt(TextureEntry::getTotalSize).reversed());

AtomicInteger totalSize = new AtomicInteger(0);

name_to_stream.stream()
.map(name_stream -> {
Dimension pngDimension = catcher(() -> Util.getPngDimension(name_stream.left, name_stream.right.get()), null, (e) -> fileBad(name_stream.left, e));
if (pngDimension == null)
return null;
return new Pair<>(pngDimension, name_stream);
}).filter(Objects::nonNull)
.map(dim_pair -> dim_pair.lmap(dim_pair.left.width * dim_pair.left.height))
.peek(size_pair -> totalSize.addAndGet(size_pair.left))
.map(str_supp -> new TextureEntry(str_supp.left, str_supp.right))
.peek(entry -> totalSize.addAndGet(entry.getTotalSize()))
.forEach(texturesHeap::add);

boolean hasOperated = false;

while (!texturesHeap.isEmpty() && totalSize.get() >= MAX_ATLAS_SIZE) {
System.out.println("Starting combined texture size (pixels): " + totalSize.get());


while (!texturesHeap.isEmpty() && (!isAutoscale() || totalSize.get() >= MAX_ATLAS_SIZE)) {
hasOperated = true;
Pair<Integer, Pair<String, Supplier<InputStream>>> tuple = texturesHeap.poll();
Integer oldSize = tuple.left;
String name = tuple.right.left;
Supplier<InputStream> is_get = tuple.right.right;
TextureEntry oldEntry = texturesHeap.poll();
int oldSize = oldEntry.getTotalSize();

TextureEntry newEntry;
try {
BufferedImage img = ImageIO.read(is_get.get());
if (img == null) {
System.err.println("Image null somehow idk");
continue;
}

int square = Util.getClosestPowerOf2(Math.max(img.getWidth(), img.getHeight()));

System.out.println("Compressing: " + name);
img = Thumbnailator.createThumbnail(img, square, square);

int newSize = img.getHeight() * img.getWidth();
totalSize.addAndGet(newSize - oldSize); // update total size


Path outPath = outDirectory.resolve(Paths.get(name));
FileUtils.createParentDirectories(outPath.toFile());

try (OutputStream outFile = Files.newOutputStream(outPath)) {
ImageIO.write(img, PathUtils.getExtension(outPath), outFile);
}

texturesHeap.add(new Pair<>(
newSize,
new Pair<>(
name,
() -> catcher(() -> Files.newInputStream(outPath), null, e -> fileBad(outPath.toString(), e))
)
));

} catch (IOException e) {
fileBad(name, e);
newEntry = compressTexture(oldEntry);
} catch (Exception e) {
fileBad(oldEntry.path, e);
continue;
}

totalSize.addAndGet(newEntry.getTotalSize() - oldSize); // update total size

if (isAutoscale())
texturesHeap.add(newEntry); // put back on the heap for possible re-resizing if needed
}


String displayText;
if (hasOperated) {
File mcmeta = outDirectory.resolve("pack.mcmeta").toFile();
Expand All @@ -163,13 +115,45 @@ public void fileLogic(String[] argsIn) {
displayText = "Nothing to do!";
}

EventQueue.invokeAndWait(() -> JOptionPane.showMessageDialog(null, displayText));
uiHandler.onFinish(displayText);
} catch (Exception e) {
throw new RuntimeException(e);
}

}

private static TextureEntry compressTexture(TextureEntry entry) {
try (InputStream is = entry.getter.get()) {
BufferedImage img = ImageIO.read(is);
if (img == null) {
throw new IOException("Image read as null: " + entry.path);
}

int square = isAutoscale() ? entry.getBestCap() : args.maxScale;

System.out.println("Compressing: " + entry.path);
img = Thumbnailator.createThumbnail(img, square, square); // does keep the aspect ratio the same


Path outPath = outDirectory.resolve(Paths.get(entry.path));
FileUtils.createParentDirectories(outPath.toFile());

try (OutputStream outFile = Files.newOutputStream(outPath)) {
ImageIO.write(img, PathUtils.getExtension(outPath), outFile);
}

return new TextureEntry(
entry.path,
() -> catcher(() -> Files.newInputStream(outPath), null, e -> fileBad(outPath.toString(), e)),
new Dimension(img.getWidth(), img.getHeight())
);
}
}

private static boolean isAutoscale() {
return args.maxScale == null;
}


public static void pack(Path sourceDirPath, String zipFilePath) throws IOException {
File f = new File(zipFilePath);
if (!f.exists())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ public synchronized void run() {
if (don >= 100) {
break;
}
textArea.setCaretPosition(textArea.getDocument().getLength());
}
if (don == lines.size()) {
lines.clear();
Expand Down
45 changes: 45 additions & 0 deletions src/main/java/btpos/tools/mclowrespackgenerator/TextureEntry.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package btpos.tools.mclowrespackgenerator;


import java.awt.Dimension;
import java.io.InputStream;
import java.util.function.Supplier;

public class TextureEntry {
public final String path;
public final Supplier<InputStream> getter;
public final Dimension dimension;

public TextureEntry(String path, Supplier<InputStream> getter) {
this(path, getter, null);
}

public TextureEntry(String path, Supplier<InputStream> getter, Dimension dimension) {
this.path = path;
this.getter = getter;
this.dimension = dimension != null ? dimension : findDimension(path, getter);
}

private static Dimension findDimension(String path, Supplier<InputStream> getter) {
return Util.getPngDimension(path, getter.get());
}

public int getTotalSize() {
return dimension.height * dimension.width;
}

public int getBestCap() {
int bigger = Math.max(dimension.height, dimension.width);
int smaller = Math.min(dimension.height, dimension.width);

// handle animated textures that are one block stretched over many
if (bigger != smaller
&& bigger % smaller == 0)
{
int ratio = bigger / smaller;
return Util.getClosestPowerOf2(smaller) * ratio;
} else {
return Util.getClosestPowerOf2(bigger);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.text.DefaultCaret;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;

public class UIGenerators {
static JFrame getConsolePanel() {
public static JFrame enableConsolePanel() {
JFrame jFrame = new JFrame();
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextArea jTextArea = new JTextArea();
JScrollPane jsp = new JScrollPane(jTextArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
jsp.getVerticalScrollBar().addAdjustmentListener(e -> jTextArea.select(jTextArea.getHeight() + 1000, 0));
jTextArea.setEditable(false);


TextAreaOutputStream tex = new TextAreaOutputStream(jTextArea);

PrintStream splitConsoleStream = new PrintStream(new OutputStream() {
Expand All @@ -32,7 +33,7 @@ public void write(int b) throws IOException {
System.setErr(splitConsoleStream);

jFrame.setSize(500, 300);
jFrame.add(jTextArea);
jFrame.add(jsp);
jFrame.setLocationRelativeTo(null);

return jFrame;
Expand Down
Loading

0 comments on commit d7e452c

Please sign in to comment.