Separate out Generic object rendering

This commit is contained in:
James Seibel
2024-06-28 16:53:05 -06:00
parent 6bfa3a422e
commit 0d0826f319
11 changed files with 648 additions and 544 deletions
@@ -23,6 +23,7 @@ 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.IDhApiRenderProxy;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent;
import com.seibel.distanthorizons.api.methods.override.DhApiWorldGeneratorOverrideRegister;
@@ -127,6 +128,7 @@ public class DhApi
*/
public static IDhApiWrapperFactory wrapperFactory = null;
public static IDhApiCustomRenderRegister renderRegister = null;
}
@@ -0,0 +1,18 @@
package com.seibel.distanthorizons.api.interfaces.render;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import java.util.List;
public interface IDhApiCustomRenderRegister
{
void add(IDhApiRenderableBoxGroup cubeGroup) throws IllegalArgumentException;
IDhApiRenderableBoxGroup remove(long id);
IDhApiRenderableBoxGroup createForSingleBox(DhApiRenderableBox cube);
IDhApiRenderableBoxGroup createRelativePositionedGroup(float originBlockX, float originBlockY, float originBlockZ, List<DhApiRenderableBox> cubeList);
IDhApiRenderableBoxGroup createAbsolutePositionedGroup(List<DhApiRenderableBox> cubeList);
}
@@ -0,0 +1,21 @@
package com.seibel.distanthorizons.api.interfaces.render;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import java.util.List;
import java.util.function.Consumer;
public interface IDhApiRenderableBoxGroup extends List<DhApiRenderableBox>
{
long getId();
void setOriginBlockPos(float x, float y, float z);
float getOriginBlockX();
float getOriginBlockY();
float getOriginBlockZ();
void setPreRenderFunc(Consumer<DhApiRenderParam> renderEventParam);
}
@@ -0,0 +1,26 @@
package com.seibel.distanthorizons.api.objects.render;
import com.seibel.distanthorizons.coreapi.util.math.Vec3f;
import java.awt.*;
public final class DhApiRenderableBox
{
public Vec3f minPos;
public Vec3f maxPos;
public Color color;
public boolean fullBright = false;
public DhApiRenderableBox(Vec3f minPos, Vec3f maxPos, Color color)
{
this.minPos = minPos;
this.maxPos = maxPos;
this.color = color;
}
}
@@ -20,6 +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.sql.DatabaseUpdater;
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.distanthorizons.coreapi.ModInfo;
@@ -93,6 +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.wrapperFactory = SingletonInjector.INSTANCE.get(IWrapperFactory.class);
if (DhApi.Delayed.wrapperFactory == null)
{
@@ -80,7 +80,7 @@ public class DebugRenderer
/** A box from 0,0,0 to 1,1,1 */
private static final float[] BOX_VERTICIES = {
private static final float[] BOX_VERTICES = {
// Pos x y z
0, 0, 0,
1, 0, 0,
@@ -115,7 +115,47 @@ public class DebugRenderer
// constructor //
//=============//
public DebugRenderer() { }
private DebugRenderer() { }
public void init()
{
if (this.init)
{
return;
}
this.init = true;
this.va = AbstractVertexAttribute.create();
this.va.bind();
// Pos
this.va.setVertexAttribute(0, 0, VertexPointer.addVec3Pointer(false));
this.va.completeAndCheck(Float.BYTES * 3);
this.basicShader = new ShaderProgram("shaders/debug/vert.vert", "shaders/debug/frag.frag",
"fragColor", new String[]{"vPosition"});
this.createBuffer();
}
private void createBuffer()
{
// box vertices
ByteBuffer boxVerticesBuffer = ByteBuffer.allocateDirect(BOX_VERTICES.length * Float.BYTES);
boxVerticesBuffer.order(ByteOrder.nativeOrder());
boxVerticesBuffer.asFloatBuffer().put(BOX_VERTICES);
boxVerticesBuffer.rewind();
this.vertexBuffer = new GLVertexBuffer(false);
this.vertexBuffer.bind();
this.vertexBuffer.uploadBuffer(boxVerticesBuffer, 8, EDhApiGpuUploadMethod.DATA, BOX_VERTICES.length * Float.BYTES);
// outline vertex indexes
ByteBuffer boxOutlineBuffer = ByteBuffer.allocateDirect(BOX_OUTLINE_INDICES.length * Integer.BYTES);
boxOutlineBuffer.order(ByteOrder.nativeOrder());
boxOutlineBuffer.asIntBuffer().put(BOX_OUTLINE_INDICES);
boxOutlineBuffer.rewind();
this.outlineIndexBuffer = new GLElementBuffer(false);
this.outlineIndexBuffer.uploadBuffer(boxOutlineBuffer, EDhApiGpuUploadMethod.DATA, BOX_OUTLINE_INDICES.length * Integer.BYTES, GL32.GL_STATIC_DRAW);
}
@@ -141,52 +181,10 @@ public class DebugRenderer
//===========//
// rendering //
//===========//
public void init()
{
if (this.init)
{
return;
}
this.init = true;
this.va = AbstractVertexAttribute.create();
this.va.bind();
// Pos
this.va.setVertexAttribute(0, 0, VertexPointer.addVec3Pointer(false));
this.va.completeAndCheck(Float.BYTES * 3);
this.basicShader = new ShaderProgram("shaders/debug/vert.vert", "shaders/debug/frag.frag",
"fragColor", new String[]{"vPosition"});
this.createBuffer();
}
private void createBuffer()
{
// box vertices
ByteBuffer boxVerticesBuffer = ByteBuffer.allocateDirect(BOX_VERTICIES.length * Float.BYTES);
boxVerticesBuffer.order(ByteOrder.nativeOrder());
boxVerticesBuffer.asFloatBuffer().put(BOX_VERTICIES);
boxVerticesBuffer.rewind();
this.vertexBuffer = new GLVertexBuffer(false);
this.vertexBuffer.bind();
this.vertexBuffer.uploadBuffer(boxVerticesBuffer, 8, EDhApiGpuUploadMethod.DATA, BOX_VERTICIES.length * Float.BYTES);
// outline vertex indexes
ByteBuffer boxOutlineBuffer = ByteBuffer.allocateDirect(BOX_OUTLINE_INDICES.length * Integer.BYTES);
boxOutlineBuffer.order(ByteOrder.nativeOrder());
boxOutlineBuffer.asIntBuffer().put(BOX_OUTLINE_INDICES);
boxOutlineBuffer.rewind();
this.outlineIndexBuffer = new GLElementBuffer(false);
this.outlineIndexBuffer.uploadBuffer(boxOutlineBuffer, EDhApiGpuUploadMethod.DATA, BOX_OUTLINE_INDICES.length * Integer.BYTES, GL32.GL_STATIC_DRAW);
}
public void render(Mat4f transform)
{
this.transformationMatrixThisFrame = transform;
@@ -229,8 +227,8 @@ public class DebugRenderer
public void renderBox(Box box)
{
Mat4f boxTransform = Mat4f.createTranslateMatrix(box.a.x - this.camPosFloatThisFrame.x, box.a.y - this.camPosFloatThisFrame.y, box.a.z - this.camPosFloatThisFrame.z);
boxTransform.multiply(Mat4f.createScaleMatrix(box.b.x - box.a.x, box.b.y - box.a.y, box.b.z - box.a.z));
Mat4f boxTransform = Mat4f.createTranslateMatrix(box.minPos.x - this.camPosFloatThisFrame.x, box.minPos.y - this.camPosFloatThisFrame.y, box.minPos.z - this.camPosFloatThisFrame.z);
boxTransform.multiply(Mat4f.createScaleMatrix(box.maxPos.x - box.minPos.x, box.maxPos.y - box.minPos.y, box.maxPos.z - box.minPos.z));
Mat4f t = this.transformationMatrixThisFrame.copy();
t.multiply(boxTransform);
this.basicShader.setUniform(this.basicShader.getUniformLocation("transform"), t);
@@ -246,25 +244,25 @@ public class DebugRenderer
public static final class Box
{
public Vec3f a;
public Vec3f b;
public Vec3f minPos;
public Vec3f maxPos;
public Color color;
public Box(Vec3f a, Vec3f b, Color color)
public Box(Vec3f minPos, Vec3f maxPos, Color color)
{
this.a = a;
this.b = b;
this.minPos = minPos;
this.maxPos = maxPos;
this.color = color;
}
public Box(Vec3f a, Vec3f b, Color color, Vec3f margin)
public Box(Vec3f minPos, Vec3f maxPos, Color color, Vec3f margin)
{
this.a = a;
this.a.add(margin);
this.b = b;
this.b.subtract(margin);
this.minPos = minPos;
this.minPos.add(margin);
this.maxPos = maxPos;
this.maxPos.subtract(margin);
this.color = color;
}
@@ -275,8 +273,8 @@ public class DebugRenderer
float edge = pos.getBlockWidth() * marginPercent;
Vec3f a = new Vec3f(blockMin.x + edge, minY, blockMin.z + edge);
Vec3f b = new Vec3f(blockMax.x - edge, maxY, blockMax.z - edge);
this.a = a;
this.b = b;
this.minPos = a;
this.maxPos = b;
this.color = color;
}
@@ -288,8 +286,8 @@ public class DebugRenderer
float edge = pos.getBlockWidth() * marginPercent;
Vec3f a = new Vec3f(blockMin.x + edge, hashY, blockMin.z + edge);
Vec3f b = new Vec3f(blockMax.x - edge, hashY, blockMax.z - edge);
this.a = a;
this.b = b;
this.minPos = a;
this.maxPos = b;
this.color = color;
}
@@ -337,7 +335,7 @@ public class DebugRenderer
float percent = (now - this.startTime) / (float) this.duration;
percent = (float) Math.pow(percent, 4);
float yDiff = this.yChange * percent;
return new Box(new Vec3f(this.box.a.x, this.box.a.y + yDiff, this.box.a.z), new Vec3f(this.box.b.x, this.box.b.y + yDiff, this.box.b.z), this.box.color);
return new Box(new Vec3f(this.box.minPos.x, this.box.minPos.y + yDiff, this.box.minPos.z), new Vec3f(this.box.maxPos.x, this.box.maxPos.y + yDiff, this.box.maxPos.z), this.box.color);
}
public boolean isDead(long time) { return (time - this.startTime) > this.duration; }
@@ -353,7 +351,7 @@ public class DebugRenderer
public BoxWithLife(Box box, long ns, float yChange, Color deathColor)
{
this.box = box;
this.particaleOnClose = new BoxParticle(new Box(box.a, box.b, deathColor), -1, ns, yChange);
this.particaleOnClose = new BoxParticle(new Box(box.minPos, box.maxPos, deathColor), -1, ns, yChange);
register(this, null);
}
@@ -363,7 +361,7 @@ public class DebugRenderer
public BoxWithLife(Box box, double s, float yChange, Color deathColor)
{
this.box = box;
this.particaleOnClose = new BoxParticle(new Box(box.a, box.b, deathColor), s, yChange);
this.particaleOnClose = new BoxParticle(new Box(box.minPos, box.maxPos, deathColor), s, yChange);
}
public BoxWithLife(Box box, double s, float yChange) { this(box, s, yChange, box.color); }
@@ -1,470 +0,0 @@
/*
* 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.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.api.enums.config.EDhApiLoggerMode;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
import com.seibel.distanthorizons.core.logging.ConfigBasedSpamLogger;
import com.seibel.distanthorizons.core.pos.DhBlockPos2D;
import com.seibel.distanthorizons.core.pos.DhLodPos;
import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.core.render.glObject.GLState;
import com.seibel.distanthorizons.core.render.glObject.buffer.GLElementBuffer;
import com.seibel.distanthorizons.core.render.glObject.buffer.GLVertexBuffer;
import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram;
import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.AbstractVertexAttribute;
import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexPointer;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
import com.seibel.distanthorizons.coreapi.util.math.Vec3d;
import com.seibel.distanthorizons.coreapi.util.math.Vec3f;
import org.apache.logging.log4j.LogManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.opengl.GL32;
import java.awt.*;
import java.io.Closeable;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.concurrent.PriorityBlockingQueue;
public class GenericCubeRenderer
{
public static GenericCubeRenderer INSTANCE = new GenericCubeRenderer();
public static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(GenericCubeRenderer.class), () -> EDhApiLoggerMode.LOG_ALL_TO_CHAT);
public static final ConfigBasedSpamLogger SPAM_LOGGER = new ConfigBasedSpamLogger(LogManager.getLogger(TestRenderer.class), () -> EDhApiLoggerMode.LOG_ALL_TO_CHAT, 1);
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
// rendering setup
private ShaderProgram basicUnlitShader;
private GLVertexBuffer vertexBuffer;
private GLElementBuffer solidIndexBuffer;
private AbstractVertexAttribute va;
private boolean init = false;
// used when rendering
private Mat4f transformationMatrixThisFrame;
private Vec3f camPosFloatThisFrame;
//private final RendererLists rendererLists = new RendererLists();
//private final PriorityBlockingQueue<BoxParticle> particles = new PriorityBlockingQueue<>();
/** A box from 0,0,0 to 1,1,1 */
private static final float[] BOX_VERTICIES = {
// Pos x y z
0, 0, 0,
1, 0, 0,
1, 1, 0,
0, 1, 0,
0, 0, 1,
1, 0, 1,
1, 1, 1,
0, 1, 1,
};
private static final int[] SOLID_BOX_INDICES = {
// min Z, vertical face
0, 3, 2,
2, 1, 0,
// max Z, vertical face
4, 5, 6,
6, 7, 4,
// min X, vertical face
7, 3, 0,
0, 4, 7,
// max X, vertical face
2, 6, 5,
5, 1, 2,
// min Y, horizontal face
1, 5, 4,
4, 0, 1,
// max Y, horizontal face
3, 7, 6,
6, 2, 3,
};
//=============//
// constructor //
//=============//
public GenericCubeRenderer() { }
//==============//
// registration //
//==============//
//public static void makeParticle(BoxParticle particle)
//{
// if (INSTANCE != null && Config.Client.Advanced.Debugging.DebugWireframe.enableRendering.get())
// {
// INSTANCE.particles.add(particle);
// }
//}
//
//public static void register(IDebugRenderable renderable, ConfigEntry<Boolean> config) { if (INSTANCE != null) { INSTANCE.addRenderer(renderable, config); } }
//public void addRenderer(IDebugRenderable renderable, ConfigEntry<Boolean> config) { this.rendererLists.addRenderable(renderable, config); }
//
//public static void unregister(IDebugRenderable renderable, ConfigEntry<Boolean> config) { if (INSTANCE != null) { INSTANCE.removeRenderer(renderable, config); } }
//private void removeRenderer(IDebugRenderable renderable, ConfigEntry<Boolean> config) { this.rendererLists.removeRenderable(renderable, config); }
//
//public static void clearRenderables() { INSTANCE.rendererLists.clearRenderables(); }
//===========//
// rendering //
//===========//
public void init()
{
if (this.init)
{
return;
}
this.init = true;
this.va = AbstractVertexAttribute.create();
this.va.bind();
// Pos
this.va.setVertexAttribute(0, 0, VertexPointer.addVec3Pointer(false));
this.va.completeAndCheck(Float.BYTES * 3);
this.basicUnlitShader = new ShaderProgram("shaders/debug/vert.vert", "shaders/debug/frag.frag",
"fragColor", new String[]{"vPosition"});
this.createBuffers();
}
private void createBuffers()
{
// cube vertices
ByteBuffer boxVerticesBuffer = ByteBuffer.allocateDirect(BOX_VERTICIES.length * Float.BYTES);
boxVerticesBuffer.order(ByteOrder.nativeOrder());
boxVerticesBuffer.asFloatBuffer().put(BOX_VERTICIES);
boxVerticesBuffer.rewind();
this.vertexBuffer = new GLVertexBuffer(false);
this.vertexBuffer.bind();
this.vertexBuffer.uploadBuffer(boxVerticesBuffer, 8, EDhApiGpuUploadMethod.DATA, BOX_VERTICIES.length * Float.BYTES);
// cube vertex indexes
ByteBuffer solidIndexBuffer = ByteBuffer.allocateDirect(SOLID_BOX_INDICES.length * Integer.BYTES);
solidIndexBuffer.order(ByteOrder.nativeOrder());
solidIndexBuffer.asIntBuffer().put(SOLID_BOX_INDICES);
solidIndexBuffer.rewind();
this.solidIndexBuffer = new GLElementBuffer(false);
this.solidIndexBuffer.uploadBuffer(solidIndexBuffer, EDhApiGpuUploadMethod.DATA, SOLID_BOX_INDICES.length * Integer.BYTES, GL32.GL_STATIC_DRAW);
this.solidIndexBuffer.bind();
}
public void render(Mat4f transform)
{
this.transformationMatrixThisFrame = transform;
Vec3d camPos = MC_RENDER.getCameraExactPosition();
this.camPosFloatThisFrame = new Vec3f((float) camPos.x, (float) camPos.y, (float) camPos.z);
GLState glState = new GLState();
this.init();
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
GL32.glEnable(GL32.GL_DEPTH_TEST);
this.basicUnlitShader.bind();
this.va.bind();
this.va.bindBufferToAllBindingPoints(this.vertexBuffer.getId());
this.solidIndexBuffer.bind();
//this.rendererLists.render(this);
renderUnlitCube(new Box(new Vec3f(0f,0f,0f), new Vec3f(16f,190f,16f), Color.CYAN));
this.basicUnlitShader.unbind();
glState.restore();
}
private void renderUnlitCube(Box box)
{
Mat4f boxTransform = Mat4f.createTranslateMatrix(box.a.x - this.camPosFloatThisFrame.x, box.a.y - this.camPosFloatThisFrame.y, box.a.z - this.camPosFloatThisFrame.z);
boxTransform.multiply(Mat4f.createScaleMatrix(box.b.x - box.a.x, box.b.y - box.a.y, box.b.z - box.a.z));
Mat4f transformMatrix = this.transformationMatrixThisFrame.copy();
transformMatrix.multiply(boxTransform);
this.basicUnlitShader.setUniform(this.basicUnlitShader.getUniformLocation("transform"), transformMatrix);
this.basicUnlitShader.setUniform(this.basicUnlitShader.getUniformLocation("uColor"), box.color);
GL32.glDrawElements(GL32.GL_TRIANGLES , SOLID_BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0);
}
//================//
// helper classes //
//================//
public static final class Box
{
public Vec3f a;
public Vec3f b;
public Color color;
public Box(Vec3f a, Vec3f b, Color color)
{
this.a = a;
this.b = b;
this.color = color;
}
public Box(Vec3f a, Vec3f b, Color color, Vec3f margin)
{
this.a = a;
this.a.add(margin);
this.b = b;
this.b.subtract(margin);
this.color = color;
}
public Box(DhLodPos pos, float minY, float maxY, float marginPercent, Color color)
{
DhBlockPos2D blockMin = pos.getCornerBlockPos();
DhBlockPos2D blockMax = blockMin.add(pos.getBlockWidth(), pos.getBlockWidth());
float edge = pos.getBlockWidth() * marginPercent;
Vec3f a = new Vec3f(blockMin.x + edge, minY, blockMin.z + edge);
Vec3f b = new Vec3f(blockMax.x - edge, maxY, blockMax.z - edge);
this.a = a;
this.b = b;
this.color = color;
}
public Box(DhLodPos pos, float y, float yDiff, Object hash, float marginPercent, Color color)
{
float hashY = ((float) hash.hashCode() / Integer.MAX_VALUE) * yDiff;
DhBlockPos2D blockMin = pos.getCornerBlockPos();
DhBlockPos2D blockMax = blockMin.add(pos.getBlockWidth(), pos.getBlockWidth());
float edge = pos.getBlockWidth() * marginPercent;
Vec3f a = new Vec3f(blockMin.x + edge, hashY, blockMin.z + edge);
Vec3f b = new Vec3f(blockMax.x - edge, hashY, blockMax.z - edge);
this.a = a;
this.b = b;
this.color = color;
}
public Box(long pos, float minY, float maxY, float marginPercent, Color color)
{
this(DhSectionPos.getSectionBBoxPos(pos), minY, maxY, marginPercent, color);
}
public Box(long pos, float y, float yDiff, Object hash, float marginPercent, Color color)
{
this(DhSectionPos.getSectionBBoxPos(pos), y, yDiff, hash, marginPercent, color);
}
}
//public static final class BoxParticle implements Comparable<BoxParticle>
//{
// public Box box;
// public long startTime;
// public long duration;
// public float yChange;
//
// public BoxParticle(Box box, long startTime, long duration, float yChange)
// {
// this.box = box;
// this.startTime = startTime;
// this.duration = duration;
// this.yChange = yChange;
// }
//
// public BoxParticle(Box box, long nanoSecondDuratoin, float yChange) { this(box, System.nanoTime(), nanoSecondDuratoin, yChange); }
//
// public BoxParticle(Box box, double secondDuration, float yChange) { this(box, System.nanoTime(), (long) (secondDuration * 1000000000), yChange); }
//
//
// @Override
// public int compareTo(@NotNull BoxParticle particle)
// {
// return Long.compare(this.startTime + this.duration, particle.startTime + particle.duration);
// }
//
// public Box getBox()
// {
// long now = System.nanoTime();
// float percent = (now - this.startTime) / (float) this.duration;
// percent = (float) Math.pow(percent, 4);
// float yDiff = this.yChange * percent;
// return new Box(new Vec3f(this.box.a.x, this.box.a.y + yDiff, this.box.a.z), new Vec3f(this.box.b.x, this.box.b.y + yDiff, this.box.b.z), this.box.color);
// }
//
// public boolean isDead(long time) { return (time - this.startTime) > this.duration; }
//
//}
//private static class RendererLists
//{
// public final LinkedList<WeakReference<IDebugRenderable>> generalRenderableList = new LinkedList<>();
//
// private final HashMap<ConfigEntry<Boolean>, LinkedList<WeakReference<IDebugRenderable>>> renderableListByConfig = new HashMap<>();
//
//
//
// // registration //
//
// public void addRenderable(IDebugRenderable renderable, @Nullable ConfigEntry<Boolean> config)
// {
// synchronized (this)
// {
// if (config != null)
// {
// if (!this.renderableListByConfig.containsKey(config))
// {
// this.renderableListByConfig.put(config, new LinkedList<>());
// }
//
// LinkedList<WeakReference<IDebugRenderable>> renderableList = this.renderableListByConfig.get(config);
// renderableList.add(new WeakReference<>(renderable));
// }
// else
// {
// this.generalRenderableList.add(new WeakReference<>(renderable));
// }
// }
// }
//
// public void removeRenderable(IDebugRenderable renderable, @Nullable ConfigEntry<Boolean> config)
// {
// synchronized (this)
// {
// if (config != null)
// {
// if (this.renderableListByConfig.containsKey(config))
// {
// LinkedList<WeakReference<IDebugRenderable>> renderableList = this.renderableListByConfig.get(config);
// this.removeRenderableFromInternalList(renderableList, renderable);
// }
// }
// else
// {
// this.removeRenderableFromInternalList(this.generalRenderableList, renderable);
// }
// }
// }
// private void removeRenderableFromInternalList(LinkedList<WeakReference<IDebugRenderable>> rendererList, IDebugRenderable renderable)
// {
// Iterator<WeakReference<IDebugRenderable>> iterator = rendererList.iterator();
// while (iterator.hasNext())
// {
// WeakReference<IDebugRenderable> renderableRef = iterator.next();
// if (renderableRef.get() == null)
// {
// iterator.remove();
// continue;
// }
//
// if (renderableRef.get() == renderable)
// {
// iterator.remove();
// return;
// }
// }
// }
//
// public void clearRenderables()
// {
// for (ConfigEntry<Boolean> config : this.renderableListByConfig.keySet())
// {
// LinkedList<WeakReference<IDebugRenderable>> renderableList = this.renderableListByConfig.get(config);
// if (config.get() && renderableList != null)
// {
// renderableList.clear();
// }
// }
// }
//
//
//
// // rendering //
//
// public void render(GenericCubeRenderer debugRenderer)
// {
// this.renderList(debugRenderer, this.generalRenderableList);
//
// for (ConfigEntry<Boolean> config : this.renderableListByConfig.keySet())
// {
// LinkedList<WeakReference<IDebugRenderable>> renderableList = this.renderableListByConfig.get(config);
// if (config.get() && renderableList != null && renderableList.size() != 0)
// {
// this.renderList(debugRenderer, renderableList);
// }
// }
// }
// private void renderList(GenericCubeRenderer debugRenderer, LinkedList<WeakReference<IDebugRenderable>> rendererList)
// {
// synchronized (this)
// {
// try
// {
// Iterator<WeakReference<IDebugRenderable>> iterator = rendererList.iterator();
// while (iterator.hasNext())
// {
// WeakReference<IDebugRenderable> ref = iterator.next();
// IDebugRenderable renderable = ref.get();
// if (renderable == null)
// {
// iterator.remove();
// continue;
// }
//
// renderable.debugRender(debugRenderer);
// }
// }
// catch (Exception e)
// {
// SPAM_LOGGER.error("Unexpected Debug renderer error, Error: "+e.getMessage(), e);
// }
// }
// }
//}
}
@@ -0,0 +1,496 @@
/*
* 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.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;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
import com.seibel.distanthorizons.core.logging.ConfigBasedSpamLogger;
import com.seibel.distanthorizons.core.render.glObject.GLState;
import com.seibel.distanthorizons.core.render.glObject.buffer.GLElementBuffer;
import com.seibel.distanthorizons.core.render.glObject.buffer.GLVertexBuffer;
import com.seibel.distanthorizons.core.render.glObject.shader.ShaderProgram;
import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.AbstractVertexAttribute;
import com.seibel.distanthorizons.core.render.glObject.vertexAttribute.VertexPointer;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
import com.seibel.distanthorizons.coreapi.util.math.Vec3d;
import com.seibel.distanthorizons.coreapi.util.math.Vec3f;
import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongSet;
import org.apache.logging.log4j.LogManager;
import org.lwjgl.opengl.GL32;
import javax.annotation.Nullable;
import java.awt.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Spliterator;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;
public class GenericObjectRenderer implements IDhApiCustomRenderRegister
{
public static GenericObjectRenderer INSTANCE = new GenericObjectRenderer();
public static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(GenericObjectRenderer.class), () -> EDhApiLoggerMode.LOG_ALL_TO_CHAT);
public static final ConfigBasedSpamLogger SPAM_LOGGER = new ConfigBasedSpamLogger(LogManager.getLogger(TestRenderer.class), () -> EDhApiLoggerMode.LOG_ALL_TO_CHAT, 1);
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
// rendering setup
private ShaderProgram basicUnlitShader;
private GLVertexBuffer vertexBuffer;
private GLElementBuffer solidIndexBuffer;
private AbstractVertexAttribute va;
private boolean init = false;
// used when rendering
private Mat4f transformationMatrixThisFrame;
private Vec3f camPosFloatThisFrame;
// TODO may need to be double buffered to prevent rendering lag
private final Long2ReferenceOpenHashMap<DhApiRenderableBoxGroup> boxGroupById = new Long2ReferenceOpenHashMap<>();
private final ReentrantLock mapModifyLock = new ReentrantLock();
/** A box from 0,0,0 to 1,1,1 */
private static final float[] BOX_VERTICES = {
// Pos x y z
0, 0, 0,
1, 0, 0,
1, 1, 0,
0, 1, 0,
0, 0, 1,
1, 0, 1,
1, 1, 1,
0, 1, 1,
};
private static final int[] SOLID_BOX_INDICES = {
// min Z, vertical face
0, 3, 2,
2, 1, 0,
// max Z, vertical face
4, 5, 6,
6, 7, 4,
// min X, vertical face
7, 3, 0,
0, 4, 7,
// max X, vertical face
2, 6, 5,
5, 1, 2,
// min Y, horizontal face
1, 5, 4,
4, 0, 1,
// max Y, horizontal face
3, 7, 6,
6, 2, 3,
};
//=============//
// constructor //
//=============//
private GenericObjectRenderer() { }
public void init()
{
if (this.init)
{
return;
}
this.init = true;
this.va = AbstractVertexAttribute.create();
this.va.bind();
// Pos
this.va.setVertexAttribute(0, 0, VertexPointer.addVec3Pointer(false));
this.va.completeAndCheck(Float.BYTES * 3);
this.basicUnlitShader = new ShaderProgram("shaders/genericObject/vert.vert", "shaders/genericObject/frag.frag",
"fragColor", new String[]{"vPosition"});
this.createBuffers();
// testing //
// single giant cube
IDhApiRenderableBoxGroup singleGiantCubeGroup = DhApi.Delayed.renderRegister.createForSingleBox(
new DhApiRenderableBox(
new Vec3f(0f,0f,0f), new Vec3f(16f,190f,16f),
new Color(Color.CYAN.getRed(), Color.CYAN.getGreen(), Color.CYAN.getBlue(), 125))
);
DhApi.Delayed.renderRegister.add(singleGiantCubeGroup);
// single slender cube
singleGiantCubeGroup = DhApi.Delayed.renderRegister.createForSingleBox(
new DhApiRenderableBox(
new Vec3f(16f,0f,31f), new Vec3f(17f,2000f,32f),
new Color(Color.GREEN.getRed(), Color.GREEN.getGreen(), Color.GREEN.getBlue(), 125))
);
DhApi.Delayed.renderRegister.add(singleGiantCubeGroup);
// absolute cube group
ArrayList<DhApiRenderableBox> absCubeList = new ArrayList<>();
for (int i = 0; i < 18; i++)
{
absCubeList.add(new DhApiRenderableBox(
new Vec3f(0f+i,150f+i,24f), new Vec3f(1f+i,151f+i,25f),
new Color(Color.ORANGE.getRed(), Color.ORANGE.getGreen(), Color.ORANGE.getBlue())));
}
IDhApiRenderableBoxGroup absolutePosCubeGroup = DhApi.Delayed.renderRegister.createAbsolutePositionedGroup(absCubeList);
DhApi.Delayed.renderRegister.add(absolutePosCubeGroup);
// relative cube group
ArrayList<DhApiRenderableBox> relCubeList = new ArrayList<>();
for (int i = 0; i < 8; i+=2)
{
relCubeList.add(new DhApiRenderableBox(
new Vec3f(0f,0f+i,0f), new Vec3f(1f,1f+i,1f),
new Color(Color.MAGENTA.getRed(), Color.MAGENTA.getGreen(), Color.MAGENTA.getBlue())));
}
IDhApiRenderableBoxGroup relativePosCubeGroup = DhApi.Delayed.renderRegister.createRelativePositionedGroup(
24f, 140f, 24f,
relCubeList);
AtomicInteger frameCount = new AtomicInteger(0);
relativePosCubeGroup.setPreRenderFunc((event) ->
{
float x = relativePosCubeGroup.getOriginBlockX();
x += event.partialTicks / 2;
x %= 32;
relativePosCubeGroup.setOriginBlockPos(x, relativePosCubeGroup.getOriginBlockY(), relativePosCubeGroup.getOriginBlockZ());
});
DhApi.Delayed.renderRegister.add(relativePosCubeGroup);
}
private void createBuffers()
{
// cube vertices
ByteBuffer boxVerticesBuffer = ByteBuffer.allocateDirect(BOX_VERTICES.length * Float.BYTES);
boxVerticesBuffer.order(ByteOrder.nativeOrder());
boxVerticesBuffer.asFloatBuffer().put(BOX_VERTICES);
boxVerticesBuffer.rewind();
this.vertexBuffer = new GLVertexBuffer(false);
this.vertexBuffer.bind();
this.vertexBuffer.uploadBuffer(boxVerticesBuffer, 8, EDhApiGpuUploadMethod.DATA, BOX_VERTICES.length * Float.BYTES);
// cube vertex indexes
ByteBuffer solidIndexBuffer = ByteBuffer.allocateDirect(SOLID_BOX_INDICES.length * Integer.BYTES);
solidIndexBuffer.order(ByteOrder.nativeOrder());
solidIndexBuffer.asIntBuffer().put(SOLID_BOX_INDICES);
solidIndexBuffer.rewind();
this.solidIndexBuffer = new GLElementBuffer(false);
this.solidIndexBuffer.uploadBuffer(solidIndexBuffer, EDhApiGpuUploadMethod.DATA, SOLID_BOX_INDICES.length * Integer.BYTES, GL32.GL_STATIC_DRAW);
this.solidIndexBuffer.bind();
}
//================//
// group creation //
//================//
@Override
public IDhApiRenderableBoxGroup createForSingleBox(DhApiRenderableBox box)
{
ArrayList<DhApiRenderableBox> list = new ArrayList<>();
list.add(box);
return new DhApiRenderableBoxGroup(0, 0, 0, list, false);
}
@Override
public IDhApiRenderableBoxGroup createRelativePositionedGroup(float originBlockX, float originBlockY, float originBlockZ, List<DhApiRenderableBox> cubeList)
{ return new DhApiRenderableBoxGroup(originBlockX, originBlockY, originBlockZ, cubeList, true); }
@Override
public IDhApiRenderableBoxGroup createAbsolutePositionedGroup(List<DhApiRenderableBox> boxList)
{ return new DhApiRenderableBoxGroup(0, 0, 0, boxList, false); }
//==============//
// registration //
//==============//
@Override
public void add(IDhApiRenderableBoxGroup boxGroup) throws IllegalArgumentException
{
try
{
mapModifyLock.lock();
long id = boxGroup.getId();
if (this.boxGroupById.containsKey(id))
{
throw new IllegalArgumentException("A cube group with the ID [" + id + "] is already present.");
}
this.boxGroupById.put(id, (DhApiRenderableBoxGroup) boxGroup);
// TODO add to DB async?
}
finally
{
mapModifyLock.unlock();
}
}
@Override
public IDhApiRenderableBoxGroup remove(long id)
{
try
{
mapModifyLock.lock();
// TODO remove from DB async?
return this.boxGroupById.remove(id);
}
finally
{
mapModifyLock.unlock();
}
}
public void clear()
{
try
{
mapModifyLock.lock();
this.boxGroupById.clear();
}
finally
{
mapModifyLock.unlock();
}
}
//===========//
// rendering //
//===========//
public void render(DhApiRenderParam renderEventParam)
{
Mat4f transform = new Mat4f(renderEventParam.dhProjectionMatrix);
transform.multiply(renderEventParam.dhModelViewMatrix);
this.transformationMatrixThisFrame = transform;
Vec3d camPos = MC_RENDER.getCameraExactPosition();
this.camPosFloatThisFrame = new Vec3f((float) camPos.x, (float) camPos.y, (float) camPos.z);
GLState glState = new GLState();
this.init();
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
GL32.glEnable(GL32.GL_DEPTH_TEST);
GL32.glEnable(GL32.GL_BLEND);
GL32.glBlendEquation(GL32.GL_FUNC_ADD);
GL32.glBlendFuncSeparate(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA, GL32.GL_ONE, GL32.GL_ONE_MINUS_SRC_ALPHA);
this.basicUnlitShader.bind();
this.va.bind();
this.va.bindBufferToAllBindingPoints(this.vertexBuffer.getId());
this.solidIndexBuffer.bind();
LongSet keys = boxGroupById.keySet();
for (long key : keys)
{
DhApiRenderableBoxGroup cubeGroup = boxGroupById.get(key);
this.renderCubeGroup(cubeGroup, renderEventParam);
}
this.basicUnlitShader.unbind();
glState.restore();
}
private void renderCubeGroup(DhApiRenderableBoxGroup cubeGroup, DhApiRenderParam renderEventParam)
{
cubeGroup.preRender(renderEventParam);
for (DhApiRenderableBox cube : cubeGroup.cubeList)
{
renderCube(cubeGroup, cube);
}
}
private void renderCube(DhApiRenderableBoxGroup cubeGroup, DhApiRenderableBox cube)
{
float originOffsetX = 0;
float originOffsetY = 0;
float originOffsetZ = 0;
if (cubeGroup.positionCubesRelativeToGroupOrigin)
{
originOffsetX = cubeGroup.originBlockX;
originOffsetY = cubeGroup.originBlockY;
originOffsetZ = cubeGroup.originBlockZ;
}
Mat4f boxTransform = Mat4f.createTranslateMatrix(
cube.minPos.x + originOffsetX - this.camPosFloatThisFrame.x,
cube.minPos.y + originOffsetY - this.camPosFloatThisFrame.y,
cube.minPos.z + originOffsetZ - this.camPosFloatThisFrame.z);
boxTransform.multiply(Mat4f.createScaleMatrix(
cube.maxPos.x - cube.minPos.x,
cube.maxPos.y - cube.minPos.y,
cube.maxPos.z - cube.minPos.z));
Mat4f transformMatrix = this.transformationMatrixThisFrame.copy();
transformMatrix.multiply(boxTransform);
this.basicUnlitShader.setUniform(this.basicUnlitShader.getUniformLocation("transform"), transformMatrix);
this.basicUnlitShader.setUniform(this.basicUnlitShader.getUniformLocation("uColor"), cube.color);
GL32.glDrawElements(GL32.GL_TRIANGLES , SOLID_BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0);
}
//================//
// helper classes //
//================//
private static final class DhApiRenderableBoxGroup extends AbstractList<DhApiRenderableBox> implements IDhApiRenderableBoxGroup
{
public final static AtomicInteger NEXT_ID_ATOMIC_INT = new AtomicInteger(0);
public final long id;
/** If false the cubes will be positioned relative to the level's origin */
public final boolean positionCubesRelativeToGroupOrigin;
private final ArrayList<DhApiRenderableBox> cubeList;
private float originBlockX;
private float originBlockY;
private float originBlockZ;
@Nullable
public Consumer<DhApiRenderParam> beforeRenderFunc;
// setters/getters //
@Override
public long getId() { return this.id; }
@Override
public void setOriginBlockPos(float x, float y, float z)
{
this.originBlockX = x;
this.originBlockY = y;
this.originBlockZ = z;
}
@Override
public float getOriginBlockX() { return this.originBlockX; }
@Override
public float getOriginBlockY() { return this.originBlockY; }
@Override
public float getOriginBlockZ() { return this.originBlockZ; }
// constructor //
public DhApiRenderableBoxGroup(float originBlockX, float originBlockY, float originBlockZ, List<DhApiRenderableBox> cubeList, boolean positionCubesRelativeToGroupOrigin)
{
// TODO save to database
// TODO when?
this.id = NEXT_ID_ATOMIC_INT.getAndIncrement();
this.cubeList = new ArrayList<>(cubeList);
this.originBlockX = originBlockX;
this.originBlockY = originBlockY;
this.originBlockZ = originBlockZ;
this.positionCubesRelativeToGroupOrigin = positionCubesRelativeToGroupOrigin;
}
// methods //
@Override
public boolean add(DhApiRenderableBox cube) { return this.cubeList.add(cube); }
@Override
public void setPreRenderFunc(Consumer<DhApiRenderParam> func) { this.beforeRenderFunc = func; }
//@Override
public void preRender(DhApiRenderParam renderEventParam)
{
if (this.beforeRenderFunc != null)
{
beforeRenderFunc.accept(renderEventParam);
}
}
// overrides //
@Override
public DhApiRenderableBox get(int index) { return this.cubeList.get(index); }
@Override
public int size() { return this.cubeList.size(); }
@Override
public boolean removeIf(Predicate<? super DhApiRenderableBox> filter) { return this.cubeList.removeIf(filter); }
@Override
public void replaceAll(UnaryOperator<DhApiRenderableBox> operator) { this.cubeList.replaceAll(operator); }
@Override
public void sort(Comparator<? super DhApiRenderableBox> c) { this.cubeList.sort(c); }
@Override
public void forEach(Consumer<? super DhApiRenderableBox> action) { this.cubeList.forEach(action); }
@Override
public Spliterator<DhApiRenderableBox> spliterator() { return this.cubeList.spliterator(); }
@Override
public Stream<DhApiRenderableBox> stream() { return this.cubeList.stream(); }
@Override
public Stream<DhApiRenderableBox> parallelStream() { return this.cubeList.parallelStream(); }
}
}
@@ -57,9 +57,6 @@ import org.apache.logging.log4j.LogManager;
import org.lwjgl.opengl.GL32;
import java.awt.*;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
@@ -424,15 +421,10 @@ public class LodRenderer
DebugRenderer.INSTANCE.render(combinedMatrix);
}
profiler.popPush("Generic Cubes");
profiler.popPush("Custom Objects");
GenericObjectRenderer.INSTANCE.render(renderEventParam);
{
Mat4f combinedMatrix = new Mat4f(renderEventParam.dhProjectionMatrix);
combinedMatrix.multiply(renderEventParam.dhModelViewMatrix);
GenericCubeRenderer.INSTANCE.render(combinedMatrix);
profiler.popPush("LOD cleanup");
}
profiler.popPush("LOD cleanup");
@@ -0,0 +1,9 @@
#version 150 core
uniform vec4 uColor;
out vec4 fragColor;
void main()
{
fragColor = uColor;
}
@@ -0,0 +1,10 @@
#version 150 core
uniform mat4 transform;
in vec3 vPosition;
void main()
{
gl_Position = transform * vec4(vPosition, 1.0);
}