Skip to content

Commit

Permalink
Use a buffered model for rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
tr7zw committed Jul 23, 2022
1 parent 40b20de commit 5e25a75
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 50 deletions.
Expand Up @@ -3,12 +3,15 @@
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.At.Shift;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import com.mojang.blaze3d.pipeline.RenderTarget;

import dev.tr7zw.fastergui.FasterGuiModBase;
import net.minecraft.client.Minecraft;
import net.minecraft.client.main.GameConfig;

/**
* While rendering the hud/screen, other mods might also use custom render
Expand All @@ -29,5 +32,10 @@ public void getMainRenderTarget(CallbackInfoReturnable<RenderTarget> ci) {
ci.cancel();
}
}

// @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;allowsMultiplayer()Z", shift = Shift.BEFORE), method = "Lnet/minecraft/client/Minecraft;<init>(Lnet/minecraft/client/main/GameConfig;)V")
// private void init(GameConfig config, CallbackInfo info) {
// System.loadLibrary("renderdoc");
// }

}
40 changes: 28 additions & 12 deletions Shared/src/main/java/dev/tr7zw/fastergui/util/BufferRenderer.java
Expand Up @@ -6,18 +6,17 @@
import com.mojang.blaze3d.pipeline.TextureTarget;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.mojang.math.Vector3f;

import dev.tr7zw.fastergui.FasterGuiModBase;
import dev.tr7zw.fastergui.util.Model.Vector2f;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GameRenderer;

public class BufferRenderer {

private static final Minecraft minecraft = Minecraft.getInstance();
private static Model model = null;
private RenderTarget guiTarget = new TextureTarget(100, 100, true, false);
private long nextFrame = System.currentTimeMillis();
private boolean isRendering = false;
Expand All @@ -31,15 +30,39 @@ public BufferRenderer(boolean forceBlending) {
this.forceBlending = forceBlending;
}

private static void refreshModel(int screenWidth, int screenHeight){
if(model != null) {
model.close();
}

Vector3f[] modelData = new Vector3f[]{
new Vector3f(0.0f, screenHeight, -90.0f),
new Vector3f(screenWidth, screenHeight, -90.0F),
new Vector3f(screenWidth, 0.0F, -90.0F),
new Vector3f(0.0F, 0.0F, -90.0F),
};
Vector2f[] uvData = new Vector2f[]{
new Vector2f(0.0f, 0.0f),
new Vector2f(1.0f, 0.0f),
new Vector2f(1.0f, 1.0f),
new Vector2f(0.0f, 1.0f),
};
model = new Model(modelData, uvData);
}

public void render(CallbackInfo ci) {
int screenWidth = minecraft.getWindow().getGuiScaledWidth();
int screenHeight = minecraft.getWindow().getGuiScaledHeight();
boolean forceRender = false;
if (guiTarget.width != minecraft.getWindow().getWidth()
|| guiTarget.height != minecraft.getWindow().getHeight()) {
guiTarget.resize(minecraft.getWindow().getWidth(), minecraft.getWindow().getHeight(), true);
refreshModel(screenWidth, screenHeight);
forceRender = true;
}
if(model == null) {
refreshModel(screenWidth, screenHeight);
}
if (!forceRender && System.currentTimeMillis() < nextFrame) {
renderTextureOverlay(guiTarget.getColorTextureId(), screenWidth, screenHeight);
ci.cancel();
Expand Down Expand Up @@ -82,14 +105,7 @@ private void renderTextureOverlay(int textureid, int screenWidth, int screenHeig
RenderSystem.setShader(GameRenderer::getPositionTexShader);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
RenderSystem.setShaderTexture(0, textureid);
Tesselator tesselator = Tesselator.getInstance();
BufferBuilder bufferbuilder = tesselator.getBuilder();
bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX);
bufferbuilder.vertex(0.0D, screenHeight, -90.0D).uv(0.0F, 0.0F).endVertex(); // 1
bufferbuilder.vertex(screenWidth, screenHeight, -90.0D).uv(1.0F, 0.0F).endVertex(); // 2
bufferbuilder.vertex(screenWidth, 0.0D, -90.0D).uv(1.0F, 1.0F).endVertex(); // 3
bufferbuilder.vertex(0.0D, 0.0D, -90.0D).uv(0.0F, 1.0F).endVertex(); // 4
tesselator.end();
model.draw(RenderSystem.getModelViewMatrix());
RenderSystem.depthMask(true);
RenderSystem.enableDepthTest();
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
Expand Down
53 changes: 53 additions & 0 deletions Shared/src/main/java/dev/tr7zw/fastergui/util/Model.java
@@ -0,0 +1,53 @@
package dev.tr7zw.fastergui.util;

import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.VertexBuffer;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.mojang.math.Matrix4f;
import com.mojang.math.Vector3f;

import net.minecraft.client.renderer.ShaderInstance;

public class Model {
VertexBuffer toDraw;
int vertexCount;
public Model(Vector3f[] modelData, Vector2f[] uvData){

BufferBuilder bufferbuilder = new BufferBuilder(modelData.length);

bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX);
for(int i = 0; i < modelData.length; i++){
Vector3f pos = modelData[i];
Vector2f uv = uvData[i];
bufferbuilder.vertex(pos.x(), pos.y(), pos.z()).uv(uv.x(), uv.y()).endVertex();
}
toDraw = new VertexBuffer();
upload(bufferbuilder.end());
}
public void drawWithShader(Matrix4f matrix4f, Matrix4f matrix4f2, ShaderInstance shaderInstance) {
toDraw.bind();
toDraw.drawWithShader(matrix4f,matrix4f2,shaderInstance);
}
public void draw(Matrix4f matrix4f) {
drawWithShader(matrix4f, RenderSystem.getProjectionMatrix(), RenderSystem.getShader());
}

private void upload(BufferBuilder.RenderedBuffer renderedBuffer) {
RenderSystem.assertOnRenderThread();
if (renderedBuffer.isEmpty()) {
renderedBuffer.release();
} else {
toDraw.bind();
toDraw.upload(renderedBuffer);
}
}

public void close() {
toDraw.close();
}

public record Vector2f(float x, float y) {}

}
Expand Up @@ -6,15 +6,13 @@
import com.mojang.blaze3d.pipeline.TextureTarget;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.mojang.math.Matrix3f;
import com.mojang.math.Matrix4f;
import com.mojang.math.Vector3f;

import dev.tr7zw.fastergui.FasterGuiModBase;
import dev.tr7zw.fastergui.util.Model.Vector2f;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.renderer.GameRenderer;
Expand All @@ -28,11 +26,31 @@ public class NametagBufferRenderer {
private static final Minecraft minecraft = Minecraft.getInstance();
private RenderTarget renderTargetHidden;
private RenderTarget renderTargetVisible;
private Model model;
private int textwidth = 0;

public NametagBufferRenderer() {

private void initializeModel() {
if(model != null) {
model.close();
}
float height = (int)FasterGuiModBase.nametagSettings.renderHeight;

Vector3f[] modelData = new Vector3f[]{
new Vector3f(0.0f, height, 0.01F),
new Vector3f(textwidth, height, 0.01F),
new Vector3f(textwidth, 0.0f, 0.01F),
new Vector3f(0.0f, 0.0f, 0.01F),
};
Vector2f[] uvData = new Vector2f[]{
new Vector2f(0.0f, 0.0f),
new Vector2f(1.0f, 0.0f),
new Vector2f(1.0f, 1.0f),
new Vector2f(0.0f, 1.0f),
};
model = new Model(modelData, uvData);
cleaner.register(this, new ModelCleaner(model));
}


public void refreshImage(Component text, MultiBufferSource arg3, int light) {
textwidth = minecraft.font.width(text);
Expand All @@ -51,10 +69,12 @@ public void refreshImage(Component text, MultiBufferSource arg3, int light) {
if(renderTargetHidden == null) {
renderTargetHidden = setupTexture(width, height);
renderTargetVisible = setupTexture(width, height);
initializeModel();
}
if(renderTargetHidden.width != width || renderTargetHidden.height != height) {
renderTargetHidden.resize(width, height, false);
renderTargetVisible.resize(width, height, false);
initializeModel();
}

renderTargetHidden.clear(false);
Expand All @@ -68,7 +88,7 @@ private RenderTarget setupTexture(int width, int height) {
RenderTarget target = new TextureTarget(width, height, false, false);
target.setClearColor(0, 0, 0, 0);
target.clear(false);
cleaner.register(this, new State(target));
cleaner.register(this, new RenderTargetCleaner(target));
return target;
}

Expand All @@ -78,7 +98,6 @@ public void render(PoseStack poseStack, int light, boolean hidden, boolean depth
poseStack.pushPose();
poseStack.translate(-textwidth/2f, 0, 0);
RenderSystem.enableBlend();
// RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
FasterGuiModBase.correctBlendMode();
RenderSystem.setShader(GameRenderer::getPositionTexShader);
if(depthTest) {
Expand All @@ -88,17 +107,7 @@ public void render(PoseStack poseStack, int light, boolean hidden, boolean depth
}
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
RenderSystem.setShaderTexture(0, renderTarget.getColorTextureId());
Tesselator tesselator = RenderSystem.renderThreadTesselator();
BufferBuilder bufferbuilder = tesselator.getBuilder();
float height = (int)FasterGuiModBase.nametagSettings.renderHeight;
float width = textwidth;
Matrix4f pose = poseStack.last().pose();
bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX);
bufferbuilder.vertex(pose, 0.0f, height, 0.01F).uv(0.0F, 0.0F).uv2(light).endVertex(); // 1
bufferbuilder.vertex(pose, width, height, 0.01F).uv(1.0F, 0.0F).uv2(light).endVertex(); // 2
bufferbuilder.vertex(pose, width, 0.0f, 0.01F).uv(1.0F, 1.0F).uv2(light).endVertex(); // 3
bufferbuilder.vertex(pose, 0.0f, 0.0f, 0.01F).uv(0.0F, 1.0F).uv2(light).endVertex(); // 4
tesselator.end();
model.draw(poseStack.last().pose());
poseStack.popPose();
FasterGuiModBase.correctBlendMode();
RenderSystem.enableDepthTest();
Expand Down Expand Up @@ -136,12 +145,12 @@ private void renderNametagToBuffer(RenderTarget renderTarget, Component text, Mu
RenderSystem.enableCull();
}

static class State implements Runnable {
static class RenderTargetCleaner implements Runnable {

private RenderTarget cleanableRenderTarget;

State(RenderTarget guiTarget) {
this.cleanableRenderTarget = guiTarget;
RenderTargetCleaner(RenderTarget renderTarget) {
this.cleanableRenderTarget = renderTarget;
}

public void run() {
Expand All @@ -151,4 +160,19 @@ public void run() {
}
}

static class ModelCleaner implements Runnable {

private Model cleanableModel;

ModelCleaner(Model model) {
this.cleanableModel = model;
}

public void run() {
RenderSystem.recordRenderCall(() -> {
cleanableModel.close();
});
}
}

}
Expand Up @@ -2,21 +2,18 @@

import java.lang.ref.Cleaner;
import java.util.List;

import com.mojang.blaze3d.pipeline.RenderTarget;
import com.mojang.blaze3d.pipeline.TextureTarget;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.mojang.math.Matrix3f;
import com.mojang.math.Matrix4f;
import com.mojang.math.Vector3f;

import dev.tr7zw.fastergui.FasterGuiModBase;
import dev.tr7zw.fastergui.util.Model.Vector2f;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.MultiBufferSource;
Expand All @@ -29,15 +26,17 @@ public class SignBufferRenderer {

private static final Cleaner cleaner = Cleaner.create();
private static final Minecraft minecraft = Minecraft.getInstance();
private static Model model = null;
private RenderTarget guiTarget;

public SignBufferRenderer(SignBlockEntity arg, MultiBufferSource arg3, int light) {
arg3.getBuffer(RenderType.endGateway()); // force clear the vertex consumer
guiTarget = new TextureTarget((int)FasterGuiModBase.signSettings.bufferWidth, (int)FasterGuiModBase.signSettings.bufferHeight, false, false);
// guiTarget.resize((int)FasterGuiModBase.signSettings.bufferWidth, (int)FasterGuiModBase.signSettings.bufferHeight, false);
guiTarget.setClearColor(0, 0, 0, 0);
guiTarget.clear(false);
cleaner.register(this, new State(guiTarget));
if(model == null)
initializeModel();
}

public void refreshImage(SignBlockEntity arg, MultiBufferSource arg3, int light) {
Expand All @@ -46,6 +45,25 @@ public void refreshImage(SignBlockEntity arg, MultiBufferSource arg3, int light)
renderSignToBuffer(arg, arg3, light);
}

private static void initializeModel(){
float height = (int)FasterGuiModBase.signSettings.renderHeight;
float width = (int)FasterGuiModBase.signSettings.renderWidth;

Vector3f[] modelData = new Vector3f[]{
new Vector3f(0.0f, height, 0.01F),
new Vector3f(width, height, 0.01F),
new Vector3f(width, 0.0f, 0.01F),
new Vector3f(0.0f, 0.0f, 0.01F),
};
Vector2f[] uvData = new Vector2f[]{
new Vector2f(0.0f, 0.0f),
new Vector2f(1.0f, 0.0f),
new Vector2f(1.0f, 1.0f),
new Vector2f(0.0f, 1.0f),
};
model = new Model(modelData, uvData);
}

public void render(PoseStack poseStack, int light) {
poseStack.pushPose();
poseStack.translate(FasterGuiModBase.signSettings.offsetX , FasterGuiModBase.signSettings.offsetY, 0);
Expand All @@ -56,17 +74,11 @@ public void render(PoseStack poseStack, int light) {
RenderSystem.setShader(GameRenderer::getPositionTexShader);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
RenderSystem.setShaderTexture(0, guiTarget.getColorTextureId());
Tesselator tesselator = RenderSystem.renderThreadTesselator();
BufferBuilder bufferbuilder = tesselator.getBuilder();
float height = (int)FasterGuiModBase.signSettings.renderHeight;
float width = (int)FasterGuiModBase.signSettings.renderWidth;

Matrix4f pose = poseStack.last().pose();
bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX);
bufferbuilder.vertex(pose, 0.0f, height, 0.01F).uv(0.0F, 0.0F).uv2(light).endVertex(); // 1
bufferbuilder.vertex(pose, width, height, 0.01F).uv(1.0F, 0.0F).uv2(light).endVertex(); // 2
bufferbuilder.vertex(pose, width, 0.0f, 0.01F).uv(1.0F, 1.0F).uv2(light).endVertex(); // 3
bufferbuilder.vertex(pose, 0.0f, 0.0f, 0.01F).uv(0.0F, 1.0F).uv2(light).endVertex(); // 4
tesselator.end();

model.draw(pose); // TODO: is light required here, since it's baked into the texture?

poseStack.popPose();
}

Expand Down

0 comments on commit 5e25a75

Please sign in to comment.