Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package dev.spiritstudios.snapper.gui.screen;

import dev.spiritstudios.snapper.Snapper;
import dev.spiritstudios.snapper.util.DynamicTexture;
import dev.spiritstudios.snapper.util.DynamicCubemapTexture;
import dev.spiritstudios.snapper.util.SafeFiles;
import dev.spiritstudios.snapper.util.SnapperUtil;
import net.minecraft.client.MinecraftClient;
Expand All @@ -13,73 +13,49 @@
import net.minecraft.screen.ScreenTexts;
import net.minecraft.text.Text;
import net.minecraft.util.Colors;
import net.minecraft.util.Identifier;
import net.minecraft.util.Util;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;

public class PanoramaViewerScreen extends Screen {
protected static final CubeMapRenderer PANORAMA_RENDERER = new CubeMapRenderer(Snapper.id("screenshots/panorama/panorama"));
protected static final Identifier ID = Snapper.id("screenshots/panorama");
protected static final CubeMapRenderer PANORAMA_RENDERER = new CubeMapRenderer(ID);

protected static final RotatingCubeMapRenderer ROTATING_PANORAMA_RENDERER = new RotatingCubeMapRenderer(PANORAMA_RENDERER);

static {
ROTATING_PANORAMA_RENDERER.registerTextures(MinecraftClient.getInstance().getTextureManager());
}
private final RotatingCubeMapRenderer rotatingPanoramaRenderer = new RotatingCubeMapRenderer(PANORAMA_RENDERER);
private final DynamicCubemapTexture texture;

private final String title;
private final Screen parent;

private final List<DynamicTexture> images = new ArrayList<>();

protected PanoramaViewerScreen(String title, Screen parent) {
super(Text.translatable("menu.snapper.viewer_menu"));
this.title = title;
this.parent = parent;
this.client = MinecraftClient.getInstance();
assert this.client != null;

List<Path> facePaths = this.getImagePaths();

if (facePaths == null) {
Snapper.LOGGER.error("No panorama found");
close();
return;
}

for (Path path : facePaths) {
DynamicTexture.createPanoramaFace(this.client.getTextureManager(), path)
.ifPresent(screenshotImage -> {
images.add(screenshotImage);
screenshotImage
.load()
.thenAccept(ignored -> screenshotImage.enableFiltering());
});
}
assert client != null;
this.texture = this.getTexture();
}


private @Nullable @Unmodifiable List<Path> getImagePaths() {
@Nullable
private DynamicCubemapTexture getTexture() {
Objects.requireNonNull(this.client);

Path panoramaDir = SnapperUtil.getConfiguredScreenshotDirectory().resolve("panorama");
if (!SnapperUtil.panoramaPresent(panoramaDir)) return null;

try (Stream<Path> stream = Files.list(panoramaDir)) {
return stream
.filter(path -> {
.allMatch(path -> {
if (Files.isDirectory(path)) return false;

return SafeFiles.isContentType(path, "image/png", ".png");
})
.toList();
}) ? DynamicCubemapTexture.createPanorama(ID, panoramaDir).orElse(null) : null;
} catch (IOException | NullPointerException e) {
Snapper.LOGGER.error("Failed to list the contents of directory", e);
return null;
Expand All @@ -90,8 +66,9 @@ protected PanoramaViewerScreen(String title, Screen parent) {
public void close() {
Objects.requireNonNull(this.client);

for (DynamicTexture image : images) {
image.close();
if (texture != null) {
client.getTextureManager().destroyTexture(ID);
texture.close();
}

client.setScreen(this.parent);
Expand All @@ -101,6 +78,13 @@ public void close() {
protected void init() {
assert client != null;

if (this.texture == null) {
Snapper.LOGGER.error("No panorama found");
close();
return;
}
client.getTextureManager().registerTexture(ID, texture);

Path panoramaPath = Path.of(client.runDirectory.getPath(), "screenshots", "panorama");
addDrawableChild(ButtonWidget.builder(Text.translatable("button.snapper.folder"), button -> {
Util.getOperatingSystem().open(panoramaPath);
Expand All @@ -114,7 +98,7 @@ protected void init() {

@Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
ROTATING_PANORAMA_RENDERER.render(context, this.width, this.height, true);
rotatingPanoramaRenderer.render(context, this.width, this.height, true);

context.drawCenteredTextWithShadow(
this.textRenderer,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package dev.spiritstudios.snapper.util;

import dev.spiritstudios.snapper.Snapper;
import net.minecraft.client.resource.metadata.TextureResourceMetadata;
import net.minecraft.client.texture.CubemapTexture;
import net.minecraft.client.texture.NativeImage;
import net.minecraft.client.texture.TextureContents;
import net.minecraft.resource.ResourceManager;
import net.minecraft.util.Identifier;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;

public class DynamicCubemapTexture extends CubemapTexture {
private static final String[] TEXTURE_SUFFIXES = new String[]{"_1.png", "_3.png", "_5.png", "_4.png", "_0.png", "_2.png"};
private final Path path;

public DynamicCubemapTexture(Identifier id, Path path) {
super(id);
this.path = path;
}

@Override
public TextureContents loadContents(ResourceManager resourceManager) throws IOException {
TextureContents contents;
try (InputStream baseStream = Files.newInputStream(path.resolve("panorama" + TEXTURE_SUFFIXES[0]))) {
NativeImage baseImage = NativeImage.read(baseStream);
int width = baseImage.getWidth();
int height = baseImage.getHeight();
NativeImage image = new NativeImage(width, height * 6, false);
baseImage.copyRect(image, 0, 0, 0, 0, width, height, false, true);

for (int i = 1; i < 6; i++) {
try (InputStream panoramaStream = Files.newInputStream(path.resolve("panorama" + TEXTURE_SUFFIXES[i]))) {
NativeImage panoramaImage = NativeImage.read(panoramaStream);
if (panoramaImage.getWidth() != width || panoramaImage.getHeight() != height) {
Snapper.LOGGER.error("Image dimensions of panorama '{}' sides do not match: part 0 is {}x{}, but part {} is {}x{}", getId(), width, height, i, panoramaImage.getWidth(), panoramaImage.getHeight());
baseImage.close();
throw new IOException();
}
panoramaImage.copyRect(image, 0, 0, 0, i * height, width, height, false, true);
panoramaImage.close();
}
}

baseImage.close();
contents = new TextureContents(image, new TextureResourceMetadata(true, false));
}
return contents;
}

public static Optional<DynamicCubemapTexture> createPanorama(Identifier id, Path path) {
return Optional.of(new DynamicCubemapTexture(
id,
path
));
}
}
14 changes: 0 additions & 14 deletions src/client/java/dev/spiritstudios/snapper/util/DynamicTexture.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,6 @@ public static Optional<DynamicTexture> createScreenshot(TextureManager textureMa
}
}

public static Optional<DynamicTexture> createPanoramaFace(TextureManager textureManager, Path path) {
try {
return Optional.of(new DynamicTexture(
textureManager,
Snapper.id(
"screenshots/panorama/" + Util.replaceInvalidChars(path.getFileName().toString(), Identifier::isPathCharacterValid)
),
path
));
} catch (IOException e) {
return Optional.empty();
}
}

/*
* Must be called on render thread
*/
Expand Down