package net.vulkanmod.vulkan.pass;

import net.minecraft.class_1937;
import net.minecraft.class_243;
import net.minecraft.class_310;
import net.minecraft.class_4184;
import net.vulkanmod.vulkan.Renderer;
import net.vulkanmod.vulkan.VRenderSystem;
import net.vulkanmod.vulkan.framebuffer.Framebuffer;
import net.vulkanmod.vulkan.framebuffer.RenderPass;
import net.vulkanmod.vulkan.texture.VulkanImage;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.VK10;
import org.lwjgl.vulkan.VkCommandBuffer;
import org.lwjgl.vulkan.VkViewport;

public class ShadowPass {
   public static final int SHADOW_MAP_SIZE = 4096;
   private Framebuffer shadowFramebuffer;
   private RenderPass shadowRenderPass;

   public static ShadowPass create() {
      return new ShadowPass();
   }

   ShadowPass() {
      this.createResources();
   }

   private void createResources() {
      this.shadowFramebuffer = Framebuffer.builder(4096, 4096, 0, true).setDepthFormat(126).build();
      RenderPass.Builder builder = RenderPass.builder(this.shadowFramebuffer);
      builder.getDepthAttachmentInfo().setOps(1, 0).setFinalLayout(4);
      this.shadowRenderPass = builder.build();
   }

   private void update() {
      class_310 mc = class_310.method_1551();
      class_1937 level = mc.field_1687;
      long lastTick = -1L;
      if (level != null && level.method_8510() != lastTick) {
         lastTick = level.method_8510();
         class_4184 camera = mc.field_1773.method_19418();
         class_243 camPos = camera.method_19326();
         float timeOfDay = (float)(level.method_8532() % 24000L) / 24000.0F;
         float sunAngle = timeOfDay * 2.0F * (float)Math.PI;
         float sunDirX = (float)Math.cos((double)sunAngle);
         float sunDirY = (float)Math.sin((double)sunAngle);
         float sunDirZ = 0.0F;
         VRenderSystem.setShaderLightDir(0, sunDirX, sunDirY, sunDirZ);
         VRenderSystem.setShaderLightDir(1, 0.0F, 0.0F, 0.0F);
         float shadowDistance = 256.0F;
         float range = 256.0F;
         double centerX = Math.floor(camPos.field_1352);
         double centerY = Math.floor(camPos.field_1351);
         double centerZ = Math.floor(camPos.field_1350);
         float lightX = (float)centerX + sunDirX * shadowDistance;
         float lightY = (float)centerY + sunDirY * shadowDistance;
         float lightZ = (float)centerZ + sunDirZ * shadowDistance;
         Vector3f up = Math.abs(sunDirY) > 0.99F ? new Vector3f(0.0F, 0.0F, 1.0F) : new Vector3f(0.0F, 1.0F, 0.0F);
         Matrix4f lightView = (new Matrix4f()).lookAt(lightX, lightY, lightZ, (float)centerX, (float)centerY, (float)centerZ, up.x, up.y, up.z);
         Matrix4f lightProj = (new Matrix4f()).ortho(-range, range, -range, range, 0.5F, shadowDistance * 2.0F, true);
         Matrix4f worldLightVP = (new Matrix4f(lightProj)).mul(lightView);
         Matrix4f lightSpaceMat = worldLightVP.translate((float)camPos.field_1352, (float)camPos.field_1351, (float)camPos.field_1350);
         lightSpaceMat.get(VRenderSystem.lightSpaceMatrix.buffer.asFloatBuffer());
         VRenderSystem.recomputeLightSpaceViewMatrix();
      }
   }

   public void begin(VkCommandBuffer commandBuffer, MemoryStack stack) {
      this.update();
      Renderer.getInstance().beginRenderPass(this.shadowRenderPass, this.shadowFramebuffer);
      VkViewport.Buffer viewport = VkViewport.malloc(1, stack);
      viewport.x(0.0F).y(0.0F).width(4096.0F).height(4096.0F).minDepth(0.0F).maxDepth(1.0F);
      VK10.vkCmdSetViewport(commandBuffer, 0, viewport);
      VK10.vkCmdSetDepthBias(commandBuffer, 0.0F, 0.0F, 0.0F);
   }

   public void end(VkCommandBuffer commandBuffer) {
      Renderer.getInstance().endRenderPass(commandBuffer);
   }

   public VulkanImage getShadowMap() {
      return this.shadowFramebuffer.getDepthAttachment();
   }

   public void onResize() {
   }

   public void cleanUp() {
      this.shadowRenderPass.cleanUp();
      this.shadowFramebuffer.cleanUp();
   }
}
