re-add generic rendering to the API

This commit is contained in:
James Seibel
2024-07-03 22:37:52 -05:00
parent 81bfa9a02b
commit 88db5c9594
14 changed files with 454 additions and 318 deletions
@@ -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. <br>
* These objects can be added to the renderer in {@link IDhApiLevelWrapper}
* @since API 3.0.0
*/
public static IDhApiCustomRenderObjectFactory customRenderObjectFactory = null;
}
@@ -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<DhApiRenderableBox> cubeList);
IDhApiRenderableBoxGroup createAbsolutePositionedGroup(List<DhApiRenderableBox> cubeList);
}
@@ -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. <br><br>
*
* 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<DhApiRenderableBox> cubeList);
IDhApiRenderableBoxGroup createAbsolutePositionedGroup(List<DhApiRenderableBox> cubeList);
}
@@ -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.<br>
@@ -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();
}
@@ -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)
{
@@ -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<BeaconBeamDTO> 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)
{
@@ -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
@@ -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
@@ -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<DhApiRenderableBox> list = new ArrayList<>();
list.add(box);
return this.createAbsolutePositionedGroup(list);
}
@Override
public IDhApiRenderableBoxGroup createRelativePositionedGroup(DhApiVec3f originBlockPos, List<DhApiRenderableBox> boxList)
{ return new RenderableBoxGroup(new Vec3f(originBlockPos), boxList, true); }
@Override
public IDhApiRenderableBoxGroup createAbsolutePositionedGroup(List<DhApiRenderableBox> 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<DhApiRenderableBox>
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<DhApiRenderableBox> boxList;
private final Vec3f originBlockPos;
public int skyLight = 15;
public int blockLight = 0;
@Nullable
public Consumer<DhApiRenderParam> 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<DhApiRenderableBox> 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<DhApiRenderParam> 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<? super DhApiRenderableBox> filter) { return this.boxList.removeIf(filter); }
@Override
public void replaceAll(UnaryOperator<DhApiRenderableBox> operator) { this.boxList.replaceAll(operator); }
@Override
public void sort(Comparator<? super DhApiRenderableBox> c) { this.boxList.sort(c); }
@Override
public void forEach(Consumer<? super DhApiRenderableBox> action) { this.boxList.forEach(action); }
@Override
public Spliterator<DhApiRenderableBox> spliterator() { return this.boxList.spliterator(); }
@Override
public Stream<DhApiRenderableBox> stream() { return this.boxList.stream(); }
@Override
public Stream<DhApiRenderableBox> 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;
}
});
}
}
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
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<DhApiRenderableBox> list = new ArrayList<>();
list.add(box);
return this.createAbsolutePositionedGroup(list);
}
@Override
public IDhApiRenderableBoxGroup createRelativePositionedGroup(DhApiVec3f originBlockPos, List<DhApiRenderableBox> boxList)
{ return new RenderableBoxGroup(new Vec3f(originBlockPos), boxList, true); }
@Override
public IDhApiRenderableBoxGroup createAbsolutePositionedGroup(List<DhApiRenderableBox> boxList)
{ return new RenderableBoxGroup(new Vec3f(0, 0, 0), boxList, false); }
}
@@ -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<DhApiRenderableBox>
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<DhApiRenderableBox> boxList;
private final Vec3f originBlockPos;
public int skyLight = 15;
public int blockLight = 0;
@Nullable
public Consumer<DhApiRenderParam> 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<DhApiRenderableBox> 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<DhApiRenderParam> 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<? super DhApiRenderableBox> filter) { return this.boxList.removeIf(filter); }
@Override
public void replaceAll(UnaryOperator<DhApiRenderableBox> operator) { this.boxList.replaceAll(operator); }
@Override
public void sort(Comparator<? super DhApiRenderableBox> c) { this.boxList.sort(c); }
@Override
public void forEach(Consumer<? super DhApiRenderableBox> action) { this.boxList.forEach(action); }
@Override
public Spliterator<DhApiRenderableBox> spliterator() { return this.boxList.spliterator(); }
@Override
public Stream<DhApiRenderableBox> stream() { return this.boxList.stream(); }
@Override
public Stream<DhApiRenderableBox> 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;
}
});
}
}
@@ -50,10 +50,18 @@ public class DhApiWorldProxy implements IDhApiWorldProxy
//=============//
// constructor //
//=============//
private DhApiWorldProxy() { }
//=========//
// methods //
//=========//
@Override
public boolean worldLoaded() { return SharedApi.getAbstractDhWorld() != null; }
@@ -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);
}
@@ -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; }
}