Move generic cube rendering into it's own class

This commit is contained in:
James Seibel
2024-06-27 06:36:30 -06:00
parent 352abc40e6
commit 6bfa3a422e
3 changed files with 479 additions and 52 deletions
@@ -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);
}
//================//
@@ -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 <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);
// }
// }
// }
//}
}
@@ -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");
}