diff --git a/api/src/main/java/com/seibel/distanthorizons/api/DhApi.java b/api/src/main/java/com/seibel/distanthorizons/api/DhApi.java index a04faaad0..79f67940b 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/DhApi.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/DhApi.java @@ -23,8 +23,9 @@ import com.seibel.distanthorizons.api.interfaces.events.IDhApiEventInjector; import com.seibel.distanthorizons.api.interfaces.factories.IDhApiWrapperFactory; import com.seibel.distanthorizons.api.interfaces.override.IDhApiOverrideable; import com.seibel.distanthorizons.api.interfaces.override.worldGenerator.IDhApiWorldGeneratorOverrideRegister; -import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister; +import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderObjectFactory; import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderProxy; +import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper; import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent; import com.seibel.distanthorizons.api.methods.override.DhApiWorldGeneratorOverrideRegister; import com.seibel.distanthorizons.coreapi.ModInfo; @@ -128,11 +129,12 @@ public class DhApi */ public static IDhApiWrapperFactory wrapperFactory = null; - ///** - // * Used to add custom objects to DH's render pass. - // * @since API 3.0.0 - // */ - //public static IDhApiCustomRenderRegister renderRegister = null; + /** + * Used to create custom renderable objects.
+ * These objects can be added to the renderer in {@link IDhApiLevelWrapper} + * @since API 3.0.0 + */ + public static IDhApiCustomRenderObjectFactory customRenderObjectFactory = null; } diff --git a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/render/IDhApiCustomRenderObjectFactory.java b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/render/IDhApiCustomRenderObjectFactory.java new file mode 100644 index 000000000..7e78e0c60 --- /dev/null +++ b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/render/IDhApiCustomRenderObjectFactory.java @@ -0,0 +1,26 @@ +package com.seibel.distanthorizons.api.interfaces.render; + +import com.seibel.distanthorizons.api.objects.math.DhApiVec3f; +import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox; + +import java.util.List; + +/** + * Handles creating + * {@link IDhApiRenderableBoxGroup} objects, + * which can be added via a {@link IDhApiCustomRenderRegister}. + * + * @see IDhApiCustomRenderRegister + * @see IDhApiRenderableBoxGroup + * + * @author James Seibel + * @version 2024-7-3 + * @since API 3.0.0 + */ +public interface IDhApiCustomRenderObjectFactory +{ + IDhApiRenderableBoxGroup createForSingleBox(DhApiRenderableBox cube); + IDhApiRenderableBoxGroup createRelativePositionedGroup(DhApiVec3f originBlockPos, List cubeList); + IDhApiRenderableBoxGroup createAbsolutePositionedGroup(List cubeList); + +} diff --git a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/render/IDhApiCustomRenderRegister.java b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/render/IDhApiCustomRenderRegister.java index 6b9b06daf..c156c0c8c 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/render/IDhApiCustomRenderRegister.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/render/IDhApiCustomRenderRegister.java @@ -1,18 +1,24 @@ package com.seibel.distanthorizons.api.interfaces.render; -import com.seibel.distanthorizons.api.objects.math.DhApiVec3f; -import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox; - -import java.util.List; +import com.seibel.distanthorizons.api.DhApi; +import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper; +import com.seibel.distanthorizons.api.interfaces.world.IDhApiWorldProxy; /** - * Handles adding, removing, and creating + * Handles adding and removing * {@link IDhApiRenderableBoxGroup} objects, - * which can be used to render custom objects into - * DH's terrain. + * from DH's renderer.

+ * + * Can be accessed in + * {@link DhApi.Delayed#worldProxy} -> {@link IDhApiLevelWrapper}. + * + * @see IDhApiCustomRenderObjectFactory + * @see IDhApiRenderableBoxGroup + * @see IDhApiWorldProxy + * @see IDhApiLevelWrapper * * @author James Seibel - * @version 2024-6-30 + * @version 2024-7-3 * @since API 3.0.0 */ public interface IDhApiCustomRenderRegister @@ -21,9 +27,4 @@ public interface IDhApiCustomRenderRegister IDhApiRenderableBoxGroup remove(long id); - - IDhApiRenderableBoxGroup createForSingleBox(DhApiRenderableBox cube); - IDhApiRenderableBoxGroup createRelativePositionedGroup(DhApiVec3f originBlockPos, List cubeList); - IDhApiRenderableBoxGroup createAbsolutePositionedGroup(List cubeList); - } diff --git a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/world/IDhApiLevelWrapper.java b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/world/IDhApiLevelWrapper.java index 2583dfb4a..30d9e161c 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/world/IDhApiLevelWrapper.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/world/IDhApiLevelWrapper.java @@ -21,6 +21,7 @@ package com.seibel.distanthorizons.api.interfaces.world; import com.seibel.distanthorizons.api.interfaces.IDhApiUnsafeWrapper; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType; +import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister; /** * Can be either a Server or Client level.
@@ -49,4 +50,10 @@ public interface IDhApiLevelWrapper extends IDhApiUnsafeWrapper */ default int getMinHeight() { return 0; } + /** + * Will return null if called on the server, + * or if called before the renderer has been set up. + */ + IDhApiCustomRenderRegister getRenderRegister(); + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/Initializer.java b/core/src/main/java/com/seibel/distanthorizons/core/Initializer.java index dbf715181..91a4d88f7 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/Initializer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/Initializer.java @@ -20,7 +20,7 @@ package com.seibel.distanthorizons.core; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; -import com.seibel.distanthorizons.core.render.renderer.GenericObjectRenderer; +import com.seibel.distanthorizons.core.render.renderer.GenericRenderObjectFactory; import com.seibel.distanthorizons.core.sql.DatabaseUpdater; import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory; import com.seibel.distanthorizons.coreapi.ModInfo; @@ -94,7 +94,7 @@ public class Initializer DhApi.Delayed.terrainRepo = DhApiTerrainDataRepo.INSTANCE; DhApi.Delayed.worldProxy = DhApiWorldProxy.INSTANCE; DhApi.Delayed.renderProxy = DhApiRenderProxy.INSTANCE; - //DhApi.Delayed.renderRegister = GenericObjectRenderer.INSTANCE; + DhApi.Delayed.customRenderObjectFactory = GenericRenderObjectFactory.INSTANCE; DhApi.Delayed.wrapperFactory = SingletonInjector.INSTANCE.get(IWrapperFactory.class); if (DhApi.Delayed.wrapperFactory == null) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhLevel.java index 56eb78972..5ecc362dc 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhLevel.java @@ -31,6 +31,7 @@ import com.seibel.distanthorizons.core.pos.DhBlockPos; import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.render.renderer.GenericObjectRenderer; +import com.seibel.distanthorizons.core.render.renderer.GenericRenderObjectFactory; import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO; import com.seibel.distanthorizons.core.sql.dto.ChunkHashDTO; import com.seibel.distanthorizons.core.sql.repo.BeaconBeamRepo; @@ -207,6 +208,8 @@ public abstract class AbstractDhLevel implements IDhLevel public void setBeaconBeamsForChunk(DhChunkPos chunkPos, List newBeamList) { GenericObjectRenderer genericObjectRenderer = this.getGenericRenderer(); + + // should always be non-null, but just in case if (this.beaconBeamRepo != null && genericObjectRenderer != null) { @@ -253,7 +256,7 @@ public abstract class AbstractDhLevel implements IDhLevel // new beam found, add to DB this.beaconBeamRepo.save(newBeam); - IDhApiRenderableBoxGroup beaconBox = genericObjectRenderer.createForSingleBox(new DhApiRenderableBox( + IDhApiRenderableBoxGroup beaconBox = GenericRenderObjectFactory.INSTANCE.createForSingleBox(new DhApiRenderableBox( new DhApiVec3f(newBeam.pos.x, newBeam.pos.y+1, newBeam.pos.z), new DhApiVec3f(newBeam.pos.x+1, 6_000, newBeam.pos.z+1), newBeam.color @@ -295,6 +298,8 @@ public abstract class AbstractDhLevel implements IDhLevel public void loadBeaconBeamsInPos(long pos) { GenericObjectRenderer genericObjectRenderer = this.getGenericRenderer(); + + // should always be non-null, but just in case if (this.beaconBeamRepo != null && genericObjectRenderer != null) { @@ -304,7 +309,7 @@ public abstract class AbstractDhLevel implements IDhLevel { BeaconBeamDTO beam = existingBeamList.get(i); - IDhApiRenderableBoxGroup beaconBox = genericObjectRenderer.createForSingleBox(new DhApiRenderableBox( + IDhApiRenderableBoxGroup beaconBox = GenericRenderObjectFactory.INSTANCE.createForSingleBox(new DhApiRenderableBox( new DhApiVec3f(beam.pos.x, beam.pos.y+1, beam.pos.z), new DhApiVec3f(beam.pos.x+1, 6_000, beam.pos.z+1), beam.color @@ -335,6 +340,8 @@ public abstract class AbstractDhLevel implements IDhLevel public void unloadBeaconBeamsInPos(long pos) { GenericObjectRenderer genericObjectRenderer = this.getGenericRenderer(); + + // should always be non-null, but just in case if (this.beaconBeamRepo != null && genericObjectRenderer != null) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java index 166b0a1df..1f7e19a9b 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java @@ -60,6 +60,7 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel public DhClientLevel(AbstractSaveStructure saveStructure, IClientLevelWrapper clientLevelWrapper, @Nullable File fullDataSaveDirOverride, boolean enableRendering) { this.levelWrapper = clientLevelWrapper; + this.levelWrapper.setParentClientLevel(this); this.saveStructure = saveStructure; this.dataFileHandler = new RemoteFullDataSourceProvider(this, saveStructure, fullDataSaveDirOverride); this.clientside = new ClientLevelModule(this); @@ -156,10 +157,11 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel @Override public void close() { + this.levelWrapper.setParentClientLevel(null); this.clientside.close(); super.close(); this.dataFileHandler.close(); - LOGGER.info("Closed " + DhClientLevel.class.getSimpleName() + " for " + levelWrapper); + LOGGER.info("Closed [" + DhClientLevel.class.getSimpleName() + "] for [" + this.levelWrapper + "]"); } @Override diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java index 0b950ed39..c6b4c6911 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java @@ -41,6 +41,10 @@ public class DhServerLevel extends AbstractDhLevel implements IDhServerLevel + //=============// + // constructor // + //=============// + public DhServerLevel(AbstractSaveStructure saveStructure, IServerLevelWrapper serverLevelWrapper) { if (saveStructure.getFullDataFolder(serverLevelWrapper).mkdirs()) @@ -56,6 +60,10 @@ public class DhServerLevel extends AbstractDhLevel implements IDhServerLevel + //=========// + // methods // + //=========// + public void serverTick() { this.chunkToLodBuilder.tick(); } @Override diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/GenericObjectRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/GenericObjectRenderer.java index ea73498bd..420a4a3fa 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/GenericObjectRenderer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/GenericObjectRenderer.java @@ -19,7 +19,6 @@ package com.seibel.distanthorizons.core.render.renderer; -import com.seibel.distanthorizons.api.DhApi; import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod; import com.seibel.distanthorizons.api.enums.config.EDhApiLoggerMode; import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup; @@ -27,12 +26,10 @@ import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegist import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam; import com.seibel.distanthorizons.api.objects.math.DhApiVec3f; import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox; -import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.logging.ConfigBasedSpamLogger; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.f3.F3Screen; -import com.seibel.distanthorizons.core.pos.DhBlockPos; import com.seibel.distanthorizons.core.render.glObject.GLProxy; import com.seibel.distanthorizons.core.render.glObject.GLState; import com.seibel.distanthorizons.core.render.glObject.buffer.GLElementBuffer; @@ -234,8 +231,11 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister } private void addGenericDebugObjects() { + GenericRenderObjectFactory factory = GenericRenderObjectFactory.INSTANCE; + + // single giant box - IDhApiRenderableBoxGroup singleGiantBoxGroup = this.createForSingleBox( + IDhApiRenderableBoxGroup singleGiantBoxGroup = factory.createForSingleBox( new DhApiRenderableBox( new DhApiVec3f(0f,0f,0f), new DhApiVec3f(16f,190f,16f), new Color(Color.CYAN.getRed(), Color.CYAN.getGreen(), Color.CYAN.getBlue(), 125)) @@ -246,7 +246,7 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister // single slender box - IDhApiRenderableBoxGroup singleTallBoxGroup = this.createForSingleBox( + IDhApiRenderableBoxGroup singleTallBoxGroup = factory.createForSingleBox( new DhApiRenderableBox( new DhApiVec3f(16f,0f,31f), new DhApiVec3f(17f,2000f,32f), new Color(Color.GREEN.getRed(), Color.GREEN.getGreen(), Color.GREEN.getBlue(), 125)) @@ -264,7 +264,7 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister new DhApiVec3f(0f+i,150f+i,24f), new DhApiVec3f(1f+i,151f+i,25f), new Color(Color.ORANGE.getRed(), Color.ORANGE.getGreen(), Color.ORANGE.getBlue()))); } - IDhApiRenderableBoxGroup absolutePosBoxGroup = this.createAbsolutePositionedGroup(absBoxList); + IDhApiRenderableBoxGroup absolutePosBoxGroup = factory.createAbsolutePositionedGroup(absBoxList); this.add(absolutePosBoxGroup); @@ -276,7 +276,7 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister new DhApiVec3f(0f,0f+i,0f), new DhApiVec3f(1f,1f+i,1f), new Color(Color.MAGENTA.getRed(), Color.MAGENTA.getGreen(), Color.MAGENTA.getBlue()))); } - IDhApiRenderableBoxGroup relativePosBoxGroup = this.createRelativePositionedGroup( + IDhApiRenderableBoxGroup relativePosBoxGroup = factory.createRelativePositionedGroup( new DhApiVec3f(24f, 140f, 24f), relBoxList); relativePosBoxGroup.setPreRenderFunc((event) -> @@ -300,7 +300,7 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister new Color(Color.RED.getRed(), Color.RED.getGreen(), Color.RED.getBlue()))); } } - IDhApiRenderableBoxGroup massRelativePosBoxGroup = this.createRelativePositionedGroup( + IDhApiRenderableBoxGroup massRelativePosBoxGroup = factory.createRelativePositionedGroup( new DhApiVec3f(-25f, 140f, 0f), massRelBoxList); massRelativePosBoxGroup.setPreRenderFunc((event) -> @@ -323,29 +323,6 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister - - //================// - // group creation // - //================// - - @Override - public IDhApiRenderableBoxGroup createForSingleBox(DhApiRenderableBox box) - { - ArrayList list = new ArrayList<>(); - list.add(box); - return this.createAbsolutePositionedGroup(list); - } - - @Override - public IDhApiRenderableBoxGroup createRelativePositionedGroup(DhApiVec3f originBlockPos, List boxList) - { return new RenderableBoxGroup(new Vec3f(originBlockPos), boxList, true); } - - @Override - public IDhApiRenderableBoxGroup createAbsolutePositionedGroup(List boxList) - { return new RenderableBoxGroup(new Vec3f(0, 0, 0), boxList, false); } - - - //==============// // registration // //==============// @@ -355,7 +332,7 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister { if (!(iBoxGroup instanceof RenderableBoxGroup)) { - throw new IllegalArgumentException("Box group must be of type ["+ RenderableBoxGroup.class.getSimpleName()+"]."); + throw new IllegalArgumentException("Box group must be of type ["+ RenderableBoxGroup.class.getSimpleName()+"], type received: ["+(iBoxGroup != null ? iBoxGroup.getClass() : "NULL")+"]."); } RenderableBoxGroup boxGroup = (RenderableBoxGroup) iBoxGroup; @@ -493,9 +470,9 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister this.shader.setUniform(this.instancedShaderOffsetUniform, new Vec3f( - boxGroup.originBlockPos.x, - boxGroup.originBlockPos.y, - boxGroup.originBlockPos.z + boxGroup.getOriginBlockPos().x, + boxGroup.getOriginBlockPos().y, + boxGroup.getOriginBlockPos().z )); this.shader.setUniform(this.instancedShaderCameraPosUniform, @@ -577,7 +554,7 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister this.shader.setUniform(this.skyLightUniform, boxGroup.skyLight); this.shader.setUniform(this.blockLightUniform, boxGroup.blockLight); - for (DhApiRenderableBox box : boxGroup.boxList) + for (DhApiRenderableBox box : boxGroup) { renderBox(boxGroup, box, transformMatrix, camPos); } @@ -591,9 +568,9 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister float originOffsetZ = 0; if (boxGroup.positionBoxesRelativeToGroupOrigin) { - originOffsetX = boxGroup.originBlockPos.x; - originOffsetY = boxGroup.originBlockPos.y; - originOffsetZ = boxGroup.originBlockPos.z; + originOffsetX = boxGroup.getOriginBlockPos().x; + originOffsetY = boxGroup.getOriginBlockPos().y; + originOffsetZ = boxGroup.getOriginBlockPos().z; } Mat4f boxTransform = Mat4f.createTranslateMatrix( @@ -640,259 +617,4 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister return LodUtil.formatLog("Generic Obj Count: " + activeCountText + "/" + totalCountText); } - - - //================// - // helper classes // - //================// - - private static final class RenderableBoxGroup - extends AbstractList - implements IDhApiRenderableBoxGroup, Closeable - { - public final static AtomicInteger NEXT_ID_ATOMIC_INT = new AtomicInteger(0); - - - - public final long id; - - /** If false the boxes will be positioned relative to the level's origin */ - public final boolean positionBoxesRelativeToGroupOrigin; - - private final ArrayList boxList; - - private final Vec3f originBlockPos; - - public int skyLight = 15; - public int blockLight = 0; - - @Nullable - public Consumer beforeRenderFunc; - - private boolean vertexDataDirty = true; - public boolean active = true; - - // instance data - private int instanceTranslationVbo = 0; - private int instanceScaleVbo = 0; - private int instanceColorVbo = 0; - - - - // setters/getters // - - @Override - public long getId() { return this.id; } - - @Override - public void setOriginBlockPos(DhApiVec3f pos) - { - this.originBlockPos.x = pos.x; - this.originBlockPos.y = pos.y; - this.originBlockPos.z = pos.z; - } - - @Override - public DhApiVec3f getOriginBlockPos() { return new DhApiVec3f(this.originBlockPos.x, this.originBlockPos.y, this.originBlockPos.z); } - - - @Override - public void setSkyLight(int skyLight) - { - if (skyLight < LodUtil.MIN_MC_LIGHT || skyLight > LodUtil.MAX_MC_LIGHT) - { - throw new IllegalArgumentException("Sky light ["+skyLight+"] must be between ["+LodUtil.MIN_MC_LIGHT+"] and ["+LodUtil.MAX_MC_LIGHT+"] (inclusive)."); - } - this.skyLight = skyLight; - } - @Override - public int getSkyLight() { return this.skyLight; } - - @Override - public void setBlockLight(int blockLight) - { - if (blockLight < LodUtil.MIN_MC_LIGHT || blockLight > LodUtil.MAX_MC_LIGHT) - { - throw new IllegalArgumentException("Block light ["+blockLight+"] must be between ["+LodUtil.MIN_MC_LIGHT+"] and ["+LodUtil.MAX_MC_LIGHT+"] (inclusive)."); - } - this.blockLight = blockLight; - } - @Override - public int getBlockLight() { return this.blockLight; } - - - - //=============// - // constructor // - //=============// - - public RenderableBoxGroup(Vec3f originBlockPos, List boxList, boolean positionBoxesRelativeToGroupOrigin) - { - // TODO save to database - // TODO when? - - this.id = NEXT_ID_ATOMIC_INT.getAndIncrement(); - this.boxList = new ArrayList<>(boxList); - - this.originBlockPos = originBlockPos; - this.positionBoxesRelativeToGroupOrigin = positionBoxesRelativeToGroupOrigin; - } - - - - // methods // - - @Override - public boolean add(DhApiRenderableBox box) { return this.boxList.add(box); } - - @Override - public void setPreRenderFunc(Consumer func) { this.beforeRenderFunc = func; } - - @Override - public void triggerBoxChange() { this.vertexDataDirty = true; } - - @Override - public void setActive(boolean active) { this.active = active; } - @Override - public boolean isActive() { return this.active; } - - public void preRender(DhApiRenderParam renderEventParam) - { - if (this.beforeRenderFunc != null) - { - beforeRenderFunc.accept(renderEventParam); - } - } - - - - // overrides // - - @Override - public DhApiRenderableBox get(int index) { return this.boxList.get(index); } - @Override - public int size() { return this.boxList.size(); } - @Override - public boolean removeIf(Predicate filter) { return this.boxList.removeIf(filter); } - @Override - public void replaceAll(UnaryOperator operator) { this.boxList.replaceAll(operator); } - @Override - public void sort(Comparator c) { this.boxList.sort(c); } - @Override - public void forEach(Consumer action) { this.boxList.forEach(action); } - @Override - public Spliterator spliterator() { return this.boxList.spliterator(); } - @Override - public Stream stream() { return this.boxList.stream(); } - @Override - public Stream parallelStream() { return this.boxList.parallelStream(); } - - - - //===================// - // vertex attributes // - //===================// - - /** Does nothing if the vertex data is already up-to-date */ - private void updateVertexAttributeData() - { - if (!this.vertexDataDirty) - { - return; - } - this.vertexDataDirty = false; - - if (this.instanceTranslationVbo == 0) - { - this.instanceTranslationVbo = GL32.glGenBuffers(); - this.instanceScaleVbo = GL32.glGenBuffers(); - this.instanceColorVbo = GL32.glGenBuffers(); - } - - int boxCount = this.size(); - - - // transformation / scaling // - - float[] translationData = new float[boxCount * 3]; - float[] scalingData = new float[boxCount * 3]; - for (int i = 0; i < boxCount; i++) - { - DhApiRenderableBox box = this.get(i); - - int dataIndex = i * 3; - - translationData[dataIndex] = box.minPos.x; - translationData[dataIndex + 1] = box.minPos.y; - translationData[dataIndex + 2] = box.minPos.z; - - scalingData[dataIndex] = box.maxPos.x - box.minPos.x; - scalingData[dataIndex + 1] = box.maxPos.y - box.minPos.y; - scalingData[dataIndex + 2] = box.maxPos.z - box.minPos.z; - - } - - - // colors // - - float[] colorData = new float[boxCount * 4]; - for (int i = 0; i < boxCount; i++) - { - DhApiRenderableBox box = this.get(i); - Color color = box.color; - int colorIndex = i * 4; - colorData[colorIndex] = color.getRed() / 255.0f; - colorData[colorIndex + 1] = color.getGreen() / 255.0f; - colorData[colorIndex + 2] = color.getBlue() / 255.0f; - colorData[colorIndex + 3] = color.getAlpha() / 255.0f; - } - - - // Upload transformation matrices - GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.instanceTranslationVbo); - GL32.glBufferData(GL32.GL_ARRAY_BUFFER, translationData ,GL32.GL_DYNAMIC_DRAW); - GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.instanceScaleVbo); - GL32.glBufferData(GL32.GL_ARRAY_BUFFER, scalingData, GL32.GL_DYNAMIC_DRAW); - - // Upload colors - GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.instanceColorVbo); - GL32.glBufferData(GL32.GL_ARRAY_BUFFER, colorData, GL32.GL_DYNAMIC_DRAW); - } - - - - //================// - // base overrides // - //================// - - @Override - public String toString() { return "ID:["+this.id+"], pos:["+this.originBlockPos.x+","+this.originBlockPos.y+","+this.originBlockPos.z+"], size:["+this.size()+"], active:["+this.active+"]"; } - - @Override - public void close() - { - GLProxy.getInstance().queueRunningOnRenderThread(() -> - { - if (this.instanceTranslationVbo != 0) - { - GL32.glDeleteBuffers(this.instanceTranslationVbo); - this.instanceTranslationVbo = 0; - } - - if (this.instanceScaleVbo != 0) - { - GL32.glDeleteBuffers(this.instanceScaleVbo); - this.instanceScaleVbo = 0; - } - - if (this.instanceColorVbo != 0) - { - GL32.glDeleteBuffers(this.instanceColorVbo); - this.instanceColorVbo = 0; - } - }); - } - - } - } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/GenericRenderObjectFactory.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/GenericRenderObjectFactory.java new file mode 100644 index 000000000..bae8c24af --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/GenericRenderObjectFactory.java @@ -0,0 +1,76 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020-2023 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.seibel.distanthorizons.core.render.renderer; + +import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderObjectFactory; +import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister; +import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup; +import com.seibel.distanthorizons.api.objects.math.DhApiVec3f; +import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.util.math.Vec3f; +import org.apache.logging.log4j.Logger; + +import java.util.List; +import java.util.*; + +/** + * Handles creating {@link DhApiRenderableBox}. + * + * @see IDhApiCustomRenderRegister + * @see DhApiRenderableBox + */ +public class GenericRenderObjectFactory implements IDhApiCustomRenderObjectFactory +{ + private static final Logger LOGGER = DhLoggerBuilder.getLogger(); + + public static final GenericRenderObjectFactory INSTANCE = new GenericRenderObjectFactory(); + + + + //=============// + // constructor // + //=============// + + private GenericRenderObjectFactory() { } + + + + //================// + // group creation // + //================// + + @Override + public IDhApiRenderableBoxGroup createForSingleBox(DhApiRenderableBox box) + { + ArrayList list = new ArrayList<>(); + list.add(box); + return this.createAbsolutePositionedGroup(list); + } + + @Override + public IDhApiRenderableBoxGroup createRelativePositionedGroup(DhApiVec3f originBlockPos, List boxList) + { return new RenderableBoxGroup(new Vec3f(originBlockPos), boxList, true); } + + @Override + public IDhApiRenderableBoxGroup createAbsolutePositionedGroup(List boxList) + { return new RenderableBoxGroup(new Vec3f(0, 0, 0), boxList, false); } + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/RenderableBoxGroup.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/RenderableBoxGroup.java new file mode 100644 index 000000000..0e87d046e --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/RenderableBoxGroup.java @@ -0,0 +1,268 @@ +package com.seibel.distanthorizons.core.render.renderer; + +import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup; +import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam; +import com.seibel.distanthorizons.api.objects.math.DhApiVec3f; +import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox; +import com.seibel.distanthorizons.core.render.glObject.GLProxy; +import com.seibel.distanthorizons.core.util.LodUtil; +import com.seibel.distanthorizons.core.util.math.Vec3f; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.opengl.GL32; + +import java.awt.*; +import java.io.Closeable; +import java.util.*; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; +import java.util.stream.Stream; + +public class RenderableBoxGroup + extends AbstractList + implements IDhApiRenderableBoxGroup, Closeable + { + public final static AtomicInteger NEXT_ID_ATOMIC_INT = new AtomicInteger(0); + + + + public final long id; + + /** If false the boxes will be positioned relative to the level's origin */ + public final boolean positionBoxesRelativeToGroupOrigin; + + private final ArrayList boxList; + + private final Vec3f originBlockPos; + + public int skyLight = 15; + public int blockLight = 0; + + @Nullable + public Consumer beforeRenderFunc; + + private boolean vertexDataDirty = true; + public boolean active = true; + + // instance data + public int instanceTranslationVbo = 0; + public int instanceScaleVbo = 0; + public int instanceColorVbo = 0; + + + + // setters/getters // + + @Override + public long getId() { return this.id; } + + @Override + public void setOriginBlockPos(DhApiVec3f pos) + { + this.originBlockPos.x = pos.x; + this.originBlockPos.y = pos.y; + this.originBlockPos.z = pos.z; + } + + @Override + public DhApiVec3f getOriginBlockPos() { return new DhApiVec3f(this.originBlockPos.x, this.originBlockPos.y, this.originBlockPos.z); } + + + @Override + public void setSkyLight(int skyLight) + { + if (skyLight < LodUtil.MIN_MC_LIGHT || skyLight > LodUtil.MAX_MC_LIGHT) + { + throw new IllegalArgumentException("Sky light ["+skyLight+"] must be between ["+LodUtil.MIN_MC_LIGHT+"] and ["+LodUtil.MAX_MC_LIGHT+"] (inclusive)."); + } + this.skyLight = skyLight; + } + @Override + public int getSkyLight() { return this.skyLight; } + + @Override + public void setBlockLight(int blockLight) + { + if (blockLight < LodUtil.MIN_MC_LIGHT || blockLight > LodUtil.MAX_MC_LIGHT) + { + throw new IllegalArgumentException("Block light ["+blockLight+"] must be between ["+LodUtil.MIN_MC_LIGHT+"] and ["+LodUtil.MAX_MC_LIGHT+"] (inclusive)."); + } + this.blockLight = blockLight; + } + @Override + public int getBlockLight() { return this.blockLight; } + + + + //=============// + // constructor // + //=============// + + public RenderableBoxGroup(Vec3f originBlockPos, List boxList, boolean positionBoxesRelativeToGroupOrigin) + { + this.id = NEXT_ID_ATOMIC_INT.getAndIncrement(); + this.boxList = new ArrayList<>(boxList); + + this.originBlockPos = originBlockPos; + this.positionBoxesRelativeToGroupOrigin = positionBoxesRelativeToGroupOrigin; + } + + + + // methods // + + @Override + public boolean add(DhApiRenderableBox box) { return this.boxList.add(box); } + + @Override + public void setPreRenderFunc(Consumer func) { this.beforeRenderFunc = func; } + + @Override + public void triggerBoxChange() { this.vertexDataDirty = true; } + + @Override + public void setActive(boolean active) { this.active = active; } + @Override + public boolean isActive() { return this.active; } + + public void preRender(DhApiRenderParam renderEventParam) + { + if (this.beforeRenderFunc != null) + { + beforeRenderFunc.accept(renderEventParam); + } + } + + + + // overrides // + + @Override + public DhApiRenderableBox get(int index) { return this.boxList.get(index); } + @Override + public int size() { return this.boxList.size(); } + @Override + public boolean removeIf(Predicate filter) { return this.boxList.removeIf(filter); } + @Override + public void replaceAll(UnaryOperator operator) { this.boxList.replaceAll(operator); } + @Override + public void sort(Comparator c) { this.boxList.sort(c); } + @Override + public void forEach(Consumer action) { this.boxList.forEach(action); } + @Override + public Spliterator spliterator() { return this.boxList.spliterator(); } + @Override + public Stream stream() { return this.boxList.stream(); } + @Override + public Stream parallelStream() { return this.boxList.parallelStream(); } + + + + //===================// + // vertex attributes // + //===================// + + /** Does nothing if the vertex data is already up-to-date */ + public void updateVertexAttributeData() + { + if (!this.vertexDataDirty) + { + return; + } + this.vertexDataDirty = false; + + if (this.instanceTranslationVbo == 0) + { + this.instanceTranslationVbo = GL32.glGenBuffers(); + this.instanceScaleVbo = GL32.glGenBuffers(); + this.instanceColorVbo = GL32.glGenBuffers(); + } + + int boxCount = this.size(); + + + // transformation / scaling // + + float[] translationData = new float[boxCount * 3]; + float[] scalingData = new float[boxCount * 3]; + for (int i = 0; i < boxCount; i++) + { + DhApiRenderableBox box = this.get(i); + + int dataIndex = i * 3; + + translationData[dataIndex] = box.minPos.x; + translationData[dataIndex + 1] = box.minPos.y; + translationData[dataIndex + 2] = box.minPos.z; + + scalingData[dataIndex] = box.maxPos.x - box.minPos.x; + scalingData[dataIndex + 1] = box.maxPos.y - box.minPos.y; + scalingData[dataIndex + 2] = box.maxPos.z - box.minPos.z; + + } + + + // colors // + + float[] colorData = new float[boxCount * 4]; + for (int i = 0; i < boxCount; i++) + { + DhApiRenderableBox box = this.get(i); + Color color = box.color; + int colorIndex = i * 4; + colorData[colorIndex] = color.getRed() / 255.0f; + colorData[colorIndex + 1] = color.getGreen() / 255.0f; + colorData[colorIndex + 2] = color.getBlue() / 255.0f; + colorData[colorIndex + 3] = color.getAlpha() / 255.0f; + } + + + // Upload transformation matrices + GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.instanceTranslationVbo); + GL32.glBufferData(GL32.GL_ARRAY_BUFFER, translationData ,GL32.GL_DYNAMIC_DRAW); + GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.instanceScaleVbo); + GL32.glBufferData(GL32.GL_ARRAY_BUFFER, scalingData, GL32.GL_DYNAMIC_DRAW); + + // Upload colors + GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.instanceColorVbo); + GL32.glBufferData(GL32.GL_ARRAY_BUFFER, colorData, GL32.GL_DYNAMIC_DRAW); + } + + + + //================// + // base overrides // + //================// + + @Override + public String toString() { return "ID:["+this.id+"], pos:["+this.originBlockPos.x+","+this.originBlockPos.y+","+this.originBlockPos.z+"], size:["+this.size()+"], active:["+this.active+"]"; } + + @Override + public void close() + { + GLProxy.getInstance().queueRunningOnRenderThread(() -> + { + if (this.instanceTranslationVbo != 0) + { + GL32.glDeleteBuffers(this.instanceTranslationVbo); + this.instanceTranslationVbo = 0; + } + + if (this.instanceScaleVbo != 0) + { + GL32.glDeleteBuffers(this.instanceScaleVbo); + this.instanceScaleVbo = 0; + } + + if (this.instanceColorVbo != 0) + { + GL32.glDeleteBuffers(this.instanceColorVbo); + this.instanceColorVbo = 0; + } + }); + } + + } + \ No newline at end of file diff --git a/core/src/main/java/com/seibel/distanthorizons/core/world/DhApiWorldProxy.java b/core/src/main/java/com/seibel/distanthorizons/core/world/DhApiWorldProxy.java index d7855be30..bc23212f7 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/world/DhApiWorldProxy.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/world/DhApiWorldProxy.java @@ -50,10 +50,18 @@ public class DhApiWorldProxy implements IDhApiWorldProxy + //=============// + // constructor // + //=============// + private DhApiWorldProxy() { } + //=========// + // methods // + //=========// + @Override public boolean worldLoaded() { return SharedApi.getAbstractDhWorld() != null; } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IClientLevelWrapper.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IClientLevelWrapper.java index 9aef5d00c..17a49bc82 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IClientLevelWrapper.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IClientLevelWrapper.java @@ -19,6 +19,7 @@ package com.seibel.distanthorizons.core.wrapperInterfaces.world; +import com.seibel.distanthorizons.core.level.DhClientLevel; import com.seibel.distanthorizons.core.pos.DhBlockPos; import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; import org.jetbrains.annotations.Nullable; @@ -41,4 +42,6 @@ public interface IClientLevelWrapper extends ILevelWrapper @Nullable IBiomeWrapper getPlainsBiomeWrapper(); + void setParentClientLevel(DhClientLevel parentClientLevel); + } diff --git a/core/src/test/java/testItems/worldGeneratorInjection/objects/LevelWrapperTest.java b/core/src/test/java/testItems/worldGeneratorInjection/objects/LevelWrapperTest.java index 187a86c41..b297fa03a 100644 --- a/core/src/test/java/testItems/worldGeneratorInjection/objects/LevelWrapperTest.java +++ b/core/src/test/java/testItems/worldGeneratorInjection/objects/LevelWrapperTest.java @@ -20,6 +20,7 @@ package testItems.worldGeneratorInjection.objects; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType; +import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister; import com.seibel.distanthorizons.api.interfaces.world.IDhApiDimensionTypeWrapper; import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper; @@ -52,4 +53,9 @@ public class LevelWrapperTest implements IDhApiLevelWrapper @Override public int getMinHeight() { return IDhApiLevelWrapper.super.getMinHeight(); } + @Override + public IDhApiCustomRenderRegister getRenderRegister() { return null; } + + + }