diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/DebugRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/DebugRenderer.java index 36c3db42b..ecced576b 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/DebugRenderer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/DebugRenderer.java @@ -66,7 +66,6 @@ public class DebugRenderer private ShaderProgram basicShader; private GLVertexBuffer vertexBuffer; private GLElementBuffer outlineIndexBuffer; - private GLElementBuffer solidIndexBuffer; private AbstractVertexAttribute va; private boolean init = false; @@ -110,30 +109,6 @@ public class DebugRenderer 3, 7, }; - 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, - }; - - //=============// @@ -210,16 +185,6 @@ public class DebugRenderer this.outlineIndexBuffer = new GLElementBuffer(false); this.outlineIndexBuffer.uploadBuffer(boxOutlineBuffer, EDhApiGpuUploadMethod.DATA, BOX_OUTLINE_INDICES.length * Integer.BYTES, GL32.GL_STATIC_DRAW); - - // solid 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) @@ -259,12 +224,6 @@ public class DebugRenderer } - this.solidIndexBuffer.bind(); - renderSolidBox(new Box(new Vec3f(0f,0f,0f), new Vec3f(16f,190f,16f), Color.CYAN), SOLID_BOX_INDICES); - - - - this.basicShader.unbind(); glState.restore(); } @@ -279,17 +238,6 @@ public class DebugRenderer GL32.glDrawElements(GL32.GL_LINES, BOX_OUTLINE_INDICES.length, GL32.GL_UNSIGNED_INT, 0); } - public void renderSolidBox(Box box, int[] drawIndices) - { - 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.basicShader.setUniform(this.basicShader.getUniformLocation("transform"), transformMatrix); - this.basicShader.setUniform(this.basicShader.getUniformLocation("uColor"), box.color); - GL32.glDrawElements(GL32.GL_TRIANGLES , drawIndices.length, GL32.GL_UNSIGNED_INT, 0); - } - //================// diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/GenericCubeRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/GenericCubeRenderer.java new file mode 100644 index 000000000..1a68cefae --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/GenericCubeRenderer.java @@ -0,0 +1,470 @@ +/* + * 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.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 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 config) { if (INSTANCE != null) { INSTANCE.addRenderer(renderable, config); } } + //public void addRenderer(IDebugRenderable renderable, ConfigEntry config) { this.rendererLists.addRenderable(renderable, config); } + // + //public static void unregister(IDebugRenderable renderable, ConfigEntry config) { if (INSTANCE != null) { INSTANCE.removeRenderer(renderable, config); } } + //private void removeRenderer(IDebugRenderable renderable, ConfigEntry 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 + //{ + // 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> generalRenderableList = new LinkedList<>(); + // + // private final HashMap, LinkedList>> renderableListByConfig = new HashMap<>(); + // + // + // + // // registration // + // + // public void addRenderable(IDebugRenderable renderable, @Nullable ConfigEntry config) + // { + // synchronized (this) + // { + // if (config != null) + // { + // if (!this.renderableListByConfig.containsKey(config)) + // { + // this.renderableListByConfig.put(config, new LinkedList<>()); + // } + // + // LinkedList> renderableList = this.renderableListByConfig.get(config); + // renderableList.add(new WeakReference<>(renderable)); + // } + // else + // { + // this.generalRenderableList.add(new WeakReference<>(renderable)); + // } + // } + // } + // + // public void removeRenderable(IDebugRenderable renderable, @Nullable ConfigEntry config) + // { + // synchronized (this) + // { + // if (config != null) + // { + // if (this.renderableListByConfig.containsKey(config)) + // { + // LinkedList> renderableList = this.renderableListByConfig.get(config); + // this.removeRenderableFromInternalList(renderableList, renderable); + // } + // } + // else + // { + // this.removeRenderableFromInternalList(this.generalRenderableList, renderable); + // } + // } + // } + // private void removeRenderableFromInternalList(LinkedList> rendererList, IDebugRenderable renderable) + // { + // Iterator> iterator = rendererList.iterator(); + // while (iterator.hasNext()) + // { + // WeakReference renderableRef = iterator.next(); + // if (renderableRef.get() == null) + // { + // iterator.remove(); + // continue; + // } + // + // if (renderableRef.get() == renderable) + // { + // iterator.remove(); + // return; + // } + // } + // } + // + // public void clearRenderables() + // { + // for (ConfigEntry config : this.renderableListByConfig.keySet()) + // { + // LinkedList> 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 config : this.renderableListByConfig.keySet()) + // { + // LinkedList> renderableList = this.renderableListByConfig.get(config); + // if (config.get() && renderableList != null && renderableList.size() != 0) + // { + // this.renderList(debugRenderer, renderableList); + // } + // } + // } + // private void renderList(GenericCubeRenderer debugRenderer, LinkedList> rendererList) + // { + // synchronized (this) + // { + // try + // { + // Iterator> iterator = rendererList.iterator(); + // while (iterator.hasNext()) + // { + // WeakReference 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); + // } + // } + // } + //} + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java index 780afd0fb..f23c4fb8f 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java @@ -422,6 +422,15 @@ public class LodRenderer // Note: this can be very slow if a lot of boxes are being rendered DebugRenderer.INSTANCE.render(combinedMatrix); + } + + profiler.popPush("Generic Cubes"); + + { + Mat4f combinedMatrix = new Mat4f(renderEventParam.dhProjectionMatrix); + combinedMatrix.multiply(renderEventParam.dhModelViewMatrix); + + GenericCubeRenderer.INSTANCE.render(combinedMatrix); profiler.popPush("LOD cleanup"); }