From ae6fa83c50531636be25b88f68ec8f1913b45f2f Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sun, 1 Mar 2026 19:33:00 -0600 Subject: [PATCH] generic object rendering --- .../common/renderTest/DhVertexFormat.java | 4 + .../renderTest/McGenericObjectRenderer.java | 648 +++++++++++++++ .../McGenericObjectRenderer_Textures.java | 779 ++++++++++++++++++ .../renderTest/McInstancedVboContainer.java | 392 +++++++++ .../McInstancedVboContainer_Textures.java | 277 +++++++ .../common/renderTest/McTestRenderer.java | 41 +- .../common/wrappers/WrapperFactory.java | 19 + coreSubProjects | 2 +- 8 files changed, 2122 insertions(+), 40 deletions(-) create mode 100644 common/src/main/java/com/seibel/distanthorizons/common/renderTest/McGenericObjectRenderer.java create mode 100644 common/src/main/java/com/seibel/distanthorizons/common/renderTest/McGenericObjectRenderer_Textures.java create mode 100644 common/src/main/java/com/seibel/distanthorizons/common/renderTest/McInstancedVboContainer.java create mode 100644 common/src/main/java/com/seibel/distanthorizons/common/renderTest/McInstancedVboContainer_Textures.java diff --git a/common/src/main/java/com/seibel/distanthorizons/common/renderTest/DhVertexFormat.java b/common/src/main/java/com/seibel/distanthorizons/common/renderTest/DhVertexFormat.java index 1bbb751c8..06b5dec3a 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/renderTest/DhVertexFormat.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/renderTest/DhVertexFormat.java @@ -19,5 +19,9 @@ public class DhVertexFormat public static final VertexFormatElement IRIS_MATERIAL = VertexFormatElement.register(/*id*/13, /*index*/0, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.GENERIC, /*count*/ 1); public static final VertexFormatElement IRIS_NORMAL = VertexFormatElement.register(/*id*/14, /*index*/0, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.GENERIC, /*count*/ 1); + public static final VertexFormatElement FLOAT_XYZ_POS = VertexFormatElement.register(/*id*/15, /*index*/0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.POSITION, /*count*/ 3); + public static final VertexFormatElement VEC3 = VertexFormatElement.register(/*id*/16, /*index*/0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.GENERIC, /*count*/ 3); + public static final VertexFormatElement IVEC3 = VertexFormatElement.register(/*id*/17, /*index*/0, VertexFormatElement.Type.INT, VertexFormatElement.Usage.GENERIC, /*count*/ 3); + } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McGenericObjectRenderer.java b/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McGenericObjectRenderer.java new file mode 100644 index 000000000..6a0e58e94 --- /dev/null +++ b/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McGenericObjectRenderer.java @@ -0,0 +1,648 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020 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.common.renderTest; + +import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import com.mojang.blaze3d.buffers.Std140Builder; +import com.mojang.blaze3d.buffers.Std140SizeCalculator; +import com.mojang.blaze3d.pipeline.BlendFunction; +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.platform.DepthTestFunction; +import com.mojang.blaze3d.platform.PolygonMode; +import com.mojang.blaze3d.shaders.UniformType; +import com.mojang.blaze3d.systems.CommandEncoder; +import com.mojang.blaze3d.systems.GpuDevice; +import com.mojang.blaze3d.systems.RenderPass; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.textures.*; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial; +import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister; +import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup; +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericObjectRenderEvent; +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericRenderCleanupEvent; +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericRenderSetupEvent; +import com.seibel.distanthorizons.api.objects.math.DhApiVec3d; +import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox; +import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading; +import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper; +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.logging.DhLogger; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.logging.f3.F3Screen; +import com.seibel.distanthorizons.core.render.renderer.RenderParams; +import com.seibel.distanthorizons.core.render.renderer.generic.GenericRenderObjectFactory; +import com.seibel.distanthorizons.core.render.renderer.generic.InstancedVboContainer; +import com.seibel.distanthorizons.core.render.renderer.generic.RenderableBoxGroup; +import com.seibel.distanthorizons.core.util.LodUtil; +import com.seibel.distanthorizons.core.util.math.Mat4f; +import com.seibel.distanthorizons.core.util.math.Vec3d; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.render.IMcGenericRenderer; +import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; +import com.seibel.distanthorizons.coreapi.ModInfo; +import net.minecraft.resources.Identifier; + +import java.awt.*; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.Collection; +import java.util.OptionalDouble; +import java.util.OptionalInt; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; + +/** + * Handles rendering generic groups of {@link DhApiRenderableBox}. + * + * @see IDhApiCustomRenderRegister + * @see DhApiRenderableBox + */ +public class McGenericObjectRenderer implements IMcGenericRenderer +{ + private static final DhLogger LOGGER = new DhLoggerBuilder().build(); + + private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); + private static final IMinecraftGLWrapper GLMC = SingletonInjector.INSTANCE.get(IMinecraftGLWrapper.class); + + private static final DhApiRenderableBoxGroupShading DEFAULT_SHADING = DhApiRenderableBoxGroupShading.getUnshaded(); + + /** + * Can be used to troubleshoot the renderer. + * If enabled several debug objects will render around (0,150,0). + */ + public static final boolean RENDER_DEBUG_OBJECTS = false; + + private final ConcurrentHashMap boxGroupById = new ConcurrentHashMap<>(); + + + // rendering setup + private boolean init = false; + + private VertexFormat vertexFormat; + + private RenderPipeline opaquePipeline; + private RenderPipeline transparentPipeline; + + //private GpuBuffer boxVertexBuffer; + //private GpuBuffer boxIndexBuffer; + + private GpuBuffer vertUniformBuffer; + + + //=============// + // constructor // + //=============// + //region + + public McGenericObjectRenderer() { } + + public void init() + { + if (this.init) + { + return; + } + this.init = true; + + this.vertexFormat = VertexFormat.builder() + .add("vPosition", DhVertexFormat.FLOAT_XYZ_POS) + .add("aColor", DhVertexFormat.RGBA_UBYTE_COLOR) + .add("aMaterial", DhVertexFormat.IRIS_MATERIAL) + .build(); + + this.createPipelines(); + //this.createBuffers(); + + if (RENDER_DEBUG_OBJECTS) + { + this.addGenericDebugObjects(); + } + } + private void createPipelines() + { + GpuDevice gpuDevice = RenderSystem.getDevice(); + CommandEncoder commandEncoder = gpuDevice.createCommandEncoder(); + + + RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder(); + { + pipelineBuilder.withCull(true); + pipelineBuilder.withDepthWrite(true); + pipelineBuilder.withDepthTestFunction(DepthTestFunction.LESS_DEPTH_TEST); + pipelineBuilder.withColorWrite(true); + pipelineBuilder.withPolygonMode(PolygonMode.FILL); + pipelineBuilder.withLocation(Identifier.parse("distanthorizons:generic")); + + pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "generic/vert")); + pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "generic/frag")); + + pipelineBuilder.withSampler("uLightMap"); + + pipelineBuilder.withUniform("vertUniformBlock", UniformType.UNIFORM_BUFFER); + + pipelineBuilder.withVertexFormat(this.vertexFormat, VertexFormat.Mode.TRIANGLES); + } + + // opaque + { + pipelineBuilder.withoutBlend(); + this.opaquePipeline = pipelineBuilder.build(); + } + + // transparent + { + pipelineBuilder.withBlend(BlendFunction.TRANSLUCENT); + this.transparentPipeline = pipelineBuilder.build(); + } + + } + private void addGenericDebugObjects() + { + GenericRenderObjectFactory factory = GenericRenderObjectFactory.INSTANCE; + + + // single giant box + IDhApiRenderableBoxGroup singleGiantBoxGroup = factory.createForSingleBox( + ModInfo.NAME + ":CyanChunkBox", + new DhApiRenderableBox( + new DhApiVec3d(0,0,0), new DhApiVec3d(16,190,16), + new Color(Color.CYAN.getRed(), Color.CYAN.getGreen(), Color.CYAN.getBlue(), 125), + EDhApiBlockMaterial.WATER) + ); + singleGiantBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT); + singleGiantBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT); + this.add(singleGiantBoxGroup); + + + // single slender box + IDhApiRenderableBoxGroup singleTallBoxGroup = factory.createForSingleBox( + ModInfo.NAME + ":GreenBeacon", + new DhApiRenderableBox( + new DhApiVec3d(16,0,31), new DhApiVec3d(17,2000,32), + new Color(Color.GREEN.getRed(), Color.GREEN.getGreen(), Color.GREEN.getBlue(), 125), + EDhApiBlockMaterial.ILLUMINATED) + ); + singleTallBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT); + singleTallBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT); + this.add(singleTallBoxGroup); + + + // absolute box group + ArrayList absBoxList = new ArrayList<>(); + for (int i = 0; i < 18; i++) + { + absBoxList.add(new DhApiRenderableBox( + new DhApiVec3d(i,150+i,24), new DhApiVec3d(1+i,151+i,25), + new Color(Color.ORANGE.getRed(), Color.ORANGE.getGreen(), Color.ORANGE.getBlue()), + EDhApiBlockMaterial.LAVA + ) + ); + } + IDhApiRenderableBoxGroup absolutePosBoxGroup = factory.createAbsolutePositionedGroup(ModInfo.NAME + ":OrangeStairs", absBoxList); + this.add(absolutePosBoxGroup); + + + // relative box group + ArrayList relBoxList = new ArrayList<>(); + for (int i = 0; i < 8; i+=2) + { + relBoxList.add(new DhApiRenderableBox( + new DhApiVec3d(0,i,0), new DhApiVec3d(1,1+i,1), + new Color(Color.MAGENTA.getRed(), Color.MAGENTA.getGreen(), Color.MAGENTA.getBlue()), + EDhApiBlockMaterial.METAL + ) + ); + } + IDhApiRenderableBoxGroup relativePosBoxGroup = factory.createRelativePositionedGroup( + ModInfo.NAME + ":MovingMagentaGroup", + new DhApiVec3d(24, 140, 24), + relBoxList); + relativePosBoxGroup.setPreRenderFunc((event) -> + { + DhApiVec3d pos = relativePosBoxGroup.getOriginBlockPos(); + pos.x += event.partialTicks / 2; + pos.x %= 32; + relativePosBoxGroup.setOriginBlockPos(pos); + }); + this.add(relativePosBoxGroup); + + + // massive relative box group + ArrayList massRelBoxList = new ArrayList<>(); + for (int x = 0; x < 50*2; x+=2) + { + for (int z = 0; z < 50*2; z+=2) + { + massRelBoxList.add(new DhApiRenderableBox( + new DhApiVec3d(-x, 0, -z), new DhApiVec3d(1-x, 1, 1-z), + new Color(Color.RED.getRed(), Color.RED.getGreen(), Color.RED.getBlue()), + EDhApiBlockMaterial.TERRACOTTA + ) + ); + } + } + IDhApiRenderableBoxGroup massRelativePosBoxGroup = factory.createRelativePositionedGroup( + ModInfo.NAME + ":MassRedGroup", + new DhApiVec3d(-25, 140, 0), + massRelBoxList); + massRelativePosBoxGroup.setPreRenderFunc((event) -> + { + DhApiVec3d blockPos = massRelativePosBoxGroup.getOriginBlockPos(); + blockPos.y += event.partialTicks / 4; + if (blockPos.y > 150f) + { + blockPos.y = 140f; + + Color newColor = (massRelativePosBoxGroup.get(0).color == Color.RED) ? Color.RED.darker() : Color.RED; + massRelativePosBoxGroup.forEach((box) -> { box.color = newColor; }); + massRelativePosBoxGroup.triggerBoxChange(); + } + + massRelativePosBoxGroup.setOriginBlockPos(blockPos); + }); + this.add(massRelativePosBoxGroup); + } + + //endregion + + + + //==============// + // registration // + //==============// + //region + + @Override + public void add(IDhApiRenderableBoxGroup iBoxGroup) throws IllegalArgumentException + { + if (!(iBoxGroup instanceof RenderableBoxGroup)) + { + throw new IllegalArgumentException("Box group must be of type ["+ RenderableBoxGroup.class.getSimpleName()+"], type received: ["+(iBoxGroup != null ? iBoxGroup.getClass() : "NULL")+"]."); + } + RenderableBoxGroup boxGroup = (RenderableBoxGroup) iBoxGroup; + + + long id = boxGroup.getId(); + if (this.boxGroupById.containsKey(id)) + { + throw new IllegalArgumentException("A box group with the ID [" + id + "] is already present."); + } + + this.boxGroupById.put(id, boxGroup); + } + + @Override + public IDhApiRenderableBoxGroup remove(long id) { return this.boxGroupById.remove(id); } + + public void clear() { this.boxGroupById.clear(); } + + //endregion + + + + //===========// + // rendering // + //===========// + //region + + /** + * @param renderingWithSsao + * if true that means this render call is happening before the SSAO pass + * and any objects rendered in this pass will have SSAO applied to them. + */ + @Override + public void render(RenderParams renderEventParam, IProfilerWrapper profiler, boolean renderingWithSsao) + { + //==============// + // render setup // + //==============// + //#region + + profiler.push("setup"); + + this.init(); + + ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderSetupEvent.class, renderEventParam); + + Vec3d camPos = MC_RENDER.getCameraExactPosition(); + + //#endregion + + if (McLodRenderer.INSTANCE.dhColorTexture == null + || McLodRenderer.INSTANCE.dhDepthTexture == null) + { + return; + } + + + + //===========// + // rendering // + //===========// + //#region + + GpuDevice gpuDevice = RenderSystem.getDevice(); + CommandEncoder commandEncoder = gpuDevice.createCommandEncoder(); + + Collection boxList = this.boxGroupById.values(); + for (RenderableBoxGroup boxGroup : boxList) + { + // validation // + + // shouldn't happen, but just in case + if (boxGroup == null) + { + continue; + } + + // skip boxes that shouldn't render this pass + if (boxGroup.ssaoEnabled != renderingWithSsao) + { + continue; + } + + profiler.popPush("render prep"); + boxGroup.preRender(renderEventParam); // called even if the group is inactive, so the group can be activate if desired + + // ignore inactive groups + if (!boxGroup.active) + { + continue; + } + + // allow API users to cancel this object's rendering + boolean cancelRendering = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericObjectRenderEvent.class, new DhApiBeforeGenericObjectRenderEvent.EventParam(renderEventParam, boxGroup)); + if (cancelRendering) + { + continue; + } + + // update instanced data if needed + { + boxGroup.tryUpdateInstancedDataAsync(); + + // skip groups that haven't been uploaded yet + if (boxGroup.instancedVbos.getState() != InstancedVboContainer.EState.RENDER) + { + continue; + } + } + + + DhApiRenderableBoxGroupShading shading = boxGroup.shading; + if (shading == null) + { + shading = DEFAULT_SHADING; + } + + // uniforms + { + int uniformBufferSize = new Std140SizeCalculator() + .putIVec3() // uOffsetChunk + .putVec3() // uOffsetSubChunk + .putIVec3() // uCameraPosChunk + .putVec3() // uCameraPosSubChunk + + .putVec3() // aTranslateChunk + .putVec3() // aTranslateSubChunk + + .putMat4f() // uProjectionMvm + .putInt() // uSkyLight + .putInt() // uBlockLight + + .putFloat() // uNorthShading + .putFloat() // uSouthShading + .putFloat() // uEastShading + .putFloat() // uWestShading + .putFloat() // uTopShading + .putFloat() // uBottomShading + .get(); + + + // create data // + + Mat4f projectionMvmMatrix = new Mat4f(renderEventParam.dhProjectionMatrix); + projectionMvmMatrix.multiply(renderEventParam.dhModelViewMatrix); + + + // upload data // + + ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize); + buffer.order(ByteOrder.LITTLE_ENDIAN); + buffer = Std140Builder.intoBuffer(buffer) + .putIVec3( + LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().x), + LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().y), + LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().z) + ) // uOffsetChunk + .putVec3( + LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().x), + LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().y), + LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().z) + ) // uOffsetSubChunk + .putIVec3( + LodUtil.getChunkPosFromDouble(camPos.x), + LodUtil.getChunkPosFromDouble(camPos.y), + LodUtil.getChunkPosFromDouble(camPos.z) + ) // uCameraPosChunk + .putVec3( + LodUtil.getSubChunkPosFromDouble(camPos.x), + LodUtil.getSubChunkPosFromDouble(camPos.y), + LodUtil.getSubChunkPosFromDouble(camPos.z) + ) // uCameraPosSubChunk + + .putMat4f(projectionMvmMatrix.createJomlMatrix()) // uProjectionMvm + .putInt(boxGroup.getSkyLight()) // uSkyLight + .putInt(boxGroup.getBlockLight()) // uBlockLight + + .putFloat(shading.north) + .putFloat(shading.south) + .putFloat(shading.east) + .putFloat(shading.west) + .putFloat(shading.top) + .putFloat(shading.bottom) + + .get() + ; + + this.vertUniformBuffer = UniformHandler.createBuffer("vertUniformBlock", uniformBufferSize, this.vertUniformBuffer); + GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vertUniformBuffer, 0, uniformBufferSize); + + commandEncoder.writeToBuffer(bufferSlice, buffer); + } + + + + + // render // + + profiler.popPush("rendering"); + profiler.push(boxGroup.getResourceLocationNamespace()); + profiler.push(boxGroup.getResourceLocationPath()); + + Supplier debugLabelSupplier = () -> "distantHorizons:McTestRenderer"; + GpuTextureView colorTexture = gpuDevice.createTextureView(McLodRenderer.INSTANCE.dhColorTexture); + OptionalInt optionalClearColorAsInt = OptionalInt.empty(); + GpuTextureView depthTexture = gpuDevice.createTextureView(McLodRenderer.INSTANCE.dhDepthTexture); + OptionalDouble optionalDepthValueAsDouble = OptionalDouble.empty(); + + try (RenderPass renderPass = commandEncoder.createRenderPass( + debugLabelSupplier, + colorTexture, + optionalClearColorAsInt, + depthTexture, optionalDepthValueAsDouble)) + { + this.renderBoxGroupInstanced(renderPass, renderEventParam, boxGroup, camPos, profiler); + } + + profiler.pop(); // resource path + profiler.pop(); // resource namespace + + boxGroup.postRender(renderEventParam); + } + + //#endregion + + + + //==========// + // clean up // + //==========// + //region + + profiler.popPush("cleanup"); + + ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderCleanupEvent.class, renderEventParam); + + profiler.pop(); + + //endregion + } + + //endregion + + + + //=====================// + // instanced rendering // + //=====================// + //region + + private void renderBoxGroupInstanced( + RenderPass renderPass, RenderParams renderEventParam, + RenderableBoxGroup boxGroup, Vec3d camPos, + IProfilerWrapper profiler) + { + // update instance data // + + profiler.push("vertex setup"); + + GpuDevice gpuDevice = RenderSystem.getDevice(); + + McInstancedVboContainer container = (McInstancedVboContainer) boxGroup.instancedVbos; + + + // bind MC Lightmap + { + LightMapWrapper lightMapWrapper = (LightMapWrapper) renderEventParam.lightmap; + + GpuTextureView textureView = gpuDevice.createTextureView(lightMapWrapper.gpuTexture); + GpuSampler gpuSampler = gpuDevice.createSampler( + AddressMode.CLAMP_TO_EDGE, AddressMode.CLAMP_TO_EDGE, // U,V + FilterMode.NEAREST, FilterMode.NEAREST, // minFilter, magFilter + 1, // maxAnisotropy + OptionalDouble.empty() // maxLod + ); + renderPass.bindTexture("uLightMap", textureView, gpuSampler); + } + + + + // Bind instance data // + profiler.popPush("binding"); + + + renderPass.setUniform("vertUniformBlock", this.vertUniformBuffer); + + // set pipeline + renderPass.setPipeline(this.opaquePipeline); // TODO + renderPass.setIndexBuffer(container.indexGpuBuffer, VertexFormat.IndexType.INT); + + renderPass.setVertexBuffer(0, container.vboGpuBuffer); + + // Draw instanced + profiler.popPush("render"); + if (container.uploadedBoxCount > 0) + { + renderPass.drawIndexed( + /*indexStart*/ 0, + /*firstIndex*/0, + /*indexCount*/container.uploadedBoxCount * 24, // TODO? + /*instanceCount*/1); + + } + + profiler.pop(); + } + + //endregion + + + + //=========// + // F3 menu // + //=========// + //region + + public String getVboRenderDebugMenuString() + { + // get counts + int totalGroupCount = this.boxGroupById.size(); + int totalBoxCount = 0; + + int activeGroupCount = 0; + int activeBoxCount = 0; + + for (long key : this.boxGroupById.keySet()) + { + RenderableBoxGroup renderGroup = this.boxGroupById.get(key); + if (renderGroup.active) + { + activeGroupCount++; + activeBoxCount += renderGroup.size(); + } + totalBoxCount += renderGroup.size(); + } + + + return "Generic Obj #: " + F3Screen.NUMBER_FORMAT.format(activeGroupCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalGroupCount) + ", " + + "Cube #: " + F3Screen.NUMBER_FORMAT.format(activeBoxCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalBoxCount); + } + + //endregion + + + +} diff --git a/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McGenericObjectRenderer_Textures.java b/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McGenericObjectRenderer_Textures.java new file mode 100644 index 000000000..176ff7975 --- /dev/null +++ b/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McGenericObjectRenderer_Textures.java @@ -0,0 +1,779 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020 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.common.renderTest; + +import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import com.mojang.blaze3d.buffers.Std140Builder; +import com.mojang.blaze3d.buffers.Std140SizeCalculator; +import com.mojang.blaze3d.pipeline.BlendFunction; +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.platform.DepthTestFunction; +import com.mojang.blaze3d.platform.PolygonMode; +import com.mojang.blaze3d.shaders.UniformType; +import com.mojang.blaze3d.systems.CommandEncoder; +import com.mojang.blaze3d.systems.GpuDevice; +import com.mojang.blaze3d.systems.RenderPass; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.textures.AddressMode; +import com.mojang.blaze3d.textures.FilterMode; +import com.mojang.blaze3d.textures.GpuSampler; +import com.mojang.blaze3d.textures.GpuTextureView; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial; +import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister; +import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup; +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericObjectRenderEvent; +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericRenderCleanupEvent; +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericRenderSetupEvent; +import com.seibel.distanthorizons.api.objects.math.DhApiVec3d; +import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox; +import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading; +import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper; +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.logging.DhLogger; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.logging.f3.F3Screen; +import com.seibel.distanthorizons.core.render.renderer.RenderParams; +import com.seibel.distanthorizons.core.render.renderer.generic.GenericRenderObjectFactory; +import com.seibel.distanthorizons.core.render.renderer.generic.InstancedVboContainer; +import com.seibel.distanthorizons.core.render.renderer.generic.RenderableBoxGroup; +import com.seibel.distanthorizons.core.util.LodUtil; +import com.seibel.distanthorizons.core.util.math.Mat4f; +import com.seibel.distanthorizons.core.util.math.Vec3d; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.render.IMcGenericRenderer; +import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; +import com.seibel.distanthorizons.coreapi.ModInfo; +import net.minecraft.resources.Identifier; +import org.lwjgl.system.MemoryUtil; + +import java.awt.*; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.Collection; +import java.util.OptionalDouble; +import java.util.OptionalInt; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; + +/** + * Handles rendering generic groups of {@link DhApiRenderableBox}. + * + * @see IDhApiCustomRenderRegister + * @see DhApiRenderableBox + */ +public class McGenericObjectRenderer_Textures implements IMcGenericRenderer +{ + private static final DhLogger LOGGER = new DhLoggerBuilder().build(); + + private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); + private static final IMinecraftGLWrapper GLMC = SingletonInjector.INSTANCE.get(IMinecraftGLWrapper.class); + + private static final DhApiRenderableBoxGroupShading DEFAULT_SHADING = DhApiRenderableBoxGroupShading.getUnshaded(); + + /** + * Can be used to troubleshoot the renderer. + * If enabled several debug objects will render around (0,150,0). + */ + public static final boolean RENDER_DEBUG_OBJECTS = false; + + /** A box from 0,0,0 to 1,1,1 */ + private static final float[] BOX_VERTICES = { + //region + // Pos x y z + + // min X, vertical face + 0, 0, 0, + 1, 0, 0, + 1, 1, 0, + 0, 1, 0, + // max X, vertical face + 0, 1, 1, + 1, 1, 1, + 1, 0, 1, + 0, 0, 1, + + // min Z, vertical face + 0, 0, 1, + 0, 0, 0, + 0, 1, 0, + 0, 1, 1, + // max Z, vertical face + 1, 0, 1, + 1, 1, 1, + 1, 1, 0, + 1, 0, 0, + + // min Y, horizontal face + 0, 0, 1, + 1, 0, 1, + 1, 0, 0, + 0, 0, 0, + // max Y, horizontal face + 0, 1, 1, + 1, 1, 1, + 1, 1, 0, + 0, 1, 0, + //endregion + }; + + private static final int[] BOX_INDICES = { + //region + // min X, vertical face + 2, 1, 0, + 0, 3, 2, + // max X, vertical face + 6, 5, 4, + 4, 7, 6, + + // min Z, vertical face + 10, 9, 8, + 8, 11, 10, + // max Z, vertical face + 14, 13, 12, + 12, 15, 14, + + // min Y, horizontal face + 18, 17, 16, + 16, 19, 18, + // max Y, horizontal face + 20, 21, 22, + 22, 23, 20, + //endregion + }; + + private final ConcurrentHashMap boxGroupById = new ConcurrentHashMap<>(); + + + // rendering setup + private boolean init = false; + + private VertexFormat vertexFormat; + + private RenderPipeline opaquePipeline; + private RenderPipeline transparentPipeline; + + private GpuBuffer boxVertexBuffer; + private GpuBuffer boxIndexBuffer; + + private GpuBuffer fragUniformBuffer; + private GpuBuffer vertUniformBuffer; + + + + //=============// + // constructor // + //=============// + //region + + public McGenericObjectRenderer_Textures() { } + + public void init() + { + if (this.init) + { + return; + } + this.init = true; + + this.vertexFormat = VertexFormat.builder() + .add("vPosition", DhVertexFormat.FLOAT_XYZ_POS) + .build(); + + this.createPipelines(); + this.createBuffers(); + + if (RENDER_DEBUG_OBJECTS) + { + this.addGenericDebugObjects(); + } + } + private void createPipelines() + { + GpuDevice gpuDevice = RenderSystem.getDevice(); + CommandEncoder commandEncoder = gpuDevice.createCommandEncoder(); + + + RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder(); + { + pipelineBuilder.withCull(true); + pipelineBuilder.withDepthWrite(true); + pipelineBuilder.withDepthTestFunction(DepthTestFunction.LESS_DEPTH_TEST); + pipelineBuilder.withColorWrite(true); + pipelineBuilder.withPolygonMode(PolygonMode.FILL); + pipelineBuilder.withLocation(Identifier.parse("distanthorizons:generic")); + + pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "generic/vert")); + pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "generic/frag")); + + pipelineBuilder.withSampler("uColorMap"); + + pipelineBuilder.withSampler("uLightMap"); + + pipelineBuilder.withUniform("vertUniformBlock", UniformType.UNIFORM_BUFFER); + + pipelineBuilder.withVertexFormat(this.vertexFormat, VertexFormat.Mode.TRIANGLES); + } + + // opaque + { + pipelineBuilder.withoutBlend(); + this.opaquePipeline = pipelineBuilder.build(); + } + + // transparent + { + pipelineBuilder.withBlend(BlendFunction.TRANSLUCENT); + this.transparentPipeline = pipelineBuilder.build(); + } + + } + private void createBuffers() + { + // box vertices + ByteBuffer boxVerticesBuffer = MemoryUtil.memAlloc(BOX_VERTICES.length * Float.BYTES); + boxVerticesBuffer.asFloatBuffer().put(BOX_VERTICES); + boxVerticesBuffer.rewind(); + MemoryUtil.memFree(boxVerticesBuffer); + + + GpuDevice gpuDevice = RenderSystem.getDevice(); + CommandEncoder commandEncoder = gpuDevice.createCommandEncoder(); + + // upload vertex data + { + Supplier labelSupplier = () -> "distantHorizons:McGenericRenderer"; + int usage = 8 | 32; // is this just using OpenGL VBO flags?, if so I can't find it, supposedly GlDevice on Mojang's side + int size = BOX_VERTICES.length * Float.BYTES; + this.boxVertexBuffer = gpuDevice.createBuffer(labelSupplier, usage, size); + + { + int offset = 0; + int length = BOX_VERTICES.length * Float.BYTES; + GpuBufferSlice bufferSlice = new GpuBufferSlice(this.boxVertexBuffer, offset, length); + + ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BOX_VERTICES.length * Float.BYTES); + // Fill buffer with vertices. + byteBuffer.order(ByteOrder.nativeOrder()); + byteBuffer.asFloatBuffer().put(BOX_VERTICES); + byteBuffer.rewind(); + + commandEncoder.writeToBuffer(bufferSlice, byteBuffer); + } + } + + // box vertex indexes + { + ByteBuffer buffer = ByteBuffer.allocateDirect(BOX_INDICES.length * Integer.BYTES); + buffer.asIntBuffer().put(BOX_INDICES); + buffer.rewind(); + + + // TODO + // GpuBuffer.USAGE_UNIFORM = 128 + // GpuBuffer.USAGE_INDEX = 64 + int usage = 8 | 32 | 64 | 128; // is this just using OpenGL VBO flags?, if so I can't find it, supposedly GlDevice on Mojang's side + this.boxIndexBuffer = gpuDevice.createBuffer(() -> "DH Generic Index Buffer", usage, buffer.capacity()); + + int offset = 0; + GpuBufferSlice bufferSlice = new GpuBufferSlice(this.boxIndexBuffer, offset, buffer.capacity()); + commandEncoder.writeToBuffer(bufferSlice, buffer); + } + } + private void addGenericDebugObjects() + { + GenericRenderObjectFactory factory = GenericRenderObjectFactory.INSTANCE; + + + // single giant box + IDhApiRenderableBoxGroup singleGiantBoxGroup = factory.createForSingleBox( + ModInfo.NAME + ":CyanChunkBox", + new DhApiRenderableBox( + new DhApiVec3d(0,0,0), new DhApiVec3d(16,190,16), + new Color(Color.CYAN.getRed(), Color.CYAN.getGreen(), Color.CYAN.getBlue(), 125), + EDhApiBlockMaterial.WATER) + ); + singleGiantBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT); + singleGiantBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT); + this.add(singleGiantBoxGroup); + + + // single slender box + IDhApiRenderableBoxGroup singleTallBoxGroup = factory.createForSingleBox( + ModInfo.NAME + ":GreenBeacon", + new DhApiRenderableBox( + new DhApiVec3d(16,0,31), new DhApiVec3d(17,2000,32), + new Color(Color.GREEN.getRed(), Color.GREEN.getGreen(), Color.GREEN.getBlue(), 125), + EDhApiBlockMaterial.ILLUMINATED) + ); + singleTallBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT); + singleTallBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT); + this.add(singleTallBoxGroup); + + + // absolute box group + ArrayList absBoxList = new ArrayList<>(); + for (int i = 0; i < 18; i++) + { + absBoxList.add(new DhApiRenderableBox( + new DhApiVec3d(i,150+i,24), new DhApiVec3d(1+i,151+i,25), + new Color(Color.ORANGE.getRed(), Color.ORANGE.getGreen(), Color.ORANGE.getBlue()), + EDhApiBlockMaterial.LAVA + ) + ); + } + IDhApiRenderableBoxGroup absolutePosBoxGroup = factory.createAbsolutePositionedGroup(ModInfo.NAME + ":OrangeStairs", absBoxList); + this.add(absolutePosBoxGroup); + + + // relative box group + ArrayList relBoxList = new ArrayList<>(); + for (int i = 0; i < 8; i+=2) + { + relBoxList.add(new DhApiRenderableBox( + new DhApiVec3d(0,i,0), new DhApiVec3d(1,1+i,1), + new Color(Color.MAGENTA.getRed(), Color.MAGENTA.getGreen(), Color.MAGENTA.getBlue()), + EDhApiBlockMaterial.METAL + ) + ); + } + IDhApiRenderableBoxGroup relativePosBoxGroup = factory.createRelativePositionedGroup( + ModInfo.NAME + ":MovingMagentaGroup", + new DhApiVec3d(24, 140, 24), + relBoxList); + relativePosBoxGroup.setPreRenderFunc((event) -> + { + DhApiVec3d pos = relativePosBoxGroup.getOriginBlockPos(); + pos.x += event.partialTicks / 2; + pos.x %= 32; + relativePosBoxGroup.setOriginBlockPos(pos); + }); + this.add(relativePosBoxGroup); + + + // massive relative box group + ArrayList massRelBoxList = new ArrayList<>(); + for (int x = 0; x < 50*2; x+=2) + { + for (int z = 0; z < 50*2; z+=2) + { + massRelBoxList.add(new DhApiRenderableBox( + new DhApiVec3d(-x, 0, -z), new DhApiVec3d(1-x, 1, 1-z), + new Color(Color.RED.getRed(), Color.RED.getGreen(), Color.RED.getBlue()), + EDhApiBlockMaterial.TERRACOTTA + ) + ); + } + } + IDhApiRenderableBoxGroup massRelativePosBoxGroup = factory.createRelativePositionedGroup( + ModInfo.NAME + ":MassRedGroup", + new DhApiVec3d(-25, 140, 0), + massRelBoxList); + massRelativePosBoxGroup.setPreRenderFunc((event) -> + { + DhApiVec3d blockPos = massRelativePosBoxGroup.getOriginBlockPos(); + blockPos.y += event.partialTicks / 4; + if (blockPos.y > 150f) + { + blockPos.y = 140f; + + Color newColor = (massRelativePosBoxGroup.get(0).color == Color.RED) ? Color.RED.darker() : Color.RED; + massRelativePosBoxGroup.forEach((box) -> { box.color = newColor; }); + massRelativePosBoxGroup.triggerBoxChange(); + } + + massRelativePosBoxGroup.setOriginBlockPos(blockPos); + }); + this.add(massRelativePosBoxGroup); + } + + //endregion + + + + //==============// + // registration // + //==============// + //region + + @Override + public void add(IDhApiRenderableBoxGroup iBoxGroup) throws IllegalArgumentException + { + if (!(iBoxGroup instanceof RenderableBoxGroup)) + { + throw new IllegalArgumentException("Box group must be of type ["+ RenderableBoxGroup.class.getSimpleName()+"], type received: ["+(iBoxGroup != null ? iBoxGroup.getClass() : "NULL")+"]."); + } + RenderableBoxGroup boxGroup = (RenderableBoxGroup) iBoxGroup; + + + long id = boxGroup.getId(); + if (this.boxGroupById.containsKey(id)) + { + throw new IllegalArgumentException("A box group with the ID [" + id + "] is already present."); + } + + this.boxGroupById.put(id, boxGroup); + } + + @Override + public IDhApiRenderableBoxGroup remove(long id) { return this.boxGroupById.remove(id); } + + public void clear() { this.boxGroupById.clear(); } + + //endregion + + + + //===========// + // rendering // + //===========// + //region + + /** + * @param renderingWithSsao + * if true that means this render call is happening before the SSAO pass + * and any objects rendered in this pass will have SSAO applied to them. + */ + @Override + public void render(RenderParams renderEventParam, IProfilerWrapper profiler, boolean renderingWithSsao) + { + //==============// + // render setup // + //==============// + //#region + + profiler.push("setup"); + + this.init(); + + ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderSetupEvent.class, renderEventParam); + + Vec3d camPos = MC_RENDER.getCameraExactPosition(); + + //#endregion + + if (McLodRenderer.INSTANCE.dhColorTexture == null + || McLodRenderer.INSTANCE.dhDepthTexture == null) + { + return; + } + + + + //===========// + // rendering // + //===========// + //#region + + GpuDevice gpuDevice = RenderSystem.getDevice(); + CommandEncoder commandEncoder = gpuDevice.createCommandEncoder(); + + Collection boxList = this.boxGroupById.values(); + for (RenderableBoxGroup boxGroup : boxList) + { + // validation // + + // shouldn't happen, but just in case + if (boxGroup == null) + { + continue; + } + + // skip boxes that shouldn't render this pass + if (boxGroup.ssaoEnabled != renderingWithSsao) + { + continue; + } + + profiler.popPush("render prep"); + boxGroup.preRender(renderEventParam); // called even if the group is inactive, so the group can be activate if desired + + // ignore inactive groups + if (!boxGroup.active) + { + continue; + } + + // allow API users to cancel this object's rendering + boolean cancelRendering = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericObjectRenderEvent.class, new DhApiBeforeGenericObjectRenderEvent.EventParam(renderEventParam, boxGroup)); + if (cancelRendering) + { + continue; + } + + // update instanced data if needed + { + boxGroup.tryUpdateInstancedDataAsync(); + + // skip groups that haven't been uploaded yet + if (boxGroup.instancedVbos.getState() != InstancedVboContainer.EState.RENDER) + { + continue; + } + } + + + DhApiRenderableBoxGroupShading shading = boxGroup.shading; + if (shading == null) + { + shading = DEFAULT_SHADING; + } + + // uniforms + { + int uniformBufferSize = new Std140SizeCalculator() + .putIVec3() // uOffsetChunk + .putVec3() // uOffsetSubChunk + .putIVec3() // uCameraPosChunk + .putVec3() // uCameraPosSubChunk + + .putMat4f() // uProjectionMvm + .putInt() // uSkyLight + .putInt() // uBlockLight + + .putFloat() // uNorthShading + .putFloat() // uSouthShading + .putFloat() // uEastShading + .putFloat() // uWestShading + .putFloat() // uTopShading + .putFloat() // uBottomShading + .get(); + + + // create data // + + Mat4f projectionMvmMatrix = new Mat4f(renderEventParam.dhProjectionMatrix); + projectionMvmMatrix.multiply(renderEventParam.dhModelViewMatrix); + + + // upload data // + + ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize); + buffer.order(ByteOrder.LITTLE_ENDIAN); + buffer = Std140Builder.intoBuffer(buffer) + .putIVec3( + LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().x), + LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().y), + LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().z) + ) // uOffsetChunk + .putVec3( + LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().x), + LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().y), + LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().z) + ) // uOffsetSubChunk + .putIVec3( + LodUtil.getChunkPosFromDouble(camPos.x), + LodUtil.getChunkPosFromDouble(camPos.y), + LodUtil.getChunkPosFromDouble(camPos.z) + ) // uCameraPosChunk + .putVec3( + LodUtil.getSubChunkPosFromDouble(camPos.x), + LodUtil.getSubChunkPosFromDouble(camPos.y), + LodUtil.getSubChunkPosFromDouble(camPos.z) + ) // uCameraPosSubChunk + + .putMat4f(projectionMvmMatrix.createJomlMatrix()) // uProjectionMvm + .putInt(boxGroup.getSkyLight()) // uSkyLight + .putInt(boxGroup.getBlockLight()) // uBlockLight + + .putFloat(shading.north) + .putFloat(shading.south) + .putFloat(shading.east) + .putFloat(shading.west) + .putFloat(shading.top) + .putFloat(shading.bottom) + + .get() + ; + + this.fragUniformBuffer = UniformHandler.createBuffer("vertUniformBlock", uniformBufferSize, this.fragUniformBuffer); + GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize); + + commandEncoder.writeToBuffer(bufferSlice, buffer); + } + + + + + // render // + + profiler.popPush("rendering"); + profiler.push(boxGroup.getResourceLocationNamespace()); + profiler.push(boxGroup.getResourceLocationPath()); + + Supplier debugLabelSupplier = () -> "distantHorizons:McTestRenderer"; + GpuTextureView colorTexture = gpuDevice.createTextureView(McLodRenderer.INSTANCE.dhColorTexture); + OptionalInt optionalClearColorAsInt = OptionalInt.empty(); + GpuTextureView depthTexture = gpuDevice.createTextureView(McLodRenderer.INSTANCE.dhDepthTexture); + OptionalDouble optionalDepthValueAsDouble = OptionalDouble.empty(); + + try (RenderPass renderPass = commandEncoder.createRenderPass( + debugLabelSupplier, + colorTexture, + optionalClearColorAsInt, + depthTexture, optionalDepthValueAsDouble)) + { + this.renderBoxGroupInstanced(renderPass, renderEventParam, boxGroup, camPos, profiler); + } + + profiler.pop(); // resource path + profiler.pop(); // resource namespace + + boxGroup.postRender(renderEventParam); + } + + //#endregion + + + + //==========// + // clean up // + //==========// + //region + + profiler.popPush("cleanup"); + + ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderCleanupEvent.class, renderEventParam); + + profiler.pop(); + + //endregion + } + + //endregion + + + + //=====================// + // instanced rendering // + //=====================// + //region + + private void renderBoxGroupInstanced( + RenderPass renderPass, RenderParams renderEventParam, + RenderableBoxGroup boxGroup, Vec3d camPos, + IProfilerWrapper profiler) + { + // update instance data // + + profiler.push("vertex setup"); + + GpuDevice gpuDevice = RenderSystem.getDevice(); + + McInstancedVboContainer_Textures container = (McInstancedVboContainer_Textures) boxGroup.instancedVbos; + + + // bind MC Lightmap + { + LightMapWrapper lightMapWrapper = (LightMapWrapper) renderEventParam.lightmap; + + GpuTextureView textureView = gpuDevice.createTextureView(lightMapWrapper.gpuTexture); + GpuSampler gpuSampler = gpuDevice.createSampler( + AddressMode.CLAMP_TO_EDGE, AddressMode.CLAMP_TO_EDGE, // U,V + FilterMode.NEAREST, FilterMode.NEAREST, // minFilter, magFilter + 1, // maxAnisotropy + OptionalDouble.empty() // maxLod + ); + renderPass.bindTexture("uLightMap", textureView, gpuSampler); + } + + renderPass.setIndexBuffer(this.boxIndexBuffer, VertexFormat.IndexType.INT); + + + + // Bind instance data // + profiler.popPush("binding"); + { + GpuTextureView colorView = gpuDevice.createTextureView(container.colorTexture); + GpuSampler colorSampler = gpuDevice.createSampler( + AddressMode.CLAMP_TO_EDGE, AddressMode.CLAMP_TO_EDGE, // U,V + FilterMode.NEAREST, FilterMode.NEAREST, // minFilter, magFilter + 1, // maxAnisotropy + OptionalDouble.empty() // maxLod + ); + renderPass.bindTexture("uColorMap", colorView, colorSampler); + + + renderPass.setVertexBuffer(0, this.boxVertexBuffer); + } + + renderPass.setUniform("vertUniformBlock", this.fragUniformBuffer); + + // set pipeline + renderPass.setPipeline(this.opaquePipeline); // TODO + + // Draw instanced + profiler.popPush("render"); + if (container.uploadedBoxCount > 0) + { + renderPass.drawIndexed( + /*indexStart*/ 0, + /*firstIndex*/0, + /*indexCount*/BOX_INDICES.length, + /*instanceCount*/container.uploadedBoxCount); + + } + + profiler.pop(); + } + + //endregion + + + + //=========// + // F3 menu // + //=========// + //region + + public String getVboRenderDebugMenuString() + { + // get counts + int totalGroupCount = this.boxGroupById.size(); + int totalBoxCount = 0; + + int activeGroupCount = 0; + int activeBoxCount = 0; + + for (long key : this.boxGroupById.keySet()) + { + RenderableBoxGroup renderGroup = this.boxGroupById.get(key); + if (renderGroup.active) + { + activeGroupCount++; + activeBoxCount += renderGroup.size(); + } + totalBoxCount += renderGroup.size(); + } + + + return "Generic Obj #: " + F3Screen.NUMBER_FORMAT.format(activeGroupCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalGroupCount) + ", " + + "Cube #: " + F3Screen.NUMBER_FORMAT.format(activeBoxCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalBoxCount); + } + + //endregion + + + +} diff --git a/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McInstancedVboContainer.java b/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McInstancedVboContainer.java new file mode 100644 index 000000000..dabe0f385 --- /dev/null +++ b/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McInstancedVboContainer.java @@ -0,0 +1,392 @@ +package com.seibel.distanthorizons.common.renderTest; + +import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import com.mojang.blaze3d.systems.CommandEncoder; +import com.mojang.blaze3d.systems.GpuDevice; +import com.mojang.blaze3d.systems.RenderSystem; +import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox; +import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer; +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.logging.DhLogger; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.render.glObject.GLEnums; +import com.seibel.distanthorizons.core.render.glObject.GLProxy; +import com.seibel.distanthorizons.core.render.glObject.buffer.QuadElementBuffer; +import com.seibel.distanthorizons.core.render.renderer.generic.IInstancedVboContainer; +import com.seibel.distanthorizons.core.render.renderer.generic.RenderableBoxGroup; +import com.seibel.distanthorizons.core.util.ColorUtil; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; +import org.lwjgl.opengl.GL32; +import org.lwjgl.system.MemoryUtil; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.List; +import java.util.function.Supplier; + +/** + * For use by {@link RenderableBoxGroup} + * + * @see RenderableBoxGroup + */ +public class McInstancedVboContainer implements IInstancedVboContainer +{ + private static final DhLogger LOGGER = new DhLoggerBuilder().build(); + + private static final IMinecraftGLWrapper GLMC = SingletonInjector.INSTANCE.get(IMinecraftGLWrapper.class); + private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); + + /** A box from 0,0,0 to 1,1,1 */ + private static final float[] BOX_VERTICES = { + //region + // Pos x y z + + // min X, vertical face + 0, 0, 0, + 1, 0, 0, + 1, 1, 0, + 0, 1, 0, + // max X, vertical face + 0, 1, 1, + 1, 1, 1, + 1, 0, 1, + 0, 0, 1, + + // min Z, vertical face + 0, 0, 1, + 0, 0, 0, + 0, 1, 0, + 0, 1, 1, + // max Z, vertical face + 1, 0, 1, + 1, 1, 1, + 1, 1, 0, + 1, 0, 0, + + // min Y, horizontal face + 0, 0, 1, + 1, 0, 1, + 1, 0, 0, + 0, 0, 0, + // max Y, horizontal face + 0, 1, 1, + 1, 1, 1, + 1, 1, 0, + 0, 1, 0, + //endregion + }; + + private static final int[] BOX_INDICES = { + //region + // min X, vertical face + 2, 1, 0, + 0, 3, 2, + // max X, vertical face + 6, 5, 4, + 4, 7, 6, + + // min Z, vertical face + 10, 9, 8, + 8, 11, 10, + // max Z, vertical face + 14, 13, 12, + 12, 15, 14, + + // min Y, horizontal face + 18, 17, 16, + 16, 19, 18, + // max Y, horizontal face + 20, 21, 22, + 22, 23, 20, + //endregion + }; + + public static final int[][][] DIRECTION_VERTEX_IBO_QUAD = new int[][][] + ///region + { + // X,Z // + { // UP + {1, 0}, // 0 + {1, 1}, // 1 + {0, 1}, // 2 + {0, 0}, // 3 + }, + { // DOWN + {0, 0}, // 0 + {0, 1}, // 1 + {1, 1}, // 2 + {1, 0}, // 3 + }, + + // X,Y // + { // NORTH + {0, 0}, // 0 + {0, 1}, // 1 + {1, 1}, // 2 + + {1, 0}, // 3 + }, + { // SOUTH + {1, 0}, // 0 + {1, 1}, // 1 + {0, 1}, // 2 + + {0, 0}, // 3 + }, + + // Z,Y // + { // WEST + {0, 0}, // 0 + {1, 0}, // 1 + {1, 1}, // 2 + + {0, 1}, // 3 + }, + { // EAST + {0, 1}, // 0 + {1, 1}, // 1 + {1, 0}, // 2 + + {0, 0}, // 3 + }, + }; + ///endregion + + + + + + public GpuBuffer vboGpuBuffer; + public GpuBuffer indexGpuBuffer; + + //public int[] chunkPosData = new int[0]; + //public float[] subChunkPosData = new float[0]; + ////public float[] scalingData = new float[0]; + //public float[] colorData = new float[0]; + //public int[] materialData = new int[0]; + private ByteBuffer vertexBuffer = ByteBuffer.allocateDirect(0); + private ByteBuffer indexBuffer = ByteBuffer.allocateDirect(0); + + public int uploadedBoxCount = 0; + + private EState state = EState.NEW; + @Override + public IInstancedVboContainer.EState getState() { return this.state; } + @Override + public void setState(IInstancedVboContainer.EState state) { this.state = state; } + + + + //===========================// + // render building/uploading // + //===========================// + //region + + public void updateVertexData(List uploadBoxList) + { + int boxCount = uploadBoxList.size(); + if (boxCount == 0) + { + return; // TODO done just to fix a buffer empty crash + } + + + // recreate the data arrays if their size is different + if (this.uploadedBoxCount != boxCount) + { + this.uploadedBoxCount = boxCount; + + int vertexBufferSize = this.vertexBufferSize(); + this.vertexBuffer = ByteBuffer.allocateDirect(vertexBufferSize); + this.vertexBuffer.order(ByteOrder.LITTLE_ENDIAN); + + int indexBufferSize = this.indexBufferSize(); + this.indexBuffer = ByteBuffer.allocateDirect(indexBufferSize); + this.indexBuffer.order(ByteOrder.LITTLE_ENDIAN); + } + this.vertexBuffer.position(0); + this.indexBuffer.position(0); + + + + //QuadElementBuffer.buildBuffer(quadCount, this.indexBuffer, GL32.GL_UNSIGNED_INT); + + + + for (int boxIndex = 0; boxIndex < boxCount; boxIndex++) + { + // index + int indexOffset = (boxIndex * 24 /*24 is the number of vertices in a box*/); + for (int i = 0; i < BOX_INDICES.length; i++) + { + this.indexBuffer.putInt(BOX_INDICES[i] + indexOffset); + } + + + + + // vertex + DhApiRenderableBox box = uploadBoxList.get(boxIndex); + + final double[] boxVertices = { + //region + // Pos x y z + + // min X, vertical face + box.minPos.x, box.minPos.y, box.minPos.z, + box.maxPos.x, box.minPos.y, box.minPos.z, + box.maxPos.x, box.maxPos.y, box.minPos.z, + box.minPos.x, box.maxPos.y, box.minPos.z, + // max X, vertical face + box.minPos.x, box.maxPos.y, box.maxPos.z, + box.maxPos.x, box.maxPos.y, box.maxPos.z, + box.maxPos.x, box.minPos.y, box.maxPos.z, + box.minPos.x, box.minPos.y, box.maxPos.z, + + // min Z, vertical face + box.minPos.x, box.minPos.y, box.maxPos.z, + box.minPos.x, box.minPos.y, box.minPos.z, + box.minPos.x, box.maxPos.y, box.minPos.z, + box.minPos.x, box.maxPos.y, box.maxPos.z, + // max Z, vertical face + box.maxPos.x, box.minPos.y, box.maxPos.z, + box.maxPos.x, box.maxPos.y, box.maxPos.z, + box.maxPos.x, box.maxPos.y, box.minPos.z, + box.maxPos.x, box.minPos.y, box.minPos.z, + + // min Y, horizontal face + box.minPos.x, box.minPos.y, box.maxPos.z, + box.maxPos.x, box.minPos.y, box.maxPos.z, + box.maxPos.x, box.minPos.y, box.minPos.z, + box.minPos.x, box.minPos.y, box.minPos.z, + // max Y, horizontal face + box.minPos.x, box.maxPos.y, box.maxPos.z, + box.maxPos.x, box.maxPos.y, box.maxPos.z, + box.maxPos.x, box.maxPos.y, box.minPos.z, + box.minPos.x, box.maxPos.y, box.minPos.z, + //endregion + }; + + for (int vertexIndex = 0; vertexIndex < boxVertices.length; vertexIndex+=3) + { + this.vertexBuffer.putFloat((float)boxVertices[vertexIndex]); // x + this.vertexBuffer.putFloat((float)boxVertices[vertexIndex+1]); // y + this.vertexBuffer.putFloat((float)boxVertices[vertexIndex+2]); // z + + int color = ColorUtil.toColorInt(box.color); + byte r = (byte) ColorUtil.getRed(color); + byte g = (byte) ColorUtil.getGreen(color); + byte b = (byte) ColorUtil.getBlue(color); + byte a = (byte) ColorUtil.getAlpha(color); + this.vertexBuffer.put(r); + this.vertexBuffer.put(g); + this.vertexBuffer.put(b); + this.vertexBuffer.put(a); + + this.vertexBuffer.put(box.material); + // TODO make sure this all is a multiple of 4 like LodQuadBuilder (might cause issues with AMD/Mac otherwise) + } + } + this.vertexBuffer.flip(); + this.indexBuffer.flip(); + + + this.state = McInstancedVboContainer.EState.READY_TO_UPLOAD; + } + + private int vertexBufferSize() + { + int faceCount = this.uploadedBoxCount * 6; + int vertexCount = faceCount * 6; + + int byteSize = vertexCount * 3 * Float.BYTES; // x,y,z + byteSize += vertexCount * 4; // r,g,b,a + byteSize += 1; // material + return byteSize; + } + private int indexBufferSize() + { + int quadCount = this.uploadedBoxCount * 36; + int byteSize = quadCount * GLEnums.getTypeSize(GL32.GL_UNSIGNED_INT) * 6; + return byteSize; + + //int faceCount = this.uploadedBoxCount * 6; + //int vertexCount = faceCount * 6; + //int byteSize = vertexCount * Integer.BYTES; + //return byteSize; + } + + public void uploadDataToGpu() + { + GpuDevice gpuDevice = RenderSystem.getDevice(); + CommandEncoder commandEncoder = gpuDevice.createCommandEncoder(); + + // vertex + { + int totalVertexByteSize = this.vertexBufferSize(); + if (this.vboGpuBuffer == null + || this.vboGpuBuffer.size() < totalVertexByteSize) + { + Supplier labelSupplier = () -> "distantHorizons:GenericContainerVertex"; + int usage = 8 | 32; // is this just using OpenGL VBO flags?, if so I can't find it, supposedly GlDevice on Mojang's side + this.vboGpuBuffer = gpuDevice.createBuffer(labelSupplier, usage, totalVertexByteSize); + } + + GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vboGpuBuffer, /*offset*/0, totalVertexByteSize); + commandEncoder.writeToBuffer(bufferSlice, this.vertexBuffer); + } + + // index + { + int totalVertexByteSize = this.indexBufferSize(); + if (this.indexGpuBuffer == null + || this.indexGpuBuffer.size() < totalVertexByteSize) + { + Supplier labelSupplier = () -> "distantHorizons:GenericContainerIndex"; + // GpuBuffer.USAGE_UNIFORM = 128 + // GpuBuffer.USAGE_INDEX = 64 + int usage = 8 | 32 | 64 | 128; // is this just using OpenGL VBO flags?, if so I can't find it, supposedly GlDevice on Mojang's side + this.indexGpuBuffer = gpuDevice.createBuffer(labelSupplier, usage, totalVertexByteSize); + } + + int offset = 0; + GpuBufferSlice bufferSlice = new GpuBufferSlice(this.indexGpuBuffer, offset, totalVertexByteSize); + + commandEncoder.writeToBuffer(bufferSlice, this.indexBuffer); + } + + this.state = EState.RENDER; + } + + //endregion + + + + //================// + // base overrides // + //================// + //region + + @Override + public void close() + { + GLProxy.queueRunningOnRenderThread(() -> + { + if (this.vboGpuBuffer != null) + { + this.vboGpuBuffer.close(); + } + if (this.indexGpuBuffer != null) + { + this.indexGpuBuffer.close(); + } + }); + } + + //endregion + + + +} diff --git a/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McInstancedVboContainer_Textures.java b/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McInstancedVboContainer_Textures.java new file mode 100644 index 000000000..a71d47641 --- /dev/null +++ b/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McInstancedVboContainer_Textures.java @@ -0,0 +1,277 @@ +package com.seibel.distanthorizons.common.renderTest; + +import com.mojang.blaze3d.platform.NativeImage; +import com.mojang.blaze3d.systems.CommandEncoder; +import com.mojang.blaze3d.systems.GpuDevice; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.textures.GpuTexture; +import com.mojang.blaze3d.textures.TextureFormat; +import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox; +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.logging.DhLogger; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.render.glObject.GLProxy; +import com.seibel.distanthorizons.core.render.renderer.generic.IInstancedVboContainer; +import com.seibel.distanthorizons.core.render.renderer.generic.RenderableBoxGroup; +import com.seibel.distanthorizons.core.util.LodUtil; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; + +import java.awt.*; +import java.nio.ByteBuffer; +import java.util.List; + + +/** + * For use by {@link RenderableBoxGroup} + * + * @see RenderableBoxGroup + */ +public class McInstancedVboContainer_Textures implements IInstancedVboContainer +{ + private static final DhLogger LOGGER = new DhLoggerBuilder().build(); + + private static final IMinecraftGLWrapper GLMC = SingletonInjector.INSTANCE.get(IMinecraftGLWrapper.class); + private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class); + + + + public GpuTexture colorTexture; + public GpuTexture scaleTexture; + public GpuTexture chunkPosXTexture; + public GpuTexture chunkPosYTexture; + public GpuTexture chunkPosZTexture; + public GpuTexture subChunkPosTexture; + public GpuTexture materialTexture; + + public int[] chunkPosData = new int[0]; + public float[] subChunkPosData = new float[0]; + public float[] scaleData = new float[0]; + public byte[] colorData = new byte[0]; + public int[] materialData = new int[0]; + + public int uploadedBoxCount = 0; + + private EState state = EState.NEW; + @Override + public EState getState() { return this.state; } + @Override + public void setState(EState state) { this.state = state; } + + + + //===========================// + // render building/uploading // + //===========================// + //region + + public void updateVertexData(List uploadBoxList) + { + int boxCount = uploadBoxList.size(); + + + // recreate the data arrays if their size is different + if (this.uploadedBoxCount != boxCount) + { + this.uploadedBoxCount = boxCount; + + this.chunkPosData = new int[boxCount * 3]; // 3 elements XYZ + this.subChunkPosData = new float[boxCount * 3]; // 3 elements XYZ + this.scaleData = new float[boxCount * 3]; // 3 elements XYZ + + this.colorData = new byte[boxCount * 4]; // 4 elements, RGBA + this.materialData = new int[boxCount]; + } + + + // transformation / scaling // + for (int i = 0; i < boxCount; i++) + { + DhApiRenderableBox box = uploadBoxList.get(i); + + int dataIndex = i * 3; + + this.chunkPosData[dataIndex] = LodUtil.getChunkPosFromDouble(box.minPos.x); + this.chunkPosData[dataIndex + 1] = LodUtil.getChunkPosFromDouble(box.minPos.y); + this.chunkPosData[dataIndex + 2] = LodUtil.getChunkPosFromDouble(box.minPos.z); + + this.subChunkPosData[dataIndex] = LodUtil.getSubChunkPosFromDouble(box.minPos.x); + this.subChunkPosData[dataIndex + 1] = LodUtil.getSubChunkPosFromDouble(box.minPos.y); + this.subChunkPosData[dataIndex + 2] = LodUtil.getSubChunkPosFromDouble(box.minPos.z); + + this.scaleData[dataIndex] = (float) (box.maxPos.x - box.minPos.x); + this.scaleData[dataIndex + 1] = (float) (box.maxPos.y - box.minPos.y); + this.scaleData[dataIndex + 2] = (float) (box.maxPos.z - box.minPos.z); + } + + + // colors/materials // + for (int i = 0; i < boxCount; i++) + { + DhApiRenderableBox box = uploadBoxList.get(i); + Color color = box.color; + int colorIndex = i * 4; + this.colorData[colorIndex] = (byte)color.getRed(); + this.colorData[colorIndex + 1] = (byte)color.getGreen(); + this.colorData[colorIndex + 2] = (byte)color.getBlue(); + this.colorData[colorIndex + 3] = (byte)color.getAlpha(); + + this.materialData[i] = box.material; + } + + this.state = EState.READY_TO_UPLOAD; + } + + public void uploadDataToGpu() + { + GpuDevice gpuDevice = RenderSystem.getDevice(); + CommandEncoder commandEncoder = gpuDevice.createCommandEncoder(); + + if (this.colorTexture == null + || this.colorTexture.getWidth(0) < this.uploadedBoxCount) + { + // TODO USAGE_COPY_DST = 1 + // TODO USAGE_TEXTURE_BINDING = 4 + int usage = 1 | 4 | 8 | 32 | 128; + String texturePrefix = "DhGenericTexture_"; + + this.colorTexture = gpuDevice.createTexture(texturePrefix + "Color", + usage, + TextureFormat.RGBA8, + this.uploadedBoxCount, 1, + 1, 1 + ); + + this.scaleTexture = gpuDevice.createTexture(texturePrefix + "Scale", + usage, + TextureFormat.RGBA8, + this.uploadedBoxCount, 1, + 1, 1 + ); + + this.chunkPosXTexture = gpuDevice.createTexture(texturePrefix + "ChunkXPos", + usage, + TextureFormat.DEPTH32, + this.uploadedBoxCount, 1, + 1, 1 + ); + this.chunkPosYTexture = gpuDevice.createTexture(texturePrefix + "ChunkYPos", + usage, + TextureFormat.DEPTH32, + this.uploadedBoxCount, 1, + 1, 1 + ); + this.chunkPosZTexture = gpuDevice.createTexture(texturePrefix + "ChunkZPos", + usage, + TextureFormat.DEPTH32, + this.uploadedBoxCount, 1, + 1, 1 + ); + + this.subChunkPosTexture = gpuDevice.createTexture(texturePrefix + "SubChunk", + usage, + TextureFormat.RGBA8, + this.uploadedBoxCount, 1, + 1, 1 + ); + + //this.materialTexture = gpuDevice.createTexture(texturePrefix + "Material", + // usage, + // TextureFormat.RED8I, // TODO not valid? + // this.uploadedBoxCount, 1, + // 1, 1 + //); + } + + { + // color + { + ByteBuffer colorBuffer = ByteBuffer.allocateDirect(this.colorData.length * Float.BYTES); + colorBuffer.asFloatBuffer(); + + for (int i = 0; i < this.colorData.length; i++) + { + colorBuffer.put(this.colorData[i]); + } + colorBuffer.rewind(); + + commandEncoder.writeToTexture( + this.colorTexture, + colorBuffer, + NativeImage.Format.RGBA, // holds bytes + 0, //mipLevel + 0, // depthOrLayer + 0, // destX + 0, // destY + this.uploadedBoxCount, // width + 1 // height + ); + } + + // scale + { + ByteBuffer scaleBuffer = ByteBuffer.allocateDirect(this.scaleData.length * Float.BYTES); + scaleBuffer.asFloatBuffer(); + + for (int i = 0; i < this.scaleData.length; i++) + { scaleBuffer.putFloat(this.scaleData[i]); } + scaleBuffer.rewind(); + + commandEncoder.writeToTexture( + this.scaleTexture, + scaleBuffer, + NativeImage.Format.RGB, // holds bytes + 0, //mipLevel + 0, // depthOrLayer + 0, // destX + 0, // destY + this.uploadedBoxCount, // width + 1 // height + ); + } + + + //for (int i = 0; i < this.chunkPosData.length; i++) + //{ buffer.putInt(this.chunkPosData[i]); } + // + //for (int i = 0; i < this.subChunkPosData.length; i++) + //{ buffer.putFloat(this.subChunkPosData[i]); } + // + //for (int i = 0; i < this.colorData.length; i++) + //{ buffer.putFloat(this.colorData[i]); } + // + //for (int i = 0; i < this.materialData.length; i++) + //{ buffer.putInt(this.materialData[i]); } + // + //buffer.rewind(); + } + + this.state = EState.RENDER; + } + + //endregion + + + + //================// + // base overrides // + //================// + //region + + @Override + public void close() + { + GLProxy.queueRunningOnRenderThread(() -> + { + if (this.colorTexture != null) + { + this.colorTexture.close(); + } + }); + } + + //endregion + + + +} diff --git a/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McTestRenderer.java b/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McTestRenderer.java index ab6d739f4..295f1e719 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McTestRenderer.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/renderTest/McTestRenderer.java @@ -195,48 +195,11 @@ public class McTestRenderer implements IMcTestRenderer // render pass setup { - // set uniform - if (false) - { - Supplier labelSupplier = () -> ""; - int usage = 0; - int size = 0; - GpuBuffer gpuBuffer = gpuDevice.createBuffer(labelSupplier, usage, size); - - renderPass.setUniform("name", gpuBuffer); - } - - // bind depth texture - if (false) - { - GpuTexture bindDepthTexture = Minecraft.getInstance().getMainRenderTarget().getDepthTexture(); - - GpuTextureView textureView = gpuDevice.createTextureView(bindDepthTexture); - GpuSampler gpuSampler = gpuDevice.createSampler( - AddressMode.CLAMP_TO_EDGE, AddressMode.CLAMP_TO_EDGE, // U,V - FilterMode.NEAREST, FilterMode.NEAREST, // minFilter, magFilter - 0, // maxAnisotropy - OptionalDouble.empty() // maxLod - ); - renderPass.bindTexture("depth", textureView, gpuSampler); - } - - // index buffer - if (false) - { - GpuBuffer buffer = null; - renderPass.setIndexBuffer(buffer, VertexFormat.IndexType.INT); - } - // bind VBO - { - renderPass.setVertexBuffer(0, vboGpuBuffer); // vertex buffer can only be "0" lol - } + renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol // set pipeline - { - renderPass.setPipeline(this.pipeline); - } + renderPass.setPipeline(this.pipeline); } // draw render pass diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java index 6b10976d2..9ec50b096 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java @@ -24,6 +24,8 @@ import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper; import com.seibel.distanthorizons.api.interfaces.override.worldGenerator.IDhApiWorldGenerator; import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper; import com.seibel.distanthorizons.api.interfaces.factories.IDhApiWrapperFactory; +import com.seibel.distanthorizons.common.renderTest.McGenericObjectRenderer; +import com.seibel.distanthorizons.common.renderTest.McInstancedVboContainer; import com.seibel.distanthorizons.common.renderTest.VertexBufferWrapper; import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper; import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper; @@ -33,10 +35,12 @@ import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; import com.seibel.distanthorizons.core.level.IDhLevel; import com.seibel.distanthorizons.core.level.IDhServerLevel; +import com.seibel.distanthorizons.core.render.renderer.generic.IInstancedVboContainer; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory; import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.render.IMcGenericRenderer; import com.seibel.distanthorizons.core.wrapperInterfaces.render.IVertexBufferWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; @@ -358,9 +362,24 @@ public class WrapperFactory implements IWrapperFactory } + @Override public IVertexBufferWrapper createVboWrapper() { return new VertexBufferWrapper(); } + @Override + public IInstancedVboContainer createInstancedVboContainer() + { + return new McInstancedVboContainer(); + } + + @Override + public IMcGenericRenderer createGenericRenderer() + { + return new McGenericObjectRenderer(); + } + + + } diff --git a/coreSubProjects b/coreSubProjects index 200e089a3..3d9ae5f08 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 200e089a3336ea61c4012f762c6e19d6c5c6c1bb +Subproject commit 3d9ae5f088d24387152bf336e752d041d5a5fb8d