Skip to content

Commit fc41ab9

Browse files
committed
Show names and descriptions as tooltips for renderer, bvh and output mode dropdowns.
1 parent 2a0f5a3 commit fc41ab9

13 files changed

Lines changed: 151 additions & 77 deletions

File tree

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;
@@ -71,16 +71,16 @@ public class AdvancedTab extends ScrollPane implements RenderControlsTab, Initia
7171
@FXML private DoubleAdjuster transmissivityCap;
7272
@FXML private IntegerAdjuster cacheResolution;
7373
@FXML private DoubleAdjuster animationTime;
74-
@FXML private ChoiceBox<PictureExportFormat> outputMode;
75-
@FXML private ChoiceBox<String> octreeImplementation;
74+
@FXML private ComboBox<PictureExportFormat> outputMode;
75+
@FXML private ComboBox<Octree.ImplementationFactory> octreeImplementation;
7676
@FXML private Button octreeSwitchImplementation;
77-
@FXML private ChoiceBox<String> bvhMethod;
78-
@FXML private ChoiceBox<String> biomeStructureImplementation;
77+
@FXML private ComboBox<BVH.Factory.BVHBuilder> bvhMethod;
78+
@FXML private ComboBox<BiomeStructure.Factory> biomeStructureImplementation;
7979
@FXML private IntegerAdjuster gridSize;
8080
@FXML private CheckBox preventNormalEmitterWithSampling;
8181
@FXML private CheckBox hideUnknownBlocks;
82-
@FXML private ChoiceBox<String> rendererSelect;
83-
@FXML private ChoiceBox<String> previewSelect;
82+
@FXML private ComboBox<Renderer> rendererSelect;
83+
@FXML private ComboBox<Renderer> previewSelect;
8484
@FXML private CheckBox showLauncher;
8585

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

188-
ArrayList<String> octreeNames = new ArrayList<>();
189+
ArrayList<Octree.ImplementationFactory> octreeImplementations = new ArrayList<>();
189190
StringBuilder tooltipTextBuilder = new StringBuilder();
190191
for(Map.Entry<String, Octree.ImplementationFactory> entry : Octree.getEntries()) {
191-
octreeNames.add(entry.getKey());
192+
octreeImplementations.add(entry.getValue());
192193
tooltipTextBuilder.append(entry.getKey());
193194
tooltipTextBuilder.append(": ");
194195
tooltipTextBuilder.append(entry.getValue().getDescription());
195196
tooltipTextBuilder.append('\n');
196197
}
197198
tooltipTextBuilder.append("Requires reloading chunks to take effect.");
198-
octreeImplementation.getItems().addAll(octreeNames);
199+
octreeImplementation.getItems().addAll(octreeImplementations);
199200
octreeImplementation.getSelectionModel().selectedItemProperty()
200201
.addListener((observable, oldvalue, newvalue) -> {
201-
PersistentSettings.setOctreeImplementation(newvalue);
202-
if (!scene.getOctreeImplementation().equals(newvalue)) {
203-
scene.setOctreeImplementation(newvalue);
202+
PersistentSettings.setOctreeImplementation(newvalue.getId());
203+
if (!scene.getOctreeImplementation().equals(getId())) {
204+
scene.setOctreeImplementation(newvalue.getId());
204205
scene.softRefresh();
205206
}
206207
});
208+
CustomizedListCellFactory.install(octreeImplementation, RegisterableCellAdapter.INSTANCE);
207209
octreeImplementation.setTooltip(new Tooltip(tooltipTextBuilder.toString()));
208210

209211
octreeSwitchImplementation.setOnAction(event -> Chunky.getCommonThreads().submit(() -> {
210212
TaskTracker tracker = controller.getSceneManager().getTaskTracker();
211213
try {
212214
try (TaskTracker.Task task = tracker.task("(1/2) Converting world octree", 1000)) {
213-
scene.getWorldOctree().switchImplementation(octreeImplementation.getValue(), task);
215+
scene.getWorldOctree().switchImplementation(octreeImplementation.getValue().getId(), task);
214216
}
215217
try (TaskTracker.Task task = tracker.task("(2/2) Converting water octree")) {
216-
scene.getWaterOctree().switchImplementation(octreeImplementation.getValue(), task);
218+
scene.getWaterOctree().switchImplementation(octreeImplementation.getValue().getId(), task);
217219
}
218220
} catch (IOException e) {
219221
Log.error("Switching octrees failed. Reload the scene.\n", e);
220222
}
221223
}));
222224

223-
ArrayList<String> bvhNames = new ArrayList<>();
224225
StringBuilder bvhMethodBuilder = new StringBuilder();
225226
for (BVH.Factory.BVHBuilder builder : BVH.Factory.getImplementations()) {
226-
bvhNames.add(builder.getName());
227227
bvhMethodBuilder.append(builder.getName());
228228
bvhMethodBuilder.append(": ");
229229
bvhMethodBuilder.append(builder.getDescription());
230230
bvhMethodBuilder.append('\n');
231231
}
232232
bvhMethodBuilder.append("Requires reloading chunks to take effect.");
233-
bvhMethod.getItems().addAll(bvhNames);
234-
bvhMethod.getSelectionModel().select(PersistentSettings.getBvhMethod());
233+
bvhMethod.getItems().addAll(BVH.Factory.getImplementations());
234+
bvhMethod.getSelectionModel().select(BVH.Factory.getImplementation(PersistentSettings.getBvhMethod()));
235235
bvhMethod.getSelectionModel().selectedItemProperty()
236236
.addListener(((observable, oldValue, newValue) -> {
237-
PersistentSettings.setBvhMethod(newValue);
238-
scene.setBvhImplementation(newValue);
237+
PersistentSettings.setBvhMethod(newValue.getId());
238+
scene.setBvhImplementation(newValue.getId());
239239
scene.softRefresh();
240240
}));
241+
CustomizedListCellFactory.install(bvhMethod, RegisterableCellAdapter.INSTANCE);
241242
bvhMethod.setTooltip(new Tooltip(bvhMethodBuilder.toString()));
242243

243-
ArrayList<String> biomeStructureIds = new ArrayList<>();
244244
StringBuilder biomeStructureTooltipBuilder = new StringBuilder();
245245
for (Registerable entry : BiomeStructure.REGISTRY.values()) {
246-
biomeStructureIds.add(entry.getId());
247246
biomeStructureTooltipBuilder.append(entry.getName());
248247
biomeStructureTooltipBuilder.append(": ");
249248
biomeStructureTooltipBuilder.append(entry.getDescription());
250249
biomeStructureTooltipBuilder.append('\n');
251250
}
252251
biomeStructureTooltipBuilder.append("Requires reloading chunks to take effect.");
253-
biomeStructureImplementation.getItems().addAll(biomeStructureIds);
252+
biomeStructureImplementation.getItems().addAll(BiomeStructure.REGISTRY.values());
254253
biomeStructureImplementation.getSelectionModel().selectedItemProperty()
255254
.addListener((observable, oldvalue, newvalue) -> {
256-
scene.setBiomeStructureImplementation(newvalue);
257-
PersistentSettings.setBiomeStructureImplementation(newvalue);
255+
scene.setBiomeStructureImplementation(newvalue.getId());
256+
PersistentSettings.setBiomeStructureImplementation(newvalue.getId());
258257
});
258+
CustomizedListCellFactory.install(biomeStructureImplementation, RegisterableCellAdapter.INSTANCE);
259259
biomeStructureImplementation.setTooltip(new Tooltip(biomeStructureTooltipBuilder.toString()));
260260

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

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

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

304306
LauncherSettings settings = new LauncherSettings();
305307
settings.load();
@@ -327,15 +329,15 @@ public void update(Scene scene) {
327329
cpuLoad.set(PersistentSettings.getCPULoad());
328330
rayDepth.set(scene.getRayDepth());
329331
branchCount.set(scene.getBranchCount());
330-
octreeImplementation.getSelectionModel().select(scene.getOctreeImplementation());
331-
bvhMethod.getSelectionModel().select(scene.getBvhImplementation());
332-
biomeStructureImplementation.getSelectionModel().select(scene.getBiomeStructureImplementation());
332+
octreeImplementation.getSelectionModel().select(Octree.getImplementation(scene.getOctreeImplementation()));
333+
bvhMethod.getSelectionModel().select(BVH.Factory.getImplementation(scene.getBvhImplementation()));
334+
biomeStructureImplementation.getSelectionModel().select(BiomeStructure.REGISTRY.get(scene.getBiomeStructureImplementation()));
333335
gridSize.set(scene.getGridSize());
334336
preventNormalEmitterWithSampling.setSelected(scene.isPreventNormalEmitterWithSampling());
335337
animationTime.set(scene.getAnimationTime());
336338
hideUnknownBlocks.setSelected(scene.getHideUnknownBlocks());
337-
rendererSelect.getSelectionModel().select(scene.getRenderer());
338-
previewSelect.getSelectionModel().select(scene.getPreviewRenderer());
339+
rendererSelect.getSelectionModel().select(DefaultRenderManager.renderers.get(scene.getRenderer()));
340+
previewSelect.getSelectionModel().select(DefaultRenderManager.previewRenderers.get(scene.getPreviewRenderer()));
339341
}
340342

341343
@Override
@@ -360,24 +362,17 @@ public void setController(RenderControlsFxController controls) {
360362
}
361363
});
362364

363-
// Set the renderers
364-
rendererSelect.getItems().clear();
365-
RenderManager renderManager = controller.getRenderManager();
366-
ArrayList<String> ids = new ArrayList<>();
367365

368-
for (Registerable renderer : renderManager.getRenderers())
369-
ids.add(renderer.getId());
366+
RenderManager renderManager = controller.getRenderManager();
370367

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

374-
// Set the preview renderers, reuse the `ids` ArrayList
373+
// Set the preview renderers
375374
previewSelect.getItems().clear();
376-
ids.clear();
377-
for (Registerable render : renderManager.getPreviewRenderers())
378-
ids.add(render.getId());
379-
380-
previewSelect.getItems().addAll(ids);
381-
previewSelect.getSelectionModel().select(scene.getPreviewRenderer());
375+
previewSelect.getItems().addAll(renderManager.getPreviewRenderers());
376+
previewSelect.getSelectionModel().select(renderManager.getPreviewRenderers().stream().filter(r -> r.getId().equals(scene.getPreviewRenderer())).findFirst().orElse(null));
382377
}
383378
}

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)