Refactor rendering business object management and improve rendering pipeline
- Introduced RendererWorkingSet and RendererWorkingSetImpl to manage rendering business objects (BOs) more effectively. - Updated RenderingBoPool to support acquiring and releasing BOs with unique IDs. - Enhanced G2DRenderer to utilize the new RendererWorkingSet for managing rendering operations. - Modified ControlRenderingBo and its implementations to use control IDs instead of generic IDs for better identification. - Improved G2DAbstractRenderingBo and its subclasses to streamline rendering logic and resource management. - Added unit tests for RendererWorkingSetImpl to ensure correct behavior of adding, committing, and retrieving rendering BOs. - Removed unnecessary methods and cleaned up code for better readability and maintainability.
This commit is contained in:
@@ -20,6 +20,9 @@ public class ModuleExecutorImpl implements ModuleExecutor {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
|
||||
// TODO Subscriptions for modules to run only on certain conditions
|
||||
|
||||
this.runTasks(module -> () -> {
|
||||
if (module instanceof final AbstractClientModule clientModule && this.moduleManager.getModulesDisplayedClientModules().contains(clientModule)) {
|
||||
this.invokeSafe(clientModule, AbstractClientModule::runUiPre);
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
package de.extio.game_engine.renderer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.extio.game_engine.renderer.model.RenderingBo;
|
||||
|
||||
public interface Renderer {
|
||||
|
||||
void show();
|
||||
|
||||
void run(List<RenderingBo> renderingBOs) throws InterruptedException;
|
||||
void run() throws InterruptedException;
|
||||
|
||||
void reset();
|
||||
|
||||
|
||||
@@ -15,6 +15,10 @@ import org.springframework.context.annotation.Bean;
|
||||
import de.extio.game_engine.event.EventService;
|
||||
import de.extio.game_engine.keyboard.KeycodeRegistry;
|
||||
import de.extio.game_engine.renderer.model.RenderingBo;
|
||||
import de.extio.game_engine.renderer.work.RendererWorkingSet;
|
||||
import de.extio.game_engine.renderer.work.RendererWorkingSetImpl;
|
||||
import de.extio.game_engine.renderer.work.RenderingBoPool;
|
||||
import de.extio.game_engine.renderer.work.RenderingBoPoolImpl;
|
||||
import de.extio.game_engine.storage.StorageService;
|
||||
|
||||
@AutoConfiguration
|
||||
@@ -36,6 +40,12 @@ public class RendererAutoConfiguration {
|
||||
|
||||
return new RenderingBoPoolImpl(mapping);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
RendererWorkingSet rendererWorkingSet(final RenderingBoPool rendererBoPool) {
|
||||
return new RendererWorkingSetImpl(rendererBoPool);
|
||||
}
|
||||
|
||||
@Bean
|
||||
RendererData rendererData(final ApplicationContext applicationContext,
|
||||
@@ -44,9 +54,10 @@ public class RendererAutoConfiguration {
|
||||
final RenderingBoPool renderingBoPool,
|
||||
final KeycodeRegistry keycodeRegistry,
|
||||
final EventService eventService,
|
||||
final StorageService storageService) {
|
||||
final StorageService storageService,
|
||||
final RendererWorkingSet rendererWorkingSet) {
|
||||
|
||||
final var rendererData = new RendererData(applicationContext, renderer, rendererControl, renderingBoPool, keycodeRegistry, eventService, storageService);
|
||||
final var rendererData = new RendererData(applicationContext, renderer, rendererControl, renderingBoPool, keycodeRegistry, eventService, storageService, rendererWorkingSet);
|
||||
renderer.setRendererData(rendererData);
|
||||
rendererControl.setRendererData(rendererData);
|
||||
renderingBoPool.setRendererData(rendererData);
|
||||
|
||||
@@ -9,6 +9,8 @@ import de.extio.game_engine.event.EventService;
|
||||
import de.extio.game_engine.keyboard.KeycodeRegistry;
|
||||
import de.extio.game_engine.renderer.model.options.UiOptions;
|
||||
import de.extio.game_engine.renderer.model.options.VideoOptions;
|
||||
import de.extio.game_engine.renderer.work.RendererWorkingSet;
|
||||
import de.extio.game_engine.renderer.work.RenderingBoPool;
|
||||
import de.extio.game_engine.storage.StorageService;
|
||||
|
||||
public class RendererData {
|
||||
@@ -32,10 +34,12 @@ public class RendererData {
|
||||
private final EventService eventService;
|
||||
|
||||
private final StorageService storageService;
|
||||
|
||||
private final RendererWorkingSet rendererWorkingSet;
|
||||
|
||||
private RendererLoop rendererLoop;
|
||||
|
||||
public RendererData(final ApplicationContext applicationContext, final Renderer renderer, final RendererControl rendererControl, final RenderingBoPool renderingBoPool, final KeycodeRegistry keycodeRegistry, final EventService eventService, final StorageService storageService) {
|
||||
public RendererData(final ApplicationContext applicationContext, final Renderer renderer, final RendererControl rendererControl, final RenderingBoPool renderingBoPool, final KeycodeRegistry keycodeRegistry, final EventService eventService, final StorageService storageService, final RendererWorkingSet rendererWorkingSet) {
|
||||
this.applicationContext = applicationContext;
|
||||
this.renderer = renderer;
|
||||
this.rendererControl = rendererControl;
|
||||
@@ -43,6 +47,7 @@ public class RendererData {
|
||||
this.keycodeRegistry = keycodeRegistry;
|
||||
this.eventService = eventService;
|
||||
this.storageService = storageService;
|
||||
this.rendererWorkingSet = rendererWorkingSet;
|
||||
}
|
||||
|
||||
public ApplicationContext getApplicationContext() {
|
||||
@@ -96,4 +101,8 @@ public class RendererData {
|
||||
public StorageService getStorageService() {
|
||||
return storageService;
|
||||
}
|
||||
|
||||
public RendererWorkingSet getRendererWorkingSet() {
|
||||
return rendererWorkingSet;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package de.extio.game_engine.renderer;
|
||||
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
@@ -41,7 +40,8 @@ public class RendererLoop implements Runnable {
|
||||
while (!this.shutdown) {
|
||||
try {
|
||||
this.rendererData.nextFrame();
|
||||
this.rendererData.getRenderer().run(new ArrayList<>()); // TODO: Pass actual renderables
|
||||
// TODO run modules here
|
||||
this.rendererData.getRenderer().run();
|
||||
exceptionCount = 0;
|
||||
}
|
||||
catch (final InterruptedException e) {
|
||||
|
||||
@@ -3,7 +3,7 @@ package de.extio.game_engine.renderer.container;
|
||||
import java.util.function.Function;
|
||||
|
||||
import de.extio.game_engine.renderer.RendererControl;
|
||||
import de.extio.game_engine.renderer.RenderingBoPool;
|
||||
import de.extio.game_engine.renderer.work.RenderingBoPool;
|
||||
import de.extio.game_engine.spatial2.model.Area2;
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,13 +6,13 @@ import java.util.function.Predicate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import de.extio.game_engine.renderer.RenderingBoPool;
|
||||
import de.extio.game_engine.renderer.model.RenderingBo;
|
||||
import de.extio.game_engine.renderer.model.RenderingBoLayer;
|
||||
import de.extio.game_engine.renderer.model.bo.ControlRenderingBo;
|
||||
import de.extio.game_engine.renderer.model.bo.ControlRenderingBo.SliderControl;
|
||||
import de.extio.game_engine.renderer.model.color.RgbaColor;
|
||||
import de.extio.game_engine.renderer.model.event.UiControlEvent;
|
||||
import de.extio.game_engine.renderer.work.RenderingBoPool;
|
||||
import de.extio.game_engine.spatial2.model.Area2;
|
||||
import de.extio.game_engine.spatial2.model.CoordI2;
|
||||
|
||||
@@ -57,8 +57,8 @@ public class ScrollBar {
|
||||
public void render(final List<RenderingBo> renderingBo, final Area2 renderingArea, final int numElements, final RenderingBoPool renderingBoPool) {
|
||||
this.lastNumElements = numElements;
|
||||
|
||||
final var bo = renderingBoPool.acquire(ControlRenderingBo.class)
|
||||
.setId(this.name)
|
||||
final var bo = renderingBoPool.acquire(this.name + "_Slider", ControlRenderingBo.class)
|
||||
.setControlId(this.name)
|
||||
.setType(SliderControl.class)
|
||||
.setCustomData(Boolean.FALSE)
|
||||
.setCustomData2(Double.valueOf(1.0D - this.scrollPosition))
|
||||
|
||||
@@ -9,12 +9,12 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import de.extio.game_engine.renderer.RendererControl;
|
||||
import de.extio.game_engine.renderer.RenderingBoPool;
|
||||
import de.extio.game_engine.renderer.model.RenderingBo;
|
||||
import de.extio.game_engine.renderer.model.RenderingBoLayer;
|
||||
import de.extio.game_engine.renderer.model.bo.ControlRenderingBo;
|
||||
import de.extio.game_engine.renderer.model.bo.ControlRenderingBo.WindowCloseButtonControl;
|
||||
import de.extio.game_engine.renderer.model.color.RgbaColor;
|
||||
import de.extio.game_engine.renderer.work.RenderingBoPool;
|
||||
import de.extio.game_engine.renderer.model.bo.DrawWindowRenderingBo;
|
||||
import de.extio.game_engine.spatial2.WorldUtils2;
|
||||
import de.extio.game_engine.spatial2.model.Area2;
|
||||
@@ -173,7 +173,7 @@ public class Window implements HasPositionAndDimension2, AutoCloseable {
|
||||
this.updateArea();
|
||||
}
|
||||
|
||||
var bo = this.renderingBoPool.acquire(DrawWindowRenderingBo.class)
|
||||
var bo = this.renderingBoPool.acquire(this.name + "_Window", DrawWindowRenderingBo.class)
|
||||
.setThickBorder(this.draggable)
|
||||
.withDimensionAbsolute(this.area.getDimension())
|
||||
.withPositionAbsoluteAnchorTopLeft(this.area.getPosition())
|
||||
@@ -184,9 +184,9 @@ public class Window implements HasPositionAndDimension2, AutoCloseable {
|
||||
consumer.accept(renderingBo, bo);
|
||||
|
||||
if (this.drawCloseButton) {
|
||||
bo = this.renderingBoPool.acquire(ControlRenderingBo.class)
|
||||
bo = this.renderingBoPool.acquire(this.name + "_Close", ControlRenderingBo.class)
|
||||
.setType(WindowCloseButtonControl.class)
|
||||
.setId(this.name + "_Close")
|
||||
.setControlId(this.name + "_Close")
|
||||
.setCustomData(this.draggable)
|
||||
.setEnabled(true)
|
||||
.setVisible(true)
|
||||
|
||||
@@ -8,9 +8,8 @@ import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.HashSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
@@ -25,7 +24,6 @@ import de.extio.game_engine.renderer.RendererData;
|
||||
import de.extio.game_engine.renderer.g2d.bo.rendering.G2DAbstractRenderingBo;
|
||||
import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawBackground;
|
||||
import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawFpsHistory;
|
||||
import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawImage;
|
||||
import de.extio.game_engine.renderer.g2d.control.G2DDrawControl;
|
||||
import de.extio.game_engine.renderer.g2d.control.G2DDrawControlTooltip;
|
||||
import de.extio.game_engine.renderer.model.RenderingBo;
|
||||
@@ -43,10 +41,12 @@ public class G2DRenderer implements Renderer {
|
||||
|
||||
private final RingBuffer<Integer> fpsHistory = new RingBuffer<>(90);
|
||||
|
||||
private final Set<Class<? extends RenderingBo>> releasedBoClasses = new HashSet<>();
|
||||
|
||||
private final StringBuilder fpsStringBuilder = new StringBuilder(15);
|
||||
|
||||
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(true);
|
||||
|
||||
private final List<RenderingBo> renderingBOs = new ArrayList<>();
|
||||
|
||||
private volatile G2DMainFrame mainFrame;
|
||||
|
||||
private RendererData rendererData;
|
||||
@@ -61,8 +61,6 @@ public class G2DRenderer implements Renderer {
|
||||
|
||||
private long frameDur;
|
||||
|
||||
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(true);
|
||||
|
||||
private String title;
|
||||
|
||||
private volatile boolean takeScreenshot;
|
||||
@@ -104,7 +102,7 @@ public class G2DRenderer implements Renderer {
|
||||
public void reset() {
|
||||
G2DDrawControl.reset();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
LOGGER.info("shutdown()");
|
||||
@@ -125,7 +123,7 @@ public class G2DRenderer implements Renderer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(final List<RenderingBo> renderingBOs) throws InterruptedException {
|
||||
public void run() throws InterruptedException {
|
||||
try {
|
||||
this.rwLock.readLock().lockInterruptibly();
|
||||
try {
|
||||
@@ -150,8 +148,9 @@ public class G2DRenderer implements Renderer {
|
||||
screenshotGraphics.setRenderingHints(G2DRenderingHintFactory.createDefault());
|
||||
}
|
||||
|
||||
this.addStaticRenderingBOs(renderingBOs);
|
||||
renderingBOs.sort((bo0, bo1) -> bo0.getLayer().compareTo(bo1.getLayer()));
|
||||
this.addStaticRenderingBOs();
|
||||
this.rendererData.getRendererWorkingSet().getLiveSet(this.renderingBOs);
|
||||
this.renderingBOs.sort((bo0, bo1) -> bo0.getLayer().compareTo(bo1.getLayer()));
|
||||
|
||||
Graphics2D screenGraphics = null;
|
||||
try {
|
||||
@@ -166,11 +165,11 @@ public class G2DRenderer implements Renderer {
|
||||
screenGraphics.setColor(Color.BLACK);
|
||||
screenGraphics.fillRect(0, 0, viewPortDimension.getX(), viewPortDimension.getY());
|
||||
|
||||
for (final RenderingBo renderingBO : renderingBOs) {
|
||||
if (renderingBO instanceof G2DAbstractRenderingBo) {
|
||||
((G2DAbstractRenderingBo) renderingBO).render(screenGraphics, this.rendererData.getRendererControl().getScaleFactor(), false);
|
||||
if (takeScreenshot_ && ((G2DAbstractRenderingBo) renderingBO).isScreenshotRelevant()) {
|
||||
((G2DAbstractRenderingBo) renderingBO).render(screenshotGraphics, this.rendererData.getRendererControl().getScaleFactor(), true);
|
||||
for (final RenderingBo renderingBO : this.renderingBOs) {
|
||||
if (renderingBO instanceof final G2DAbstractRenderingBo g2dAbstractRenderingBo) {
|
||||
g2dAbstractRenderingBo.render(screenGraphics, this.rendererData.getRendererControl().getScaleFactor(), false);
|
||||
if (takeScreenshot_ && g2dAbstractRenderingBo.isScreenshotRelevant()) {
|
||||
g2dAbstractRenderingBo.render(screenshotGraphics, this.rendererData.getRendererControl().getScaleFactor(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -192,14 +191,6 @@ public class G2DRenderer implements Renderer {
|
||||
if (screenGraphics != null) {
|
||||
screenGraphics.dispose();
|
||||
}
|
||||
|
||||
this.releasedBoClasses.clear();
|
||||
for (final RenderingBo renderingBO : renderingBOs) {
|
||||
if (this.releasedBoClasses.add(renderingBO.getClass()) && renderingBO instanceof final G2DAbstractRenderingBo g2dRenderingBo) {
|
||||
g2dRenderingBo.closeStatic();
|
||||
}
|
||||
this.rendererData.getRenderingBoPool().release(renderingBO);
|
||||
}
|
||||
}
|
||||
|
||||
if (takeScreenshot_) {
|
||||
@@ -207,6 +198,7 @@ public class G2DRenderer implements Renderer {
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.renderingBOs.clear();
|
||||
this.rwLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
@@ -217,13 +209,14 @@ public class G2DRenderer implements Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
private void addStaticRenderingBOs(final List<RenderingBo> renderingBOs) {
|
||||
renderingBOs.add(this.rendererData.getRenderingBoPool().acquire(G2DDrawBackground.class));
|
||||
renderingBOs.add(this.rendererData.getRenderingBoPool().acquire(G2DDrawControlTooltip.class));
|
||||
this.drawStatistics(renderingBOs);
|
||||
private void addStaticRenderingBOs() {
|
||||
this.rendererData.getRendererWorkingSet().add("G2DRenderer", this.rendererData.getRenderingBoPool().acquire("G2DRenderer_background", G2DDrawBackground.class));
|
||||
this.rendererData.getRendererWorkingSet().add("G2DRenderer", this.rendererData.getRenderingBoPool().acquire("G2DRenderer_control", G2DDrawControlTooltip.class));
|
||||
this.drawStatistics();
|
||||
this.rendererData.getRendererWorkingSet().commit("G2DRenderer", false);
|
||||
}
|
||||
|
||||
private void drawStatistics(final List<RenderingBo> renderingBOs) {
|
||||
private void drawStatistics() {
|
||||
if (!this.rendererData.getUiOptions().isDrawFps()) {
|
||||
return;
|
||||
}
|
||||
@@ -236,20 +229,20 @@ public class G2DRenderer implements Renderer {
|
||||
fpsStringBuilder.append(this.frameDur);
|
||||
fpsStringBuilder.append("ms");
|
||||
|
||||
final var drawFont = this.rendererData.getRenderingBoPool().acquire(DrawFontRenderingBo.class)
|
||||
final var drawFont = this.rendererData.getRenderingBoPool().acquire("g2DRenderer_fpsText", DrawFontRenderingBo.class)
|
||||
.setText(fpsStringBuilder.toString())
|
||||
.setSize(14)
|
||||
.setColor(RgbaColor.WHITE)
|
||||
.setLayer(RenderingBoLayer.TOP)
|
||||
.withPositionAbsoluteAnchorTopRight(100, 35);
|
||||
renderingBOs.add(drawFont);
|
||||
this.rendererData.getRendererWorkingSet().add("G2DRenderer", drawFont);
|
||||
|
||||
this.fpsHistory.add(Integer.valueOf((int) this.frameDur));
|
||||
final var drawFpsHistory = this.rendererData.getRenderingBoPool().acquire(G2DDrawFpsHistory.class)
|
||||
final var drawFpsHistory = this.rendererData.getRenderingBoPool().acquire("g2DRenderer_fpsHistory", G2DDrawFpsHistory.class)
|
||||
.setHistory(this.fpsHistory)
|
||||
.setLayer(RenderingBoLayer.TOP)
|
||||
.withPositionAbsoluteAnchorTopRight(100, 50);
|
||||
renderingBOs.add(drawFpsHistory);
|
||||
this.rendererData.getRendererWorkingSet().add("G2DRenderer", drawFpsHistory);
|
||||
}
|
||||
|
||||
private void frameCap() throws InterruptedException {
|
||||
|
||||
@@ -10,13 +10,14 @@ public abstract class G2DAbstractRenderingBo extends AbstractRenderingBo {
|
||||
public G2DAbstractRenderingBo(final RenderingBoLayer layer) {
|
||||
super(layer);
|
||||
}
|
||||
|
||||
|
||||
public boolean isScreenshotRelevant() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public abstract void render(Graphics2D graphics, double scaleFactor, boolean force);
|
||||
|
||||
@Override
|
||||
public void closeStatic() {
|
||||
|
||||
}
|
||||
|
||||
@@ -80,9 +80,6 @@ public class G2DDrawBackground extends G2DAbstractRenderingBo {
|
||||
this.loadImage(graphics, index, backgroundName);
|
||||
}
|
||||
if (G2DDrawBackground.BACKGROUND_IMAGE == null) {
|
||||
if (index == 0) {
|
||||
this.fillBlack(graphics, viewPort);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (BACKGROUND_IMAGE.validate(graphics.getDeviceConfiguration()) != VolatileImage.IMAGE_OK) {
|
||||
@@ -162,11 +159,6 @@ public class G2DDrawBackground extends G2DAbstractRenderingBo {
|
||||
}
|
||||
}
|
||||
|
||||
private void fillBlack(final Graphics2D graphics, final CoordI2 viewPort) {
|
||||
graphics.setColor(Color.BLACK);
|
||||
graphics.fillRect(0, 0, viewPort.getX(), viewPort.getY());
|
||||
}
|
||||
|
||||
private void loadImage(final Graphics2D graphics, final int index, final String backgroundName) {
|
||||
if (G2DDrawBackground.BACKGROUND_IMAGE != null) {
|
||||
G2DDrawBackground.BACKGROUND_IMAGE.flush();
|
||||
|
||||
@@ -39,7 +39,7 @@ public class G2DDrawControl extends G2DAbstractRenderingBo implements ControlRen
|
||||
|
||||
public static Map<String, List<BaseControl>> CONTROL_GROUPS = new HashMap<>();
|
||||
|
||||
private String id;
|
||||
private String controlId;
|
||||
|
||||
private Class<? extends BaseControl> clazz;
|
||||
|
||||
@@ -68,14 +68,14 @@ public class G2DDrawControl extends G2DAbstractRenderingBo implements ControlRen
|
||||
}
|
||||
|
||||
@Override
|
||||
public ControlRenderingBo setId(final String id) {
|
||||
this.id = id;
|
||||
public ControlRenderingBo setControlId(final String id) {
|
||||
this.controlId = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return this.id;
|
||||
public String getControlId() {
|
||||
return this.controlId;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -146,7 +146,7 @@ public class G2DDrawControl extends G2DAbstractRenderingBo implements ControlRen
|
||||
|
||||
@Override
|
||||
public void render(final Graphics2D graphics, final double scaleFactor, final boolean force) {
|
||||
var control = (G2DBaseControlImpl) CACHED_CONTROLS.get(this.id);
|
||||
var control = (G2DBaseControlImpl) CACHED_CONTROLS.get(this.controlId);
|
||||
if (control == null) {
|
||||
if (this.clazz == ButtonControl.class) {
|
||||
control = new G2DButtonControlImpl();
|
||||
@@ -189,7 +189,7 @@ public class G2DDrawControl extends G2DAbstractRenderingBo implements ControlRen
|
||||
control.setScaleFactor(scaleFactor)
|
||||
.setControlGroup(this.controlGroup)
|
||||
.setRendererData(this.rendererData)
|
||||
.setId(this.id);
|
||||
.setControlId(this.controlId);
|
||||
if (this.clazz == TextfieldControl.class && this.customData instanceof Boolean) {
|
||||
((TextfieldControl) control).setMultiLine(((Boolean) this.customData).booleanValue());
|
||||
}
|
||||
@@ -197,7 +197,7 @@ public class G2DDrawControl extends G2DAbstractRenderingBo implements ControlRen
|
||||
|
||||
control.build();
|
||||
|
||||
CACHED_CONTROLS.put(this.id, control);
|
||||
CACHED_CONTROLS.put(this.controlId, control);
|
||||
if (this.controlGroup != null && !this.controlGroup.isEmpty()) {
|
||||
var controls = CONTROL_GROUPS.get(this.controlGroup);
|
||||
if (controls == null) {
|
||||
@@ -315,7 +315,7 @@ public class G2DDrawControl extends G2DAbstractRenderingBo implements ControlRen
|
||||
public void close() throws Exception {
|
||||
super.close();
|
||||
|
||||
this.id = null;
|
||||
this.controlId = null;
|
||||
this.clazz = null;
|
||||
this.caption = null;
|
||||
this.controlGroup = null;
|
||||
|
||||
@@ -72,7 +72,7 @@ public abstract class G2DBaseControlImpl implements BaseControl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseControl setId(final String id) {
|
||||
public BaseControl setControlId(final String id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -234,9 +234,9 @@ public class G2DTableControlImpl extends G2DBaseControlImpl implements TableCont
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseControl setId(final String id) {
|
||||
this.scrollbar.setId(id + "_scroll");
|
||||
return super.setId(id);
|
||||
public BaseControl setControlId(final String id) {
|
||||
this.scrollbar.setControlId(id + "_scroll");
|
||||
return super.setControlId(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -353,9 +353,9 @@ public class G2DTextfieldControlImpl2 extends G2DBaseControlImpl implements Text
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseControl setId(final String id) {
|
||||
this.scrollbar.setId(id + "_scroll");
|
||||
return super.setId(id);
|
||||
public BaseControl setControlId(final String id) {
|
||||
this.scrollbar.setControlId(id + "_scroll");
|
||||
return super.setControlId(id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ public abstract class AbstractRenderingBo implements RenderingBo {
|
||||
|
||||
protected final static Logger LOGGER = LoggerFactory.getLogger(AbstractRenderingBo.class);
|
||||
|
||||
protected String id;
|
||||
|
||||
protected RendererData rendererData;
|
||||
|
||||
protected RgbaColor color;
|
||||
@@ -35,7 +37,17 @@ public abstract class AbstractRenderingBo implements RenderingBo {
|
||||
this.layer = layer;
|
||||
this.defaultLayer = layer;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setId(final String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderingBo withPositionRelative(final int x, final int y) {
|
||||
this.localX = x;
|
||||
@@ -203,6 +215,7 @@ public abstract class AbstractRenderingBo implements RenderingBo {
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
this.id = null;
|
||||
this.color = null;
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
@@ -212,6 +225,11 @@ public abstract class AbstractRenderingBo implements RenderingBo {
|
||||
this.height = 0;
|
||||
this.layer = this.defaultLayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeStatic() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRendererData(final RendererData RendererData) {
|
||||
|
||||
@@ -10,9 +10,11 @@ import de.extio.game_engine.spatial2.model.HasPosition2;
|
||||
* It is recommended to view my technical presentation on youtube about the game to learn more about how rendering works.
|
||||
*/
|
||||
public interface RenderingBo extends AutoCloseable {
|
||||
|
||||
void setRendererData(RendererData RendererData);
|
||||
|
||||
|
||||
void setId(String id);
|
||||
|
||||
String getId();
|
||||
|
||||
/**
|
||||
* Sets a color you want to use for rendering. It depends on the rendering bo how this information is treated.
|
||||
*/
|
||||
@@ -104,5 +106,9 @@ public interface RenderingBo extends AutoCloseable {
|
||||
* Positions this bo relative to it's parent. This can be for example game world for positioning tiles or a composite entity. Unit is usually not pixels but the position in the tile raster.
|
||||
*/
|
||||
RenderingBo withPositionRelative(HasPosition2 position);
|
||||
|
||||
|
||||
void closeStatic();
|
||||
|
||||
void setRendererData(RendererData RendererData);
|
||||
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@ import de.extio.game_engine.renderer.model.color.RgbaColor;
|
||||
*/
|
||||
public interface ControlRenderingBo extends RenderingBoHasDimension {
|
||||
|
||||
ControlRenderingBo setId(String id);
|
||||
ControlRenderingBo setControlId(String id);
|
||||
|
||||
String getId();
|
||||
String getControlId();
|
||||
|
||||
/**
|
||||
* Sets the type of the control. See class tree of BaseControl
|
||||
@@ -63,7 +63,7 @@ public interface ControlRenderingBo extends RenderingBoHasDimension {
|
||||
|
||||
boolean getInUse();
|
||||
|
||||
BaseControl setId(String id);
|
||||
BaseControl setControlId(String id);
|
||||
|
||||
BaseControl setCaption(String caption);
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package de.extio.game_engine.renderer.work;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import de.extio.game_engine.renderer.model.RenderingBo;
|
||||
|
||||
public interface RendererWorkingSet {
|
||||
|
||||
void add(String producer, RenderingBo work);
|
||||
|
||||
void add(String producer, List<RenderingBo> work);
|
||||
|
||||
RenderingBo get(String producer, String id);
|
||||
|
||||
Map<String, RenderingBo> getUncommittedWork(String producer);
|
||||
|
||||
Map<String, RenderingBo> commit(String producer, boolean clone);
|
||||
|
||||
void getLiveSet(List<RenderingBo> combinedLiveSet);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package de.extio.game_engine.renderer.work;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import de.extio.game_engine.renderer.model.RenderingBo;
|
||||
|
||||
public class RendererWorkingSetImpl implements RendererWorkingSet {
|
||||
|
||||
private final ConcurrentMap<String, RendererWork> workingSet = new ConcurrentHashMap<>();
|
||||
|
||||
private final BlockingQueue<Map<String, RenderingBo>> mapsPool = new ArrayBlockingQueue<>(100);
|
||||
|
||||
private final BlockingQueue<Set<Class<? extends RenderingBo>>> setsPool = new ArrayBlockingQueue<>(100);
|
||||
|
||||
private final RenderingBoPool rendererBoPool;
|
||||
|
||||
public RendererWorkingSetImpl(final RenderingBoPool rendererBoPool) {
|
||||
this.rendererBoPool = rendererBoPool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(final String producer, final RenderingBo work) {
|
||||
this.getWorkingSetByProducer(producer)
|
||||
.next()
|
||||
.put(work.getId(), work);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(final String producer, final List<RenderingBo> work) {
|
||||
final var nextMap = this.getWorkingSetByProducer(producer).next();
|
||||
for (final RenderingBo bo : work) {
|
||||
nextMap.put(bo.getId(), bo);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, RenderingBo> getUncommittedWork(final String producer) {
|
||||
return this.getWorkingSetByProducer(producer).next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderingBo get(final String producer, final String id) {
|
||||
return this.getWorkingSetByProducer(producer).next().get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, RenderingBo> commit(final String producer, final boolean clone) {
|
||||
final AtomicReference<Map<String, RenderingBo>> previousWork = new AtomicReference<>();
|
||||
final RendererWork rendererWork = this.workingSet.compute(producer, (k, v) -> {
|
||||
if (v == null) {
|
||||
return new RendererWork(this.obtainMapFromPool(), this.obtainMapFromPool());
|
||||
}
|
||||
previousWork.set(v.live());
|
||||
if (clone) {
|
||||
final Map<String, RenderingBo> newNext = this.obtainMapFromPool();
|
||||
newNext.putAll(v.next());
|
||||
return new RendererWork(v.next(), newNext);
|
||||
}
|
||||
else {
|
||||
return new RendererWork(v.next(), this.obtainMapFromPool());
|
||||
}
|
||||
});
|
||||
|
||||
final var previousWorkMap = previousWork.get();
|
||||
if (previousWorkMap != null) {
|
||||
final var releasedBoClasses = this.obtainSetFromPool();
|
||||
for (final RenderingBo renderingBO : previousWorkMap.values()) {
|
||||
if (releasedBoClasses.add(renderingBO.getClass())) {
|
||||
renderingBO.closeStatic();
|
||||
}
|
||||
this.rendererBoPool.release(renderingBO);
|
||||
}
|
||||
|
||||
this.returnMapToPool(previousWorkMap);
|
||||
this.returnSetToPool(releasedBoClasses);
|
||||
}
|
||||
|
||||
return rendererWork.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getLiveSet(final List<RenderingBo> combinedLiveSet) {
|
||||
this.workingSet.values().forEach(rendererWork -> combinedLiveSet.addAll(rendererWork.live().values()));
|
||||
}
|
||||
|
||||
private RendererWork getWorkingSetByProducer(final String producer) {
|
||||
return this.workingSet.computeIfAbsent(producer, k -> new RendererWork(this.obtainMapFromPool(), this.obtainMapFromPool()));
|
||||
}
|
||||
|
||||
private Map<String, RenderingBo> obtainMapFromPool() {
|
||||
var map = this.mapsPool.poll();
|
||||
if (map == null) {
|
||||
map = Collections.synchronizedMap(new HashMap<>());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private void returnMapToPool(final Map<String, RenderingBo> map) {
|
||||
map.clear();
|
||||
this.mapsPool.offer(map);
|
||||
}
|
||||
|
||||
private Set<Class<? extends RenderingBo>> obtainSetFromPool() {
|
||||
var set = this.setsPool.poll();
|
||||
if (set == null) {
|
||||
set = new HashSet<>();
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
private void returnSetToPool(final Set<Class<? extends RenderingBo>> set) {
|
||||
set.clear();
|
||||
this.setsPool.offer(set);
|
||||
}
|
||||
|
||||
private static record RendererWork(Map<String, RenderingBo> live, Map<String, RenderingBo> next) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package de.extio.game_engine.renderer;
|
||||
package de.extio.game_engine.renderer.work;
|
||||
|
||||
import de.extio.game_engine.renderer.RendererData;
|
||||
import de.extio.game_engine.renderer.model.RenderingBo;
|
||||
|
||||
/**
|
||||
@@ -14,7 +15,7 @@ public interface RenderingBoPool {
|
||||
/**
|
||||
* Acquires a rendering business object by type from the pool.
|
||||
*/
|
||||
<T extends RenderingBo> T acquire(Class<T> clazz);
|
||||
<T extends RenderingBo> T acquire(String id, Class<T> clazz);
|
||||
|
||||
/**
|
||||
* Releases a rendering business object back to the pool. This is usually managed by the renderer.
|
||||
@@ -1,10 +1,11 @@
|
||||
package de.extio.game_engine.renderer;
|
||||
package de.extio.game_engine.renderer.work;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
import de.extio.game_engine.renderer.RendererData;
|
||||
import de.extio.game_engine.renderer.model.RenderingBo;
|
||||
|
||||
public class RenderingBoPoolImpl implements RenderingBoPool {
|
||||
@@ -34,14 +35,14 @@ public class RenderingBoPoolImpl implements RenderingBoPool {
|
||||
|
||||
volatile Stack<RenderingBo> pooled;
|
||||
}
|
||||
|
||||
|
||||
public RenderingBoPoolImpl(final Map<Class<? extends RenderingBo>, Class<? extends RenderingBo>> mapping) {
|
||||
this.mapping = mapping;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends RenderingBo> T acquire(final Class<T> clazz) {
|
||||
public synchronized <T extends RenderingBo> T acquire(final String id, final Class<T> clazz) {
|
||||
Stack<RenderingBo> pooled;
|
||||
Class<? extends RenderingBo> impl;
|
||||
|
||||
@@ -71,8 +72,8 @@ public class RenderingBoPoolImpl implements RenderingBoPool {
|
||||
this.lastMapping.pooled = pooled;
|
||||
}
|
||||
|
||||
T instance;
|
||||
if (pooled.isEmpty()) {
|
||||
T instance;
|
||||
try {
|
||||
instance = clazz.cast(impl.getDeclaredConstructor().newInstance());
|
||||
}
|
||||
@@ -80,14 +81,17 @@ public class RenderingBoPoolImpl implements RenderingBoPool {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
instance.setRendererData(this.rendererData);
|
||||
return instance;
|
||||
}
|
||||
else {
|
||||
instance = (T) pooled.pop();
|
||||
}
|
||||
|
||||
return (T) pooled.pop();
|
||||
instance.setId(id);
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release(final RenderingBo obj) {
|
||||
public synchronized void release(final RenderingBo obj) {
|
||||
try {
|
||||
obj.close();
|
||||
|
||||
@@ -114,10 +118,10 @@ public class RenderingBoPoolImpl implements RenderingBoPool {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setRendererData(final RendererData rendererData) {
|
||||
this.rendererData = rendererData;
|
||||
this.rendererData = rendererData;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,378 @@
|
||||
package de.extio.game_engine.renderer.work;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import de.extio.game_engine.renderer.RendererData;
|
||||
import de.extio.game_engine.renderer.model.RenderingBo;
|
||||
import de.extio.game_engine.renderer.model.RenderingBoLayer;
|
||||
import de.extio.game_engine.renderer.model.color.RgbaColor;
|
||||
import de.extio.game_engine.spatial2.model.HasPosition2;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class RendererWorkingSetImplTest {
|
||||
|
||||
private RendererWorkingSetImpl workingSet;
|
||||
|
||||
private RenderingBoPool renderingBoPool;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
this.renderingBoPool = mock(RenderingBoPool.class);
|
||||
this.workingSet = new RendererWorkingSetImpl(this.renderingBoPool);
|
||||
}
|
||||
|
||||
@Test
|
||||
void addSingleAddsToUncommittedWork() {
|
||||
final RenderingBo bo1 = mock(RenderingBo.class);
|
||||
when(bo1.getId()).thenReturn("bo1");
|
||||
this.workingSet.add("producer", bo1);
|
||||
|
||||
final var uncommitted = this.workingSet.getUncommittedWork("producer");
|
||||
assertNotNull(uncommitted);
|
||||
assertEquals(Map.of("bo1", bo1), uncommitted);
|
||||
}
|
||||
|
||||
@Test
|
||||
void addListAddsAllToUncommittedWork() {
|
||||
final RenderingBo bo1 = mock(RenderingBo.class);
|
||||
when(bo1.getId()).thenReturn("bo1");
|
||||
final RenderingBo bo2 = mock(RenderingBo.class);
|
||||
when(bo2.getId()).thenReturn("bo2");
|
||||
|
||||
this.workingSet.add("producer", List.of(bo1, bo2));
|
||||
|
||||
final var uncommitted = this.workingSet.getUncommittedWork("producer");
|
||||
assertEquals(Map.of("bo1", bo1, "bo2", bo2), uncommitted);
|
||||
}
|
||||
|
||||
@Test
|
||||
void commitWithoutCloneMovesUncommittedToLiveAndClearsUncommitted() {
|
||||
final RenderingBo bo1 = mock(RenderingBo.class);
|
||||
when(bo1.getId()).thenReturn("bo1");
|
||||
final RenderingBo bo2 = mock(RenderingBo.class);
|
||||
when(bo2.getId()).thenReturn("bo2");
|
||||
|
||||
this.workingSet.add("producer", bo1);
|
||||
this.workingSet.add("producer", bo2);
|
||||
|
||||
final var returnedUncommitted = this.workingSet.commit("producer", false);
|
||||
final var currentUncommitted = this.workingSet.getUncommittedWork("producer");
|
||||
|
||||
assertSame(currentUncommitted, returnedUncommitted);
|
||||
assertTrue(currentUncommitted.isEmpty());
|
||||
|
||||
final List<RenderingBo> live = new ArrayList<>();
|
||||
this.workingSet.getLiveSet(live);
|
||||
assertEquals(2, live.size());
|
||||
assertTrue(live.containsAll(List.of(bo1, bo2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void commitWithCloneCopiesUncommittedIntoNewUncommitted() {
|
||||
final RenderingBo bo1 = mock(RenderingBo.class);
|
||||
when(bo1.getId()).thenReturn("bo1");
|
||||
final RenderingBo bo2 = mock(RenderingBo.class);
|
||||
when(bo2.getId()).thenReturn("bo2");
|
||||
final RenderingBo bo3 = mock(RenderingBo.class);
|
||||
when(bo3.getId()).thenReturn("bo3");
|
||||
|
||||
this.workingSet.add("producer", bo1);
|
||||
this.workingSet.add("producer", bo2);
|
||||
|
||||
final var returnedUncommitted = this.workingSet.commit("producer", true);
|
||||
final var currentUncommitted = this.workingSet.getUncommittedWork("producer");
|
||||
|
||||
assertSame(currentUncommitted, returnedUncommitted);
|
||||
assertEquals(Map.of("bo1", bo1, "bo2", bo2), currentUncommitted);
|
||||
|
||||
final List<RenderingBo> live = new ArrayList<>();
|
||||
this.workingSet.getLiveSet(live);
|
||||
assertEquals(2, live.size());
|
||||
assertTrue(live.containsAll(List.of(bo1, bo2)));
|
||||
|
||||
this.workingSet.add("producer", bo3);
|
||||
final List<RenderingBo> liveAfterAdd = new ArrayList<>();
|
||||
this.workingSet.getLiveSet(liveAfterAdd);
|
||||
assertEquals(2, liveAfterAdd.size());
|
||||
assertTrue(liveAfterAdd.containsAll(List.of(bo1, bo2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void liveSetContainsAllProducersCommittedWork() {
|
||||
final RenderingBo bo1 = mock(RenderingBo.class);
|
||||
when(bo1.getId()).thenReturn("bo1");
|
||||
final RenderingBo bo2 = mock(RenderingBo.class);
|
||||
when(bo2.getId()).thenReturn("bo2");
|
||||
final RenderingBo bo3 = mock(RenderingBo.class);
|
||||
when(bo3.getId()).thenReturn("bo3");
|
||||
|
||||
this.workingSet.add("p1", bo1);
|
||||
this.workingSet.add("p1", bo2);
|
||||
this.workingSet.add("p2", bo3);
|
||||
|
||||
this.workingSet.commit("p1", false);
|
||||
this.workingSet.commit("p2", false);
|
||||
|
||||
final List<RenderingBo> live = new ArrayList<>();
|
||||
this.workingSet.getLiveSet(live);
|
||||
assertEquals(3, live.size());
|
||||
assertTrue(live.containsAll(List.of(bo1, bo2, bo3)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void commitOnUnknownProducerCreatesEmptyState() {
|
||||
final var returnedUncommitted = this.workingSet.commit("unknown", false);
|
||||
assertNotNull(returnedUncommitted);
|
||||
assertTrue(returnedUncommitted.isEmpty());
|
||||
|
||||
final List<RenderingBo> live = new ArrayList<>();
|
||||
this.workingSet.getLiveSet(live);
|
||||
assertTrue(live.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void secondCommitReleasesPreviousLiveWorkAndCallsCloseStaticOncePerClass() {
|
||||
final var bo1 = new TestBoA();
|
||||
bo1.setId("bo1");
|
||||
final var bo2 = new TestBoA();
|
||||
bo2.setId("bo2");
|
||||
|
||||
this.workingSet.add("producer", bo1);
|
||||
this.workingSet.add("producer", bo2);
|
||||
this.workingSet.commit("producer", false);
|
||||
|
||||
final var bo3 = new TestBoB();
|
||||
bo3.setId("bo3");
|
||||
this.workingSet.add("producer", bo3);
|
||||
this.workingSet.commit("producer", false);
|
||||
|
||||
verify(this.renderingBoPool, times(1)).release(bo1);
|
||||
verify(this.renderingBoPool, times(1)).release(bo2);
|
||||
|
||||
// closeStatic() is called exactly once per class, so one of bo1 or bo2 has it called
|
||||
final int totalCloseStaticCallsForTestBoA = bo1.closeStaticCalls() + bo2.closeStaticCalls();
|
||||
assertEquals(1, totalCloseStaticCallsForTestBoA);
|
||||
assertEquals(0, bo3.closeStaticCalls());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getReturnsRenderingBoFromUncommittedWork() {
|
||||
final RenderingBo bo1 = mock(RenderingBo.class);
|
||||
when(bo1.getId()).thenReturn("bo1");
|
||||
final RenderingBo bo2 = mock(RenderingBo.class);
|
||||
when(bo2.getId()).thenReturn("bo2");
|
||||
|
||||
this.workingSet.add("producer", bo1);
|
||||
this.workingSet.add("producer", bo2);
|
||||
|
||||
final var retrieved1 = this.workingSet.get("producer", "bo1");
|
||||
final var retrieved2 = this.workingSet.get("producer", "bo2");
|
||||
final var notFound = this.workingSet.get("producer", "nonexistent");
|
||||
|
||||
assertSame(bo1, retrieved1);
|
||||
assertSame(bo2, retrieved2);
|
||||
assertTrue(notFound == null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getRetrievesFromUncommittedWorkOnly() {
|
||||
final RenderingBo bo1 = mock(RenderingBo.class);
|
||||
when(bo1.getId()).thenReturn("bo1");
|
||||
final RenderingBo bo2 = mock(RenderingBo.class);
|
||||
when(bo2.getId()).thenReturn("bo2");
|
||||
|
||||
this.workingSet.add("producer", bo1);
|
||||
this.workingSet.add("producer", bo2);
|
||||
final var committedWork = this.workingSet.commit("producer", false);
|
||||
|
||||
// After commit without clone, the uncommitted work should be empty
|
||||
assertTrue(committedWork.isEmpty());
|
||||
|
||||
// get() only retrieves from next set, not live set, so it returns null after commit
|
||||
final var retrieved1 = this.workingSet.get("producer", "bo1");
|
||||
final var retrieved2 = this.workingSet.get("producer", "bo2");
|
||||
|
||||
assertTrue(retrieved1 == null);
|
||||
assertTrue(retrieved2 == null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void addWithSameIdReplacesExistingRenderingBo() {
|
||||
final RenderingBo bo1 = mock(RenderingBo.class);
|
||||
when(bo1.getId()).thenReturn("bo1");
|
||||
final RenderingBo bo1_replacement = mock(RenderingBo.class);
|
||||
when(bo1_replacement.getId()).thenReturn("bo1");
|
||||
|
||||
this.workingSet.add("producer", bo1);
|
||||
final var uncommittedBefore = this.workingSet.getUncommittedWork("producer");
|
||||
assertEquals(1, uncommittedBefore.size());
|
||||
assertSame(bo1, uncommittedBefore.get("bo1"));
|
||||
|
||||
this.workingSet.add("producer", bo1_replacement);
|
||||
final var uncommittedAfter = this.workingSet.getUncommittedWork("producer");
|
||||
assertEquals(1, uncommittedAfter.size());
|
||||
assertSame(bo1_replacement, uncommittedAfter.get("bo1"));
|
||||
}
|
||||
|
||||
private static abstract class TestBoBase implements RenderingBo {
|
||||
|
||||
private final AtomicInteger closeStaticCalls = new AtomicInteger();
|
||||
|
||||
private String id;
|
||||
|
||||
@Override
|
||||
public void setId(final String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderingBo setColor(final RgbaColor color) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getY() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLocalX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLocalY() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderingBo setLayer(final RenderingBoLayer layer) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderingBoLayer getLayer() {
|
||||
return RenderingBoLayer.UI0_0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderingBo withPositionAbsoluteAnchorTopLeft(final int x, final int y) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderingBo withPositionAbsoluteAnchorTopLeft(final HasPosition2 position) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderingBo withPositionAbsoluteAnchorTopRight(final int x, final int y) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderingBo withPositionAbsoluteAnchorTopRight(final HasPosition2 position) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderingBo withPositionAbsoluteAnchorBottomLeft(final int x, final int y) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderingBo withPositionAbsoluteAnchorBottomLeft(final HasPosition2 position) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderingBo withPositionAbsoluteAnchorBottomRight(final int x, final int y) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderingBo withPositionAbsoluteAnchorBottomRight(final HasPosition2 position) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderingBo withPositionPercentual(final double x, final double y) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderingBo withPositionIncrementalAbsolute(final int x, final int y) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderingBo withPositionIncrementalAbsolute(final HasPosition2 position) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderingBo withPositionIncrementalPercentual(final double x, final double y) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderingBo withPositionRelative(final int x, final int y) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderingBo withPositionRelative(final HasPosition2 position) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeStatic() {
|
||||
this.closeStaticCalls.incrementAndGet();
|
||||
}
|
||||
|
||||
public int closeStaticCalls() {
|
||||
return this.closeStaticCalls.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRendererData(final RendererData RendererData) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class TestBoA extends TestBoBase {
|
||||
|
||||
}
|
||||
|
||||
private static final class TestBoB extends TestBoBase {
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user