Skip to content

Commit

Permalink
Show names and descriptions as tooltips for renderer, bvh and output …
Browse files Browse the repository at this point in the history
…mode dropdowns.
  • Loading branch information
leMaik committed Sep 9, 2023
1 parent 2a0f5a3 commit fc41ab9
Show file tree
Hide file tree
Showing 13 changed files with 151 additions and 77 deletions.
4 changes: 2 additions & 2 deletions chunky/src/java/se/llbit/chunky/renderer/RenderManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ public interface RenderManager {
/**
* Get all available {@code Renderer}s.
*/
Collection<? extends Registerable> getRenderers();
Collection<Renderer> getRenderers();

/**
* Get all available preview {@code Renderer}s.
*/
Collection<? extends Registerable> getPreviewRenderers();
Collection<Renderer> getPreviewRenderers();

/**
* Instructs the renderer to change its CPU load.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import se.llbit.chunky.plugin.PluginApi;
import se.llbit.chunky.resources.BitmapImage;
import se.llbit.util.Registerable;
import se.llbit.util.TaskTracker;

/**
Expand All @@ -14,7 +15,7 @@
* PixelPostProcessingFilter} instead.
*/
@PluginApi
public interface PostProcessingFilter {
public interface PostProcessingFilter extends Registerable {
/**
* Post process the entire frame
* @param width The width of the image
Expand All @@ -30,12 +31,14 @@ public interface PostProcessingFilter {
* Get name of the post processing filter
* @return The name of the post processing filter
*/
@Override
String getName();

/**
* Get description of the post processing filter
* @return The description of the post processing filter
*/
@Override
default String getDescription() {
return null;
}
Expand All @@ -44,5 +47,6 @@ default String getDescription() {
* Get id of the post processing filter
* @return The id of the post processing filter
*/
@Override
String getId();
}
26 changes: 26 additions & 0 deletions chunky/src/java/se/llbit/chunky/ui/RegisterableCellAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package se.llbit.chunky.ui;

import javafx.scene.control.Tooltip;
import se.llbit.fxutil.CustomizedListCellFactory;
import se.llbit.util.Registerable;

public class RegisterableCellAdapter implements CustomizedListCellFactory.Adapter<Registerable> {
public static final RegisterableCellAdapter INSTANCE = new RegisterableCellAdapter();

private RegisterableCellAdapter() {
}

@Override
public String getLabel(Registerable item) {
return item.getName();
}

@Override
public Tooltip getTooltip(Registerable item) {
String description = item.getDescription();
if (description != null && !description.isEmpty()) {
return new Tooltip(item.getDescription());
}
return null;
}
}
95 changes: 45 additions & 50 deletions chunky/src/java/se/llbit/chunky/ui/render/tabs/AdvancedTab.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@
import se.llbit.chunky.PersistentSettings;
import se.llbit.chunky.launcher.LauncherSettings;
import se.llbit.chunky.main.Chunky;
import se.llbit.chunky.renderer.EmitterSamplingStrategy;
import se.llbit.chunky.renderer.RenderController;
import se.llbit.chunky.renderer.RenderManager;
import se.llbit.chunky.renderer.*;
import se.llbit.chunky.renderer.export.PictureExportFormat;
import se.llbit.chunky.renderer.export.PictureExportFormats;
import se.llbit.chunky.renderer.scene.AsynchronousSceneManager;
Expand All @@ -38,9 +36,11 @@
import se.llbit.chunky.ui.Adjuster;
import se.llbit.chunky.ui.DoubleAdjuster;
import se.llbit.chunky.ui.IntegerAdjuster;
import se.llbit.chunky.ui.RegisterableCellAdapter;
import se.llbit.chunky.ui.controller.RenderControlsFxController;
import se.llbit.chunky.ui.dialogs.ShutdownAlert;
import se.llbit.chunky.ui.render.RenderControlsTab;
import se.llbit.fxutil.CustomizedListCellFactory;
import se.llbit.fxutil.Dialogs;
import se.llbit.log.Log;
import se.llbit.math.Octree;
Expand Down Expand Up @@ -71,16 +71,16 @@ public class AdvancedTab extends ScrollPane implements RenderControlsTab, Initia
@FXML private DoubleAdjuster transmissivityCap;
@FXML private IntegerAdjuster cacheResolution;
@FXML private DoubleAdjuster animationTime;
@FXML private ChoiceBox<PictureExportFormat> outputMode;
@FXML private ChoiceBox<String> octreeImplementation;
@FXML private ComboBox<PictureExportFormat> outputMode;
@FXML private ComboBox<Octree.ImplementationFactory> octreeImplementation;
@FXML private Button octreeSwitchImplementation;
@FXML private ChoiceBox<String> bvhMethod;
@FXML private ChoiceBox<String> biomeStructureImplementation;
@FXML private ComboBox<BVH.Factory.BVHBuilder> bvhMethod;
@FXML private ComboBox<BiomeStructure.Factory> biomeStructureImplementation;
@FXML private IntegerAdjuster gridSize;
@FXML private CheckBox preventNormalEmitterWithSampling;
@FXML private CheckBox hideUnknownBlocks;
@FXML private ChoiceBox<String> rendererSelect;
@FXML private ChoiceBox<String> previewSelect;
@FXML private ComboBox<Renderer> rendererSelect;
@FXML private ComboBox<Renderer> previewSelect;
@FXML private CheckBox showLauncher;

public AdvancedTab() throws IOException {
Expand All @@ -94,6 +94,7 @@ public AdvancedTab() throws IOException {
public void initialize(URL location, ResourceBundle resources) {
outputMode.getItems().addAll(PictureExportFormats.getFormats());
outputMode.getSelectionModel().select(PictureExportFormats.PNG);
CustomizedListCellFactory.install(outputMode, PictureExportFormat::getDescription);
cpuLoad.setName("CPU utilization");
cpuLoad.setTooltip("CPU utilization percentage per render thread.");
cpuLoad.setRange(1, 100);
Expand Down Expand Up @@ -185,77 +186,76 @@ public PictureExportFormat fromString(String string) {
renderControls.showPopup("This change takes effect after restarting Chunky.", renderThreads);
});

ArrayList<String> octreeNames = new ArrayList<>();
ArrayList<Octree.ImplementationFactory> octreeImplementations = new ArrayList<>();
StringBuilder tooltipTextBuilder = new StringBuilder();
for(Map.Entry<String, Octree.ImplementationFactory> entry : Octree.getEntries()) {
octreeNames.add(entry.getKey());
octreeImplementations.add(entry.getValue());
tooltipTextBuilder.append(entry.getKey());
tooltipTextBuilder.append(": ");
tooltipTextBuilder.append(entry.getValue().getDescription());
tooltipTextBuilder.append('\n');
}
tooltipTextBuilder.append("Requires reloading chunks to take effect.");
octreeImplementation.getItems().addAll(octreeNames);
octreeImplementation.getItems().addAll(octreeImplementations);
octreeImplementation.getSelectionModel().selectedItemProperty()
.addListener((observable, oldvalue, newvalue) -> {
PersistentSettings.setOctreeImplementation(newvalue);
if (!scene.getOctreeImplementation().equals(newvalue)) {
scene.setOctreeImplementation(newvalue);
PersistentSettings.setOctreeImplementation(newvalue.getId());
if (!scene.getOctreeImplementation().equals(getId())) {
scene.setOctreeImplementation(newvalue.getId());
scene.softRefresh();
}
});
CustomizedListCellFactory.install(octreeImplementation, RegisterableCellAdapter.INSTANCE);
octreeImplementation.setTooltip(new Tooltip(tooltipTextBuilder.toString()));

octreeSwitchImplementation.setOnAction(event -> Chunky.getCommonThreads().submit(() -> {
TaskTracker tracker = controller.getSceneManager().getTaskTracker();
try {
try (TaskTracker.Task task = tracker.task("(1/2) Converting world octree", 1000)) {
scene.getWorldOctree().switchImplementation(octreeImplementation.getValue(), task);
scene.getWorldOctree().switchImplementation(octreeImplementation.getValue().getId(), task);
}
try (TaskTracker.Task task = tracker.task("(2/2) Converting water octree")) {
scene.getWaterOctree().switchImplementation(octreeImplementation.getValue(), task);
scene.getWaterOctree().switchImplementation(octreeImplementation.getValue().getId(), task);
}
} catch (IOException e) {
Log.error("Switching octrees failed. Reload the scene.\n", e);
}
}));

ArrayList<String> bvhNames = new ArrayList<>();
StringBuilder bvhMethodBuilder = new StringBuilder();
for (BVH.Factory.BVHBuilder builder : BVH.Factory.getImplementations()) {
bvhNames.add(builder.getName());
bvhMethodBuilder.append(builder.getName());
bvhMethodBuilder.append(": ");
bvhMethodBuilder.append(builder.getDescription());
bvhMethodBuilder.append('\n');
}
bvhMethodBuilder.append("Requires reloading chunks to take effect.");
bvhMethod.getItems().addAll(bvhNames);
bvhMethod.getSelectionModel().select(PersistentSettings.getBvhMethod());
bvhMethod.getItems().addAll(BVH.Factory.getImplementations());
bvhMethod.getSelectionModel().select(BVH.Factory.getImplementation(PersistentSettings.getBvhMethod()));
bvhMethod.getSelectionModel().selectedItemProperty()
.addListener(((observable, oldValue, newValue) -> {
PersistentSettings.setBvhMethod(newValue);
scene.setBvhImplementation(newValue);
PersistentSettings.setBvhMethod(newValue.getId());
scene.setBvhImplementation(newValue.getId());
scene.softRefresh();
}));
CustomizedListCellFactory.install(bvhMethod, RegisterableCellAdapter.INSTANCE);
bvhMethod.setTooltip(new Tooltip(bvhMethodBuilder.toString()));

ArrayList<String> biomeStructureIds = new ArrayList<>();
StringBuilder biomeStructureTooltipBuilder = new StringBuilder();
for (Registerable entry : BiomeStructure.REGISTRY.values()) {
biomeStructureIds.add(entry.getId());
biomeStructureTooltipBuilder.append(entry.getName());
biomeStructureTooltipBuilder.append(": ");
biomeStructureTooltipBuilder.append(entry.getDescription());
biomeStructureTooltipBuilder.append('\n');
}
biomeStructureTooltipBuilder.append("Requires reloading chunks to take effect.");
biomeStructureImplementation.getItems().addAll(biomeStructureIds);
biomeStructureImplementation.getItems().addAll(BiomeStructure.REGISTRY.values());
biomeStructureImplementation.getSelectionModel().selectedItemProperty()
.addListener((observable, oldvalue, newvalue) -> {
scene.setBiomeStructureImplementation(newvalue);
PersistentSettings.setBiomeStructureImplementation(newvalue);
scene.setBiomeStructureImplementation(newvalue.getId());
PersistentSettings.setBiomeStructureImplementation(newvalue.getId());
});
CustomizedListCellFactory.install(biomeStructureImplementation, RegisterableCellAdapter.INSTANCE);
biomeStructureImplementation.setTooltip(new Tooltip(biomeStructureTooltipBuilder.toString()));

gridSize.setRange(4, 64);
Expand Down Expand Up @@ -295,11 +295,13 @@ public PictureExportFormat fromString(String string) {

rendererSelect.setTooltip(new Tooltip("The renderer to use for rendering."));
rendererSelect.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) ->
scene.setRenderer(newValue));
scene.setRenderer(newValue.getId()));
CustomizedListCellFactory.install(rendererSelect, RegisterableCellAdapter.INSTANCE);

previewSelect.setTooltip(new Tooltip("The renderer to use for the preview."));
previewSelect.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) ->
scene.setPreviewRenderer(newValue));
scene.setPreviewRenderer(newValue.getId()));
CustomizedListCellFactory.install(previewSelect, RegisterableCellAdapter.INSTANCE);

LauncherSettings settings = new LauncherSettings();
settings.load();
Expand Down Expand Up @@ -327,15 +329,15 @@ public void update(Scene scene) {
cpuLoad.set(PersistentSettings.getCPULoad());
rayDepth.set(scene.getRayDepth());
branchCount.set(scene.getBranchCount());
octreeImplementation.getSelectionModel().select(scene.getOctreeImplementation());
bvhMethod.getSelectionModel().select(scene.getBvhImplementation());
biomeStructureImplementation.getSelectionModel().select(scene.getBiomeStructureImplementation());
octreeImplementation.getSelectionModel().select(Octree.getImplementation(scene.getOctreeImplementation()));
bvhMethod.getSelectionModel().select(BVH.Factory.getImplementation(scene.getBvhImplementation()));
biomeStructureImplementation.getSelectionModel().select(BiomeStructure.REGISTRY.get(scene.getBiomeStructureImplementation()));
gridSize.set(scene.getGridSize());
preventNormalEmitterWithSampling.setSelected(scene.isPreventNormalEmitterWithSampling());
animationTime.set(scene.getAnimationTime());
hideUnknownBlocks.setSelected(scene.getHideUnknownBlocks());
rendererSelect.getSelectionModel().select(scene.getRenderer());
previewSelect.getSelectionModel().select(scene.getPreviewRenderer());
rendererSelect.getSelectionModel().select(DefaultRenderManager.renderers.get(scene.getRenderer()));
previewSelect.getSelectionModel().select(DefaultRenderManager.previewRenderers.get(scene.getPreviewRenderer()));
}

@Override
Expand All @@ -360,24 +362,17 @@ public void setController(RenderControlsFxController controls) {
}
});

// Set the renderers
rendererSelect.getItems().clear();
RenderManager renderManager = controller.getRenderManager();
ArrayList<String> ids = new ArrayList<>();

for (Registerable renderer : renderManager.getRenderers())
ids.add(renderer.getId());
RenderManager renderManager = controller.getRenderManager();

rendererSelect.getItems().addAll(ids);
rendererSelect.getSelectionModel().select(scene.getRenderer());
// Set the renderers
rendererSelect.getItems().clear();
rendererSelect.getItems().addAll(renderManager.getRenderers());
rendererSelect.getSelectionModel().select(renderManager.getRenderers().stream().filter(r -> r.getId().equals(scene.getRenderer())).findFirst().orElse(null));

// Set the preview renderers, reuse the `ids` ArrayList
// Set the preview renderers
previewSelect.getItems().clear();
ids.clear();
for (Registerable render : renderManager.getPreviewRenderers())
ids.add(render.getId());

previewSelect.getItems().addAll(ids);
previewSelect.getSelectionModel().select(scene.getPreviewRenderer());
previewSelect.getItems().addAll(renderManager.getPreviewRenderers());
previewSelect.getSelectionModel().select(renderManager.getPreviewRenderers().stream().filter(r -> r.getId().equals(scene.getPreviewRenderer())).findFirst().orElse(null));
}
}
12 changes: 11 additions & 1 deletion chunky/src/java/se/llbit/math/BigPackedOctree.java
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ private void finalizationNode(long nodeIndex) {
}

static public void initImplementation() {
Octree.addImplementationFactory("BIGPACKED", new Octree.ImplementationFactory() {
Octree.addImplementationFactory(new Octree.ImplementationFactory() {
@Override
public Octree.OctreeImplementation create(int depth) {
return new BigPackedOctree(depth);
Expand All @@ -481,6 +481,16 @@ public boolean isOfType(Octree.OctreeImplementation implementation) {
return implementation instanceof BigPackedOctree;
}

@Override
public String getId() {
return "BIGPACKED";
}

@Override
public String getName() {
return "Big Packed";
}

@Override
public String getDescription() {
return "Almost as memory efficient as PACKED but doesn't have a limitation on the size of the octree.";
Expand Down
12 changes: 11 additions & 1 deletion chunky/src/java/se/llbit/math/NodeBasedOctree.java
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ private void finalizationNode(Octree.Node node, Octree.Node parent, int childNo)
}

static public void initImplementation() {
Octree.addImplementationFactory("NODE", new Octree.ImplementationFactory() {
Octree.addImplementationFactory(new Octree.ImplementationFactory() {
@Override
public Octree.OctreeImplementation create(int depth) {
return new NodeBasedOctree(depth, new Octree.Node(0));
Expand All @@ -231,6 +231,16 @@ public boolean isOfType(Octree.OctreeImplementation implementation) {
return implementation instanceof NodeBasedOctree;
}

@Override
public String getId() {
return "NODE";
}

@Override
public String getName() {
return "Node";
}

@Override
public String getDescription() {
return "The legacy octree implementation, memory inefficient but can work with scene of any size.";
Expand Down
12 changes: 8 additions & 4 deletions chunky/src/java/se/llbit/math/Octree.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import se.llbit.log.Log;
import se.llbit.util.PositionalInputStream;
import se.llbit.util.PositionalOutputStream;
import se.llbit.util.Registerable;
import se.llbit.util.TaskTracker;

/**
Expand Down Expand Up @@ -111,12 +112,11 @@ default void setCube(int cubeDepth, int[] types, int x, int y, int z) {

public interface NodeId {}

public interface ImplementationFactory {
public interface ImplementationFactory extends Registerable {
OctreeImplementation create(int depth);
OctreeImplementation load(DataInputStream in) throws IOException;
OctreeImplementation loadWithNodeCount(long nodeCount, DataInputStream in) throws IOException;
boolean isOfType(OctreeImplementation implementation);
String getDescription();
}

static private Map<String, ImplementationFactory> factories = new HashMap<>();
Expand Down Expand Up @@ -836,8 +836,8 @@ public OctreeImplementation getImplementation() {
return implementation;
}

public static void addImplementationFactory(String name, ImplementationFactory factory) {
factories.put(name, factory);
public static void addImplementationFactory(ImplementationFactory factory) {
factories.put(factory.getId(), factory);
}

static {
Expand All @@ -849,4 +849,8 @@ public static void addImplementationFactory(String name, ImplementationFactory f
public static Iterable<Map.Entry<String, ImplementationFactory>> getEntries() {
return factories.entrySet();
}

public static ImplementationFactory getImplementation(String id) {
return factories.get(id);
}
}
Loading

0 comments on commit fc41ab9

Please sign in to comment.