package com.mojang.blaze3d.pipeline; import com.google.common.collect.ImmutableList; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.TextureUtil; import com.mojang.blaze3d.systems.RenderSystem; import java.util.List; import java.util.Objects; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @Environment(EnvType.CLIENT) public class MainTarget extends RenderTarget { public static final int DEFAULT_WIDTH = 854; public static final int DEFAULT_HEIGHT = 480; static final MainTarget.Dimension DEFAULT_DIMENSIONS = new MainTarget.Dimension(854, 480); public MainTarget(int width, int height) { super(true); this.createFrameBuffer(width, height); } private void createFrameBuffer(int width, int height) { MainTarget.Dimension dimension = this.allocateAttachments(width, height); this.frameBufferId = GlStateManager.glGenFramebuffers(); GlStateManager._glBindFramebuffer(36160, this.frameBufferId); GlStateManager._bindTexture(this.colorTextureId); GlStateManager._texParameter(3553, 10241, 9728); GlStateManager._texParameter(3553, 10240, 9728); GlStateManager._texParameter(3553, 10242, 33071); GlStateManager._texParameter(3553, 10243, 33071); GlStateManager._glFramebufferTexture2D(36160, 36064, 3553, this.colorTextureId, 0); GlStateManager._bindTexture(this.depthBufferId); GlStateManager._texParameter(3553, 34892, 0); GlStateManager._texParameter(3553, 10241, 9728); GlStateManager._texParameter(3553, 10240, 9728); GlStateManager._texParameter(3553, 10242, 33071); GlStateManager._texParameter(3553, 10243, 33071); GlStateManager._glFramebufferTexture2D(36160, 36096, 3553, this.depthBufferId, 0); GlStateManager._bindTexture(0); this.viewWidth = dimension.width; this.viewHeight = dimension.height; this.width = dimension.width; this.height = dimension.height; this.checkStatus(); GlStateManager._glBindFramebuffer(36160, 0); } private MainTarget.Dimension allocateAttachments(int width, int height) { RenderSystem.assertOnRenderThreadOrInit(); this.colorTextureId = TextureUtil.generateTextureId(); this.depthBufferId = TextureUtil.generateTextureId(); MainTarget.AttachmentState attachmentState = MainTarget.AttachmentState.NONE; for (MainTarget.Dimension dimension : MainTarget.Dimension.listWithFallback(width, height)) { attachmentState = MainTarget.AttachmentState.NONE; if (this.allocateColorAttachment(dimension)) { attachmentState = attachmentState.with(MainTarget.AttachmentState.COLOR); } if (this.allocateDepthAttachment(dimension)) { attachmentState = attachmentState.with(MainTarget.AttachmentState.DEPTH); } if (attachmentState == MainTarget.AttachmentState.COLOR_DEPTH) { return dimension; } } throw new RuntimeException("Unrecoverable GL_OUT_OF_MEMORY (allocated attachments = " + attachmentState.name() + ")"); } private boolean allocateColorAttachment(MainTarget.Dimension dimension) { RenderSystem.assertOnRenderThreadOrInit(); GlStateManager._getError(); GlStateManager._bindTexture(this.colorTextureId); GlStateManager._texImage2D(3553, 0, 32856, dimension.width, dimension.height, 0, 6408, 5121, null); return GlStateManager._getError() != 1285; } private boolean allocateDepthAttachment(MainTarget.Dimension dimension) { RenderSystem.assertOnRenderThreadOrInit(); GlStateManager._getError(); GlStateManager._bindTexture(this.depthBufferId); GlStateManager._texImage2D(3553, 0, 6402, dimension.width, dimension.height, 0, 6402, 5126, null); return GlStateManager._getError() != 1285; } @Environment(EnvType.CLIENT) static enum AttachmentState { NONE, COLOR, DEPTH, COLOR_DEPTH; private static final MainTarget.AttachmentState[] VALUES = values(); MainTarget.AttachmentState with(MainTarget.AttachmentState otherState) { return VALUES[this.ordinal() | otherState.ordinal()]; } } @Environment(EnvType.CLIENT) static class Dimension { public final int width; public final int height; Dimension(int width, int height) { this.width = width; this.height = height; } static List listWithFallback(int width, int height) { RenderSystem.assertOnRenderThreadOrInit(); int i = RenderSystem.maxSupportedTextureSize(); return width > 0 && width <= i && height > 0 && height <= i ? ImmutableList.of(new MainTarget.Dimension(width, height), MainTarget.DEFAULT_DIMENSIONS) : ImmutableList.of(MainTarget.DEFAULT_DIMENSIONS); } public boolean equals(Object object) { if (this == object) { return true; } else if (object != null && this.getClass() == object.getClass()) { MainTarget.Dimension dimension = (MainTarget.Dimension)object; return this.width == dimension.width && this.height == dimension.height; } else { return false; } } public int hashCode() { return Objects.hash(new Object[]{this.width, this.height}); } public String toString() { return this.width + "x" + this.height; } } }