Skip to content

Commit 31b1846

Browse files
committed
Show names and descriptions as tooltips for renderer, bvh and output mode dropdowns.
1 parent e27e28a commit 31b1846

File tree

13 files changed

+151
-77
lines changed

13 files changed

+151
-77
lines changed

chunky/src/java/se/llbit/chunky/renderer/RenderManager.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ public interface RenderManager {
3939
/**
4040
* Get all available {@code Renderer}s.
4141
*/
42-
Collection<? extends Registerable> getRenderers();
42+
Collection<Renderer> getRenderers();
4343

4444
/**
4545
* Get all available preview {@code Renderer}s.
4646
*/
47-
Collection<? extends Registerable> getPreviewRenderers();
47+
Collection<Renderer> getPreviewRenderers();
4848

4949
/**
5050
* Instructs the renderer to change its CPU load.

chunky/src/java/se/llbit/chunky/renderer/postprocessing/PostProcessingFilter.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import se.llbit.chunky.plugin.PluginApi;
44
import se.llbit.chunky.resources.BitmapImage;
5+
import se.llbit.util.Registerable;
56
import se.llbit.util.TaskTracker;
67

78
/**
@@ -14,7 +15,7 @@
1415
* PixelPostProcessingFilter} instead.
1516
*/
1617
@PluginApi
17-
public interface PostProcessingFilter {
18+
public interface PostProcessingFilter extends Registerable {
1819
/**
1920
* Post process the entire frame
2021
* @param width The width of the image
@@ -30,12 +31,14 @@ public interface PostProcessingFilter {
3031
* Get name of the post processing filter
3132
* @return The name of the post processing filter
3233
*/
34+
@Override
3335
String getName();
3436

3537
/**
3638
* Get description of the post processing filter
3739
* @return The description of the post processing filter
3840
*/
41+
@Override
3942
default String getDescription() {
4043
return null;
4144
}
@@ -44,5 +47,6 @@ default String getDescription() {
4447
* Get id of the post processing filter
4548
* @return The id of the post processing filter
4649
*/
50+
@Override
4751
String getId();
4852
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package se.llbit.chunky.ui;
2+
3+
import javafx.scene.control.Tooltip;
4+
import se.llbit.fxutil.CustomizedListCellFactory;
5+
import se.llbit.util.Registerable;
6+
7+
public class RegisterableCellAdapter implements CustomizedListCellFactory.Adapter<Registerable> {
8+
public static final RegisterableCellAdapter INSTANCE = new RegisterableCellAdapter();
9+
10+
private RegisterableCellAdapter() {
11+
}
12+
13+
@Override
14+
public String getLabel(Registerable item) {
15+
return item.getName();
16+
}
17+
18+
@Override
19+
public Tooltip getTooltip(Registerable item) {
20+
String description = item.getDescription();
21+
if (description != null && !description.isEmpty()) {
22+
return new Tooltip(item.getDescription());
23+
}
24+
return null;
25+
}
26+
}

chunky/src/java/se/llbit/chunky/ui/render/tabs/AdvancedTab.java

Lines changed: 45 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,7 @@
2727
import se.llbit.chunky.PersistentSettings;
2828
import se.llbit.chunky.launcher.LauncherSettings;
2929
import se.llbit.chunky.main.Chunky;
30-
import se.llbit.chunky.renderer.EmitterSamplingStrategy;
31-
import se.llbit.chunky.renderer.RenderController;
32-
import se.llbit.chunky.renderer.RenderManager;
30+
import se.llbit.chunky.renderer.*;
3331
import se.llbit.chunky.renderer.export.PictureExportFormat;
3432
import se.llbit.chunky.renderer.export.PictureExportFormats;
3533
import se.llbit.chunky.renderer.scene.AsynchronousSceneManager;
@@ -38,9 +36,11 @@
3836
import se.llbit.chunky.ui.Adjuster;
3937
import se.llbit.chunky.ui.DoubleAdjuster;
4038
import se.llbit.chunky.ui.IntegerAdjuster;
39+
import se.llbit.chunky.ui.RegisterableCellAdapter;
4140
import se.llbit.chunky.ui.controller.RenderControlsFxController;
4241
import se.llbit.chunky.ui.dialogs.ShutdownAlert;
4342
import se.llbit.chunky.ui.render.RenderControlsTab;
43+
import se.llbit.fxutil.CustomizedListCellFactory;
4444
import se.llbit.fxutil.Dialogs;
4545
import se.llbit.log.Log;
4646
import se.llbit.math.Octree;
@@ -72,16 +72,16 @@ public class AdvancedTab extends ScrollPane implements RenderControlsTab, Initia
7272
@FXML private DoubleAdjuster transmissivityCap;
7373
@FXML private IntegerAdjuster cacheResolution;
7474
@FXML private DoubleAdjuster animationTime;
75-
@FXML private ChoiceBox<PictureExportFormat> outputMode;
76-
@FXML private ChoiceBox<String> octreeImplementation;
75+
@FXML private ComboBox<PictureExportFormat> outputMode;
76+
@FXML private ComboBox<Octree.ImplementationFactory> octreeImplementation;
7777
@FXML private Button octreeSwitchImplementation;
78-
@FXML private ChoiceBox<String> bvhMethod;
79-
@FXML private ChoiceBox<String> biomeStructureImplementation;
78+
@FXML private ComboBox<BVH.Factory.BVHBuilder> bvhMethod;
79+
@FXML private ComboBox<BiomeStructure.Factory> biomeStructureImplementation;
8080
@FXML private IntegerAdjuster gridSize;
8181
@FXML private CheckBox preventNormalEmitterWithSampling;
8282
@FXML private CheckBox hideUnknownBlocks;
83-
@FXML private ChoiceBox<String> rendererSelect;
84-
@FXML private ChoiceBox<String> previewSelect;
83+
@FXML private ComboBox<Renderer> rendererSelect;
84+
@FXML private ComboBox<Renderer> previewSelect;
8585
@FXML private CheckBox showLauncher;
8686

8787
public AdvancedTab() throws IOException {
@@ -95,6 +95,7 @@ public AdvancedTab() throws IOException {
9595
public void initialize(URL location, ResourceBundle resources) {
9696
outputMode.getItems().addAll(PictureExportFormats.getFormats());
9797
outputMode.getSelectionModel().select(PictureExportFormats.PNG);
98+
CustomizedListCellFactory.install(outputMode, PictureExportFormat::getDescription);
9899
cpuLoad.setName("CPU utilization");
99100
cpuLoad.setTooltip("CPU utilization percentage per render thread.");
100101
cpuLoad.setRange(1, 100);
@@ -196,77 +197,76 @@ public PictureExportFormat fromString(String string) {
196197
renderControls.showPopup("This change takes effect after restarting Chunky.", renderThreads);
197198
});
198199

199-
ArrayList<String> octreeNames = new ArrayList<>();
200+
ArrayList<Octree.ImplementationFactory> octreeImplementations = new ArrayList<>();
200201
StringBuilder tooltipTextBuilder = new StringBuilder();
201202
for(Map.Entry<String, Octree.ImplementationFactory> entry : Octree.getEntries()) {
202-
octreeNames.add(entry.getKey());
203+
octreeImplementations.add(entry.getValue());
203204
tooltipTextBuilder.append(entry.getKey());
204205
tooltipTextBuilder.append(": ");
205206
tooltipTextBuilder.append(entry.getValue().getDescription());
206207
tooltipTextBuilder.append('\n');
207208
}
208209
tooltipTextBuilder.append("Requires reloading chunks to take effect.");
209-
octreeImplementation.getItems().addAll(octreeNames);
210+
octreeImplementation.getItems().addAll(octreeImplementations);
210211
octreeImplementation.getSelectionModel().selectedItemProperty()
211212
.addListener((observable, oldvalue, newvalue) -> {
212-
PersistentSettings.setOctreeImplementation(newvalue);
213-
if (!scene.getOctreeImplementation().equals(newvalue)) {
214-
scene.setOctreeImplementation(newvalue);
213+
PersistentSettings.setOctreeImplementation(newvalue.getId());
214+
if (!scene.getOctreeImplementation().equals(getId())) {
215+
scene.setOctreeImplementation(newvalue.getId());
215216
scene.softRefresh();
216217
}
217218
});
219+
CustomizedListCellFactory.install(octreeImplementation, RegisterableCellAdapter.INSTANCE);
218220
octreeImplementation.setTooltip(new Tooltip(tooltipTextBuilder.toString()));
219221

220222
octreeSwitchImplementation.setOnAction(event -> Chunky.getCommonThreads().submit(() -> {
221223
TaskTracker tracker = controller.getSceneManager().getTaskTracker();
222224
try {
223225
try (TaskTracker.Task task = tracker.task("(1/2) Converting world octree", 1000)) {
224-
scene.getWorldOctree().switchImplementation(octreeImplementation.getValue(), task);
226+
scene.getWorldOctree().switchImplementation(octreeImplementation.getValue().getId(), task);
225227
}
226228
try (TaskTracker.Task task = tracker.task("(2/2) Converting water octree")) {
227-
scene.getWaterOctree().switchImplementation(octreeImplementation.getValue(), task);
229+
scene.getWaterOctree().switchImplementation(octreeImplementation.getValue().getId(), task);
228230
}
229231
} catch (IOException e) {
230232
Log.error("Switching octrees failed. Reload the scene.\n", e);
231233
}
232234
}));
233235

234-
ArrayList<String> bvhNames = new ArrayList<>();
235236
StringBuilder bvhMethodBuilder = new StringBuilder();
236237
for (BVH.Factory.BVHBuilder builder : BVH.Factory.getImplementations()) {
237-
bvhNames.add(builder.getName());
238238
bvhMethodBuilder.append(builder.getName());
239239
bvhMethodBuilder.append(": ");
240240
bvhMethodBuilder.append(builder.getDescription());
241241
bvhMethodBuilder.append('\n');
242242
}
243243
bvhMethodBuilder.append("Requires reloading chunks to take effect.");
244-
bvhMethod.getItems().addAll(bvhNames);
245-
bvhMethod.getSelectionModel().select(PersistentSettings.getBvhMethod());
244+
bvhMethod.getItems().addAll(BVH.Factory.getImplementations());
245+
bvhMethod.getSelectionModel().select(BVH.Factory.getImplementation(PersistentSettings.getBvhMethod()));
246246
bvhMethod.getSelectionModel().selectedItemProperty()
247247
.addListener(((observable, oldValue, newValue) -> {
248-
PersistentSettings.setBvhMethod(newValue);
249-
scene.setBvhImplementation(newValue);
248+
PersistentSettings.setBvhMethod(newValue.getId());
249+
scene.setBvhImplementation(newValue.getId());
250250
scene.softRefresh();
251251
}));
252+
CustomizedListCellFactory.install(bvhMethod, RegisterableCellAdapter.INSTANCE);
252253
bvhMethod.setTooltip(new Tooltip(bvhMethodBuilder.toString()));
253254

254-
ArrayList<String> biomeStructureIds = new ArrayList<>();
255255
StringBuilder biomeStructureTooltipBuilder = new StringBuilder();
256256
for (Registerable entry : BiomeStructure.REGISTRY.values()) {
257-
biomeStructureIds.add(entry.getId());
258257
biomeStructureTooltipBuilder.append(entry.getName());
259258
biomeStructureTooltipBuilder.append(": ");
260259
biomeStructureTooltipBuilder.append(entry.getDescription());
261260
biomeStructureTooltipBuilder.append('\n');
262261
}
263262
biomeStructureTooltipBuilder.append("Requires reloading chunks to take effect.");
264-
biomeStructureImplementation.getItems().addAll(biomeStructureIds);
263+
biomeStructureImplementation.getItems().addAll(BiomeStructure.REGISTRY.values());
265264
biomeStructureImplementation.getSelectionModel().selectedItemProperty()
266265
.addListener((observable, oldvalue, newvalue) -> {
267-
scene.setBiomeStructureImplementation(newvalue);
268-
PersistentSettings.setBiomeStructureImplementation(newvalue);
266+
scene.setBiomeStructureImplementation(newvalue.getId());
267+
PersistentSettings.setBiomeStructureImplementation(newvalue.getId());
269268
});
269+
CustomizedListCellFactory.install(biomeStructureImplementation, RegisterableCellAdapter.INSTANCE);
270270
biomeStructureImplementation.setTooltip(new Tooltip(biomeStructureTooltipBuilder.toString()));
271271

272272
gridSize.setRange(4, 64);
@@ -306,11 +306,13 @@ public PictureExportFormat fromString(String string) {
306306

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

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

315317
LauncherSettings settings = new LauncherSettings();
316318
settings.load();
@@ -339,15 +341,15 @@ public void update(Scene scene) {
339341
cpuLoad.set(PersistentSettings.getCPULoad());
340342
rayDepth.set(scene.getRayDepth());
341343
branchCount.set(scene.getBranchCount());
342-
octreeImplementation.getSelectionModel().select(scene.getOctreeImplementation());
343-
bvhMethod.getSelectionModel().select(scene.getBvhImplementation());
344-
biomeStructureImplementation.getSelectionModel().select(scene.getBiomeStructureImplementation());
344+
octreeImplementation.getSelectionModel().select(Octree.getImplementation(scene.getOctreeImplementation()));
345+
bvhMethod.getSelectionModel().select(BVH.Factory.getImplementation(scene.getBvhImplementation()));
346+
biomeStructureImplementation.getSelectionModel().select(BiomeStructure.REGISTRY.get(scene.getBiomeStructureImplementation()));
345347
gridSize.set(scene.getGridSize());
346348
preventNormalEmitterWithSampling.setSelected(scene.isPreventNormalEmitterWithSampling());
347349
animationTime.set(scene.getAnimationTime());
348350
hideUnknownBlocks.setSelected(scene.getHideUnknownBlocks());
349-
rendererSelect.getSelectionModel().select(scene.getRenderer());
350-
previewSelect.getSelectionModel().select(scene.getPreviewRenderer());
351+
rendererSelect.getSelectionModel().select(DefaultRenderManager.renderers.get(scene.getRenderer()));
352+
previewSelect.getSelectionModel().select(DefaultRenderManager.previewRenderers.get(scene.getPreviewRenderer()));
351353
}
352354

353355
@Override
@@ -372,24 +374,17 @@ public void setController(RenderControlsFxController controls) {
372374
}
373375
});
374376

375-
// Set the renderers
376-
rendererSelect.getItems().clear();
377-
RenderManager renderManager = controller.getRenderManager();
378-
ArrayList<String> ids = new ArrayList<>();
379377

380-
for (Registerable renderer : renderManager.getRenderers())
381-
ids.add(renderer.getId());
378+
RenderManager renderManager = controller.getRenderManager();
382379

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

386-
// Set the preview renderers, reuse the `ids` ArrayList
385+
// Set the preview renderers
387386
previewSelect.getItems().clear();
388-
ids.clear();
389-
for (Registerable render : renderManager.getPreviewRenderers())
390-
ids.add(render.getId());
391-
392-
previewSelect.getItems().addAll(ids);
393-
previewSelect.getSelectionModel().select(scene.getPreviewRenderer());
387+
previewSelect.getItems().addAll(renderManager.getPreviewRenderers());
388+
previewSelect.getSelectionModel().select(renderManager.getPreviewRenderers().stream().filter(r -> r.getId().equals(scene.getPreviewRenderer())).findFirst().orElse(null));
394389
}
395390
}

chunky/src/java/se/llbit/math/BigPackedOctree.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ private void finalizationNode(long nodeIndex) {
460460
}
461461

462462
static public void initImplementation() {
463-
Octree.addImplementationFactory("BIGPACKED", new Octree.ImplementationFactory() {
463+
Octree.addImplementationFactory(new Octree.ImplementationFactory() {
464464
@Override
465465
public Octree.OctreeImplementation create(int depth) {
466466
return new BigPackedOctree(depth);
@@ -481,6 +481,16 @@ public boolean isOfType(Octree.OctreeImplementation implementation) {
481481
return implementation instanceof BigPackedOctree;
482482
}
483483

484+
@Override
485+
public String getId() {
486+
return "BIGPACKED";
487+
}
488+
489+
@Override
490+
public String getName() {
491+
return "Big Packed";
492+
}
493+
484494
@Override
485495
public String getDescription() {
486496
return "Almost as memory efficient as PACKED but doesn't have a limitation on the size of the octree.";

chunky/src/java/se/llbit/math/NodeBasedOctree.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ private void finalizationNode(Octree.Node node, Octree.Node parent, int childNo)
210210
}
211211

212212
static public void initImplementation() {
213-
Octree.addImplementationFactory("NODE", new Octree.ImplementationFactory() {
213+
Octree.addImplementationFactory(new Octree.ImplementationFactory() {
214214
@Override
215215
public Octree.OctreeImplementation create(int depth) {
216216
return new NodeBasedOctree(depth, new Octree.Node(0));
@@ -231,6 +231,16 @@ public boolean isOfType(Octree.OctreeImplementation implementation) {
231231
return implementation instanceof NodeBasedOctree;
232232
}
233233

234+
@Override
235+
public String getId() {
236+
return "NODE";
237+
}
238+
239+
@Override
240+
public String getName() {
241+
return "Node";
242+
}
243+
234244
@Override
235245
public String getDescription() {
236246
return "The legacy octree implementation, memory inefficient but can work with scene of any size.";

chunky/src/java/se/llbit/math/Octree.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import se.llbit.log.Log;
4040
import se.llbit.util.PositionalInputStream;
4141
import se.llbit.util.PositionalOutputStream;
42+
import se.llbit.util.Registerable;
4243
import se.llbit.util.TaskTracker;
4344

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

112113
public interface NodeId {}
113114

114-
public interface ImplementationFactory {
115+
public interface ImplementationFactory extends Registerable {
115116
OctreeImplementation create(int depth);
116117
OctreeImplementation load(DataInputStream in) throws IOException;
117118
OctreeImplementation loadWithNodeCount(long nodeCount, DataInputStream in) throws IOException;
118119
boolean isOfType(OctreeImplementation implementation);
119-
String getDescription();
120120
}
121121

122122
static private Map<String, ImplementationFactory> factories = new HashMap<>();
@@ -836,8 +836,8 @@ public OctreeImplementation getImplementation() {
836836
return implementation;
837837
}
838838

839-
public static void addImplementationFactory(String name, ImplementationFactory factory) {
840-
factories.put(name, factory);
839+
public static void addImplementationFactory(ImplementationFactory factory) {
840+
factories.put(factory.getId(), factory);
841841
}
842842

843843
static {
@@ -849,4 +849,8 @@ public static void addImplementationFactory(String name, ImplementationFactory f
849849
public static Iterable<Map.Entry<String, ImplementationFactory>> getEntries() {
850850
return factories.entrySet();
851851
}
852+
853+
public static ImplementationFactory getImplementation(String id) {
854+
return factories.get(id);
855+
}
852856
}

0 commit comments

Comments
 (0)