package net.vulkanmod.render.engine;

import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.textures.GpuTextureView;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.mojang.blaze3d.vertex.VertexFormat.class_5595;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Supplier;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.class_11219;
import net.minecraft.class_155;
import net.vulkanmod.interfaces.shader.ExtendedRenderPipeline;
import org.jetbrains.annotations.Nullable;

@Environment(EnvType.CLIENT)
public class VkRenderPass implements RenderPass {
   protected static final int MAX_VERTEX_BUFFERS = 1;
   public static final boolean VALIDATION;
   private final VkCommandEncoder encoder;
   private final boolean hasDepthTexture;
   private boolean closed;
   protected @Nullable RenderPipeline pipeline;
   protected final GpuBuffer[] vertexBuffers = new GpuBuffer[1];
   protected @Nullable GpuBuffer indexBuffer;
   protected VertexFormat.class_5595 indexType;
   private final class_11219 scissorState;
   protected final HashMap<String, GpuBufferSlice> uniforms;
   protected final HashMap<String, GpuTextureView> samplers;
   protected final Set<String> dirtyUniforms;
   protected int pushedDebugGroups;

   public VkRenderPass(VkCommandEncoder commandEncoder, boolean bl) {
      this.indexType = class_5595.field_27373;
      this.scissorState = new class_11219();
      this.uniforms = new HashMap();
      this.samplers = new HashMap();
      this.dirtyUniforms = new HashSet();
      this.encoder = commandEncoder;
      this.hasDepthTexture = bl;
   }

   public boolean hasDepthTexture() {
      return this.hasDepthTexture;
   }

   public void pushDebugGroup(Supplier<String> supplier) {
      if (this.closed) {
         throw new IllegalStateException("Can't use a closed render pass");
      } else {
         ++this.pushedDebugGroups;
      }
   }

   public void popDebugGroup() {
      if (this.closed) {
         throw new IllegalStateException("Can't use a closed render pass");
      } else if (this.pushedDebugGroups == 0) {
         throw new IllegalStateException("Can't pop more debug groups than was pushed!");
      } else {
         --this.pushedDebugGroups;
      }
   }

   public void setPipeline(RenderPipeline renderPipeline) {
      if (this.pipeline == null || this.pipeline != renderPipeline) {
         this.dirtyUniforms.addAll(this.uniforms.keySet());
      }

      this.pipeline = renderPipeline;
      if (ExtendedRenderPipeline.of(renderPipeline).getPipeline() == null) {
         this.encoder.getDevice().compilePipeline(renderPipeline);
      }

   }

   public void bindSampler(String string, @Nullable GpuTextureView gpuTextureView) {
      if (gpuTextureView == null) {
         this.samplers.remove(string);
      } else {
         this.samplers.put(string, gpuTextureView);
      }

      this.dirtyUniforms.add(string);
   }

   public void setUniform(String string, GpuBuffer gpuBuffer) {
      this.uniforms.put(string, gpuBuffer.slice());
      this.dirtyUniforms.add(string);
   }

   public void setUniform(String string, GpuBufferSlice gpuBufferSlice) {
      int i = this.encoder.getDevice().getUniformOffsetAlignment();
      if (gpuBufferSlice.offset() % i > 0) {
         throw new IllegalArgumentException("Uniform buffer offset must be aligned to " + i);
      } else {
         this.uniforms.put(string, gpuBufferSlice);
         this.dirtyUniforms.add(string);
      }
   }

   public void enableScissor(int i, int j, int k, int l) {
      this.scissorState.method_70814(i, j, k, l);
   }

   public void disableScissor() {
      this.scissorState.method_70813();
   }

   public boolean isScissorEnabled() {
      return this.scissorState.method_72091();
   }

   public int getScissorX() {
      return this.scissorState.method_72092();
   }

   public int getScissorY() {
      return this.scissorState.method_72093();
   }

   public int getScissorWidth() {
      return this.scissorState.method_72094();
   }

   public int getScissorHeight() {
      return this.scissorState.method_72095();
   }

   public class_11219 getScissorState() {
      return this.scissorState;
   }

   public void setVertexBuffer(int i, GpuBuffer gpuBuffer) {
      if (i >= 0 && i < 1) {
         this.vertexBuffers[i] = gpuBuffer;
      } else {
         throw new IllegalArgumentException("Vertex buffer slot is out of range: " + i);
      }
   }

   public void setIndexBuffer(@Nullable GpuBuffer gpuBuffer, VertexFormat.class_5595 indexType) {
      this.indexBuffer = gpuBuffer;
      this.indexType = indexType;
   }

   public void drawIndexed(int i, int j, int k, int l) {
      if (this.closed) {
         throw new IllegalStateException("Can't use a closed render pass");
      } else {
         this.encoder.executeDraw(this, i, j, k, this.indexType, l);
      }
   }

   public <T> void drawMultipleIndexed(Collection<RenderPass.class_10884<T>> collection, @Nullable GpuBuffer gpuBuffer, VertexFormat.@Nullable class_5595 indexType, Collection<String> collection2, T object) {
      if (this.closed) {
         throw new IllegalStateException("Can't use a closed render pass");
      } else {
         this.encoder.executeDrawMultiple(this, collection, gpuBuffer, indexType, collection2, object);
      }
   }

   public void draw(int i, int j) {
      if (this.closed) {
         throw new IllegalStateException("Can't use a closed render pass");
      } else {
         this.encoder.executeDraw(this, i, 0, j, (VertexFormat.class_5595)null, 1);
      }
   }

   public void close() {
      if (!this.closed) {
         if (this.pushedDebugGroups > 0) {
            throw new IllegalStateException("Render pass had debug groups left open!");
         }

         this.closed = true;
         this.encoder.finishRenderPass();
      }

   }

   public @Nullable RenderPipeline getPipeline() {
      return this.pipeline;
   }

   static {
      VALIDATION = class_155.field_1125;
   }
}
