package net.vulkanmod.render.chunk;

import com.google.common.collect.Sets;
import com.mojang.blaze3d.opengl.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat.class_5596;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import net.minecraft.class_10017;
import net.minecraft.class_10209;
import net.minecraft.class_10214;
import net.minecraft.class_1044;
import net.minecraft.class_10444;
import net.minecraft.class_1058;
import net.minecraft.class_1059;
import net.minecraft.class_1060;
import net.minecraft.class_1087;
import net.minecraft.class_10933;
import net.minecraft.class_11658;
import net.minecraft.class_11659;
import net.minecraft.class_11661;
import net.minecraft.class_11683;
import net.minecraft.class_11684;
import net.minecraft.class_11785;
import net.minecraft.class_11791;
import net.minecraft.class_11954;
import net.minecraft.class_12075;
import net.minecraft.class_1297;
import net.minecraft.class_1921;
import net.minecraft.class_2338;
import net.minecraft.class_243;
import net.minecraft.class_2561;
import net.minecraft.class_2586;
import net.minecraft.class_2680;
import net.minecraft.class_290;
import net.minecraft.class_310;
import net.minecraft.class_3191;
import net.minecraft.class_327;
import net.minecraft.class_3532;
import net.minecraft.class_3695;
import net.minecraft.class_3879;
import net.minecraft.class_4076;
import net.minecraft.class_4184;
import net.minecraft.class_4587;
import net.minecraft.class_4588;
import net.minecraft.class_4599;
import net.minecraft.class_4604;
import net.minecraft.class_5481;
import net.minecraft.class_630;
import net.minecraft.class_638;
import net.minecraft.class_777;
import net.minecraft.class_811;
import net.minecraft.class_824;
import net.minecraft.class_898;
import net.vulkanmod.Initializer;
import net.vulkanmod.render.PipelineManager;
import net.vulkanmod.render.chunk.buffer.DrawBuffers;
import net.vulkanmod.render.chunk.build.RenderRegionBuilder;
import net.vulkanmod.render.chunk.build.task.ChunkTask;
import net.vulkanmod.render.chunk.build.task.TaskDispatcher;
import net.vulkanmod.render.chunk.graph.SectionGraph;
import net.vulkanmod.render.chunk.util.StaticQueue;
import net.vulkanmod.render.profiling.BuildTimeProfiler;
import net.vulkanmod.render.profiling.Profiler;
import net.vulkanmod.render.vertex.TerrainRenderType;
import net.vulkanmod.vulkan.Drawer;
import net.vulkanmod.vulkan.Renderer;
import net.vulkanmod.vulkan.VRenderSystem;
import net.vulkanmod.vulkan.memory.MemoryTypes;
import net.vulkanmod.vulkan.memory.buffer.Buffer;
import net.vulkanmod.vulkan.memory.buffer.IndexBuffer;
import net.vulkanmod.vulkan.memory.buffer.IndirectBuffer;
import net.vulkanmod.vulkan.shader.GraphicsPipeline;
import net.vulkanmod.vulkan.texture.VTextureSelector;
import net.vulkanmod.vulkan.texture.VulkanImage;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
import org.joml.Quaternionf;
import org.lwjgl.system.MemoryUtil;

public class WorldRenderer {
   private static WorldRenderer INSTANCE;
   private static final int TERRAIN_SUN_SHADOW_BUCKETS = 1024;
   private static float terrainSunDirX = 0.0F;
   private static float terrainSunDirY = 1.0F;
   private static float terrainSunDirZ = 0.0F;
   private static int terrainSunShadowBucket = -1;
   private final class_310 minecraft = class_310.method_1551();
   private class_638 level;
   private int renderDistance;
   private final class_4599 renderBuffers;
   private final class_898 entityRenderDispatcher;
   private final class_824 blockEntityRenderDispatcher;
   private final class_11658 levelRenderState;
   private final class_11684 featureRenderDispatcher;
   private float partialTick;
   private class_243 cameraPos;
   private int lastCameraSectionX;
   private int lastCameraSectionY;
   private int lastCameraSectionZ;
   private float lastCameraX;
   private float lastCameraY;
   private float lastCameraZ;
   private float lastCamRotX;
   private float lastCamRotY;
   private SectionGrid sectionGrid;
   private SectionGraph sectionGraph;
   private boolean graphNeedsUpdate;
   private final Set<class_2586> globalBlockEntities = Sets.newHashSet();
   private final TaskDispatcher taskDispatcher;
   private double xTransparentOld;
   private double yTransparentOld;
   private double zTransparentOld;
   IndirectBuffer[] indirectBuffers;
   private static final ByteBuffer ENTITY_SHADOW_BUF = MemoryUtil.memAlloc(1179648);
   public RenderRegionBuilder renderRegionCache;
   private final List<Runnable> onAllChangedCallbacks = new ObjectArrayList();

   public static WorldRenderer init(class_898 entityRenderDispatcher, class_824 blockEntityRenderDispatcher, class_4599 renderBuffers, class_11658 levelRenderState, class_11684 featureRenderDispatcher) {
      return INSTANCE != null ? INSTANCE : (INSTANCE = new WorldRenderer(entityRenderDispatcher, blockEntityRenderDispatcher, renderBuffers, levelRenderState, featureRenderDispatcher));
   }

   private WorldRenderer(class_898 entityRenderDispatcher, class_824 blockEntityRenderDispatcher, class_4599 renderBuffers, class_11658 levelRenderState, class_11684 featureRenderDispatcher) {
      this.renderBuffers = renderBuffers;
      this.entityRenderDispatcher = entityRenderDispatcher;
      this.blockEntityRenderDispatcher = blockEntityRenderDispatcher;
      this.levelRenderState = levelRenderState;
      this.featureRenderDispatcher = featureRenderDispatcher;
      this.renderRegionCache = new RenderRegionBuilder();
      this.taskDispatcher = new TaskDispatcher();
      ChunkTask.setTaskDispatcher(this.taskDispatcher);
      this.allocateIndirectBuffers();
      TerrainRenderType.updateMapping();
      Renderer.getInstance().addOnResizeCallback(() -> {
         if (this.indirectBuffers.length != Renderer.getFramesNum()) {
            this.allocateIndirectBuffers();
         }

      });
   }

   private void allocateIndirectBuffers() {
      if (this.indirectBuffers != null) {
         Arrays.stream(this.indirectBuffers).forEach(Buffer::scheduleFree);
      }

      this.indirectBuffers = new IndirectBuffer[Renderer.getFramesNum()];

      for(int i = 0; i < this.indirectBuffers.length; ++i) {
         this.indirectBuffers[i] = new IndirectBuffer(1000000, MemoryTypes.HOST_MEM);
      }

   }

   private void benchCallback() {
      BuildTimeProfiler.runBench(this.graphNeedsUpdate || !this.taskDispatcher.isIdle());
   }

   public void setupRenderer(class_4184 camera, class_4604 frustum, boolean isCapturedFrustum, boolean spectator) {
      Profiler profiler = Profiler.getMainProfiler();
      profiler.push("Setup_Renderer");
      class_3695 mcProfiler = class_10209.method_64146();
      this.benchCallback();
      this.cameraPos = camera.method_19326();
      this.updateTerrainSunShadowState();
      if (this.minecraft.field_1690.method_38521() != this.renderDistance) {
         this.allChanged();
      }

      mcProfiler.method_15396("camera");
      float cameraX = (float)this.cameraPos.method_10216();
      float cameraY = (float)this.cameraPos.method_10214();
      float cameraZ = (float)this.cameraPos.method_10215();
      int sectionX = class_4076.method_32204((double)cameraX);
      int sectionY = class_4076.method_32204((double)cameraY);
      int sectionZ = class_4076.method_32204((double)cameraZ);
      profiler.push("reposition");
      if (this.lastCameraSectionX != sectionX || this.lastCameraSectionY != sectionY || this.lastCameraSectionZ != sectionZ) {
         this.lastCameraSectionX = sectionX;
         this.lastCameraSectionY = sectionY;
         this.lastCameraSectionZ = sectionZ;
         this.sectionGrid.repositionCamera((double)cameraX, (double)cameraZ);
      }

      profiler.pop();
      double entityDistanceScaling = (Double)this.minecraft.field_1690.method_42517().method_41753();
      class_1297.method_5840(class_3532.method_15350((double)this.renderDistance / (double)8.0F, (double)1.0F, (double)2.5F) * entityDistanceScaling);
      mcProfiler.method_15405("cull");
      mcProfiler.method_15405("update");
      boolean cameraMoved = false;
      float d_xRot = Math.abs(camera.method_19329() - this.lastCamRotX);
      float d_yRot = Math.abs(camera.method_19330() - this.lastCamRotY);
      cameraMoved |= d_xRot > 2.0F || d_yRot > 2.0F;
      cameraMoved |= cameraX != this.lastCameraX || cameraY != this.lastCameraY || cameraZ != this.lastCameraZ;
      this.graphNeedsUpdate |= cameraMoved;
      if (!isCapturedFrustum && this.graphNeedsUpdate()) {
         this.graphNeedsUpdate = false;
         this.lastCameraX = cameraX;
         this.lastCameraY = cameraY;
         this.lastCameraZ = cameraZ;
         this.lastCamRotX = camera.method_19329();
         this.lastCamRotY = camera.method_19330();
         this.sectionGraph.update(camera, frustum, spectator);
      }

      this.indirectBuffers[Renderer.getCurrentFrame()].reset();
      mcProfiler.method_15407();
      profiler.pop();
   }

   public void uploadSections() {
      class_3695 mcProfiler = class_10209.method_64146();
      mcProfiler.method_15396("upload");
      Profiler profiler = Profiler.getMainProfiler();
      profiler.push("Uploads");

      try {
         if (this.taskDispatcher.updateSections()) {
            this.graphNeedsUpdate = true;
         }
      } catch (Exception e) {
         Initializer.LOGGER.error(e.getMessage());
         this.allChanged();
      }

      profiler.pop();
      mcProfiler.method_15407();
   }

   public boolean isSectionCompiled(class_2338 blockPos) {
      RenderSection renderSection = this.sectionGrid.getSectionAtBlockPos(blockPos);
      return renderSection != null && renderSection.isCompiled();
   }

   public void allChanged() {
      if (this.level != null) {
         this.level.method_23784();
         this.renderRegionCache.clear();
         this.taskDispatcher.createThreads(Initializer.CONFIG.builderThreads);
         this.graphNeedsUpdate = true;
         this.renderDistance = this.minecraft.field_1690.method_38521();
         if (this.sectionGrid != null) {
            this.sectionGrid.freeAllBuffers();
         }

         this.taskDispatcher.clearBatchQueue();
         synchronized(this.globalBlockEntities) {
            this.globalBlockEntities.clear();
         }

         this.sectionGrid = new SectionGrid(this.level, this.renderDistance);
         this.sectionGraph = new SectionGraph(this.level, this.sectionGrid, this.taskDispatcher);
         this.onAllChangedCallbacks.forEach(Runnable::run);
         class_1297 entity = this.minecraft.method_1560();
         if (entity != null) {
            this.sectionGrid.repositionCamera(entity.method_23317(), entity.method_23321());
         }
      }

   }

   public void setLevel(@Nullable class_638 level) {
      this.lastCameraX = Float.MIN_VALUE;
      this.lastCameraY = Float.MIN_VALUE;
      this.lastCameraZ = Float.MIN_VALUE;
      this.lastCameraSectionX = Integer.MIN_VALUE;
      this.lastCameraSectionY = Integer.MIN_VALUE;
      this.lastCameraSectionZ = Integer.MIN_VALUE;
      this.level = level;
      ChunkStatusMap.createInstance(this.renderDistance);
      if (level != null) {
         this.allChanged();
      } else {
         if (this.sectionGrid != null) {
            this.sectionGrid.freeAllBuffers();
            this.sectionGrid = null;
         }

         this.taskDispatcher.stopThreads();
         this.graphNeedsUpdate = true;
      }

   }

   public void addOnAllChangedCallback(Runnable runnable) {
      this.onAllChangedCallbacks.add(runnable);
   }

   public void clearOnAllChangedCallbacks() {
      this.onAllChangedCallbacks.clear();
   }

   public void renderShadowTerrain(double camX, double camY, double camZ) {
      Renderer renderer = Renderer.getInstance();
      VRenderSystem.disableCull();
      VRenderSystem.depthFunc(515);
      GlStateManager._enableDepthTest();
      GlStateManager._depthMask(true);
      GraphicsPipeline pipeline = PipelineManager.getShadowTerrainShader();
      renderer.bindGraphicsPipeline(pipeline);
      class_1060 textureManager = class_310.method_1551().method_1531();
      class_1044 blockAtlasTexture = textureManager.method_4619(class_1059.field_5275);
      RenderSystem.setShaderTexture(0, blockAtlasTexture.method_71659());
      VTextureSelector.bindShaderTextures(pipeline);
      IndexBuffer indexBuffer = Renderer.getDrawer().getQuadsIndexBuffer().getIndexBuffer();
      Renderer.getDrawer().bindIndexBuffer(Renderer.getCommandBuffer(), indexBuffer, indexBuffer.indexType.value);
      ChunkAreaManager chunkAreaManager = this.getChunkAreaManager();
      if (chunkAreaManager != null) {
         for(ChunkArea area : chunkAreaManager.chunkAreasArr) {
            area.shadowSectionQueue.clear();
         }

         if (this.sectionGrid != null && this.sectionGrid.sections != null) {
            for(RenderSection section : this.sectionGrid.sections) {
               if (section != null && !section.isCompletelyEmpty()) {
                  ChunkArea area = section.getChunkArea();
                  if (area != null) {
                     area.shadowSectionQueue.add(section);
                  }
               }
            }
         }
      }

      Set<TerrainRenderType> allowedRenderTypes = Initializer.CONFIG.uniqueOpaqueLayer ? TerrainRenderType.COMPACT_RENDER_TYPES : TerrainRenderType.SEMI_COMPACT_RENDER_TYPES;

      for(TerrainRenderType renderType : TerrainRenderType.VALUES) {
         if (renderType != TerrainRenderType.TRANSLUCENT && renderType != TerrainRenderType.TRIPWIRE && allowedRenderTypes.contains(renderType)) {
            renderType.setCutoutUniform();
            if (chunkAreaManager != null) {
               for(ChunkArea chunkArea : chunkAreaManager.chunkAreasArr) {
                  StaticQueue<RenderSection> queue = chunkArea.shadowSectionQueue;
                  DrawBuffers drawBuffers = chunkArea.drawBuffers;
                  renderer.uploadAndBindUBOs(pipeline);
                  if (drawBuffers.getAreaBuffer(renderType) != null && queue.size() > 0) {
                     drawBuffers.bindBuffers(Renderer.getCommandBuffer(), pipeline, renderType, camX, camY, camZ);
                     renderer.uploadAndBindUBOs(pipeline);
                     drawBuffers.buildDrawBatchesDirect(this.cameraPos, queue, renderType);
                  }
               }
            }
         }
      }

      VRenderSystem.setModelOffset(0.0F, 0.0F, 0.0F);
      renderer.pushConstants(pipeline);
   }

   public void renderEntityShadows(double camX, double camY, double camZ) {
      if (this.level != null) {
         Renderer renderer = Renderer.getInstance();
         GraphicsPipeline pipeline = PipelineManager.getShadowEntityShader();
         renderer.bindGraphicsPipeline(pipeline);
         renderer.uploadAndBindUBOs(pipeline);
         ByteBuffer buf = ENTITY_SHADOW_BUF;
         buf.clear();
         ShadowVertexConsumer shadowConsumer = new ShadowVertexConsumer(buf);
         ShadowNodeCollector nodeCollector = new ShadowNodeCollector(shadowConsumer);
         class_4587 poseStack = new class_4587();
         class_12075 cameraState = new class_12075();
         cameraState.field_63078 = new class_243(camX, camY, camZ);
         cameraState.field_63077 = class_2338.method_49637(camX, camY, camZ);
         cameraState.field_63079 = true;
         cameraState.field_63080 = cameraState.field_63078;
         cameraState.field_63081 = new Quaternionf();

         for(class_1297 entity : this.level.method_18112()) {
            if (!entity.method_5767() && !entity.method_7325()) {
               double dx = entity.method_23317() - camX;
               double dy = entity.method_23318() - camY;
               double dz = entity.method_23321() - camZ;

               try {
                  class_10017 renderState = this.entityRenderDispatcher.method_72977(entity, this.partialTick);
                  poseStack.method_22903();
                  this.entityRenderDispatcher.method_72976(renderState, cameraState, dx, dy, dz, poseStack, nodeCollector);
                  poseStack.method_22909();
               } catch (Exception var23) {
               }

               if (buf.remaining() < 1024) {
                  break;
               }
            }
         }

         int vertexCount = shadowConsumer.getVertexCount();
         if (vertexCount > 0) {
            buf.flip();
            Drawer drawer = Renderer.getDrawer();
            drawer.draw(buf, class_5596.field_27382, class_290.field_1592, vertexCount);
         }

      }
   }

   public void renderSectionLayer(TerrainRenderType renderType, double camX, double camY, double camZ, Matrix4f modelView, Matrix4f projection) {
      Renderer.getInstance().getMainPass().rebindMainTarget();
      this.sortTranslucentSections(camX, camY, camZ);
      class_3695 mcProfiler = class_10209.method_64146();
      class_10214 zone = mcProfiler.method_64144(() -> "render_" + String.valueOf(renderType));
      boolean isTranslucent = renderType == TerrainRenderType.TRANSLUCENT;
      boolean indirectDraw = Initializer.CONFIG.indirectDraw;
      if (!isTranslucent) {
         GlStateManager._disableBlend();
      } else {
         GlStateManager._enableBlend();
         VRenderSystem.blendFuncSeparate(770, 771, 1, 771);
      }

      VRenderSystem.enableCull();
      VRenderSystem.depthFunc(515);
      GlStateManager._enableDepthTest();
      GlStateManager._depthMask(true);
      GlStateManager._colorMask(true, true, true, true);
      GlStateManager._disablePolygonOffset();
      VRenderSystem.setPolygonModeGL(6914);
      VRenderSystem.applyMVP(modelView, projection);
      VRenderSystem.setPrimitiveTopologyGL(4);
      Renderer renderer = Renderer.getInstance();
      GraphicsPipeline pipeline = PipelineManager.getTerrainShader(renderType);
      renderer.bindGraphicsPipeline(pipeline);
      class_1060 textureManager = class_310.method_1551().method_1531();
      class_1044 blockAtlasTexture = textureManager.method_4619(class_1059.field_5275);
      blockAtlasTexture.method_70950(true);
      RenderSystem.setShaderTexture(0, blockAtlasTexture.method_71659());
      RenderSystem.setShaderTexture(2, class_310.method_1551().field_1773.method_22974().method_71650());
      VTextureSelector.bindShaderTextures(pipeline);
      if (renderType == TerrainRenderType.TRANSLUCENT) {
         VulkanImage sceneColor = VRenderSystem.sceneColorImage;
         VTextureSelector.bindTexture(3, sceneColor != null ? sceneColor : VTextureSelector.getWhiteTexture());
         VulkanImage shadowMap = Renderer.getInstance().getShadowPass().getShadowMap();
         VTextureSelector.bindTexture(6, shadowMap != null ? shadowMap : VTextureSelector.getWhiteTexture());
      } else {
         VulkanImage shadowMap = Renderer.getInstance().getShadowPass().getShadowMap();
         VTextureSelector.bindTexture(3, shadowMap != null ? shadowMap : VTextureSelector.getWhiteTexture());
      }

      IndexBuffer indexBuffer = Renderer.getDrawer().getQuadsIndexBuffer().getIndexBuffer();
      Renderer.getDrawer().bindIndexBuffer(Renderer.getCommandBuffer(), indexBuffer, indexBuffer.indexType.value);
      int currentFrame = Renderer.getCurrentFrame();
      Set<TerrainRenderType> allowedRenderTypes = Initializer.CONFIG.uniqueOpaqueLayer ? TerrainRenderType.COMPACT_RENDER_TYPES : TerrainRenderType.SEMI_COMPACT_RENDER_TYPES;
      if (allowedRenderTypes.contains(renderType)) {
         renderType.setCutoutUniform();
         Iterator<ChunkArea> iterator = this.sectionGraph.getChunkAreaQueue().iterator(isTranslucent);

         while(iterator.hasNext()) {
            ChunkArea chunkArea = (ChunkArea)iterator.next();
            StaticQueue<RenderSection> queue = chunkArea.sectionQueue;
            DrawBuffers drawBuffers = chunkArea.drawBuffers;
            if (drawBuffers.getAreaBuffer(renderType) != null && queue.size() > 0) {
               renderer.uploadAndBindUBOs(pipeline);
               drawBuffers.bindBuffers(Renderer.getCommandBuffer(), pipeline, renderType, camX, camY, camZ);
               renderer.uploadAndBindUBOs(pipeline);
               if (indirectDraw) {
                  drawBuffers.buildDrawBatchesIndirect(this.cameraPos, this.indirectBuffers[currentFrame], queue, renderType);
               } else {
                  drawBuffers.buildDrawBatchesDirect(this.cameraPos, queue, renderType);
               }
            }
         }
      }

      if (renderType == TerrainRenderType.CUTOUT || renderType == TerrainRenderType.TRIPWIRE) {
         this.indirectBuffers[currentFrame].submitUploads();
      }

      if (!indirectDraw) {
         VRenderSystem.setModelOffset(0.0F, 0.0F, 0.0F);
         renderer.pushConstants(pipeline);
      }

      zone.close();
   }

   private void sortTranslucentSections(double camX, double camY, double camZ) {
      class_3695 mcProfiler = class_10209.method_64146();
      mcProfiler.method_15396("translucent_sort");
      double d0 = camX - this.xTransparentOld;
      double d1 = camY - this.yTransparentOld;
      double d2 = camZ - this.zTransparentOld;
      if (d0 * d0 + d1 * d1 + d2 * d2 > (double)2.0F) {
         this.xTransparentOld = camX;
         this.yTransparentOld = camY;
         this.zTransparentOld = camZ;
         int j = 0;
         Iterator<RenderSection> iterator = this.sectionGraph.getSectionQueue().iterator(false);

         while(iterator.hasNext() && j < 200) {
            RenderSection section = (RenderSection)iterator.next();
            section.resortTransparency(this.taskDispatcher);
            if (!section.isCompletelyEmpty()) {
               ++j;
            }
         }
      }

      mcProfiler.method_15407();
   }

   public void renderBlockEntities(class_4587 poseStack, class_11658 levelRenderState, class_11661 submitNodeStorage, Long2ObjectMap<SortedSet<class_3191>> destructionProgress) {
      Profiler profiler = Profiler.getMainProfiler();
      profiler.pop();
      profiler.push("Block-entities");
      class_243 vec3 = levelRenderState.field_63082.field_63078;
      double camX = vec3.method_10216();
      double camY = vec3.method_10214();
      double camZ = vec3.method_10215();

      for(RenderSection renderSection : this.sectionGraph.getBlockEntitiesSections()) {
         List<class_2586> list = renderSection.getCompiledSection().getBlockEntities();
         if (!list.isEmpty()) {
            for(class_2586 blockEntity : list) {
               class_2338 blockPos = blockEntity.method_11016();
               SortedSet<class_3191> sortedSet = (SortedSet)destructionProgress.get(blockPos.method_10063());
               class_11683.class_11792 crumblingOverlay;
               if (sortedSet != null && !sortedSet.isEmpty()) {
                  poseStack.method_22903();
                  poseStack.method_22904((double)blockPos.method_10263() - camX, (double)blockPos.method_10264() - camY, (double)blockPos.method_10260() - camZ);
                  crumblingOverlay = new class_11683.class_11792(((class_3191)sortedSet.last()).method_13988(), poseStack.method_23760());
                  poseStack.method_22909();
               } else {
                  crumblingOverlay = null;
               }

               class_11954 blockEntityRenderState = this.blockEntityRenderDispatcher.method_74348(blockEntity, this.partialTick, crumblingOverlay);
               if (blockEntityRenderState != null) {
                  levelRenderState.field_62646.add(blockEntityRenderState);
               }
            }
         }
      }

      Iterator<class_2586> iterator = this.level.method_72019().iterator();

      while(iterator.hasNext()) {
         class_2586 blockEntity2 = (class_2586)iterator.next();
         if (blockEntity2.method_11015()) {
            iterator.remove();
         } else {
            class_11954 blockEntityRenderState2 = this.blockEntityRenderDispatcher.method_74348(blockEntity2, this.partialTick, (class_11683.class_11792)null);
            if (blockEntityRenderState2 != null) {
               levelRenderState.field_62646.add(blockEntityRenderState2);
            }
         }
      }

      for(class_11954 blockEntityRenderState : levelRenderState.field_62646) {
         class_2338 blockPos = blockEntityRenderState.field_62673;
         poseStack.method_22903();
         poseStack.method_22904((double)blockPos.method_10263() - camX, (double)blockPos.method_10264() - camY, (double)blockPos.method_10260() - camZ);
         class_824 blockEntityRenderDispatcher = this.minecraft.method_31975();
         blockEntityRenderDispatcher.method_3555(blockEntityRenderState, poseStack, submitNodeStorage, levelRenderState.field_63082);
         poseStack.method_22909();
      }

   }

   public void setPartialTick(float partialTick) {
      this.partialTick = partialTick;
   }

   public float getPartialTick() {
      return this.partialTick;
   }

   public void scheduleGraphUpdate() {
      this.graphNeedsUpdate = true;
   }

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

   public int getVisibleSectionsCount() {
      return this.sectionGraph.getSectionQueue().size();
   }

   private void updateTerrainSunShadowState() {
      if (this.level != null && this.sectionGraph != null) {
         float timeOfDay = ((float)(this.level.method_8532() % 24000L) + this.partialTick) / 24000.0F;
         float sunAngle = timeOfDay * 2.0F * (float)Math.PI;
         terrainSunDirX = (float)Math.cos((double)sunAngle);
         terrainSunDirY = (float)Math.sin((double)sunAngle);
         terrainSunDirZ = 0.0F;
         int bucket = Math.floorMod((int)(timeOfDay * 1024.0F), 1024);
         if (bucket != terrainSunShadowBucket) {
            terrainSunShadowBucket = bucket;
            if (this.sectionGrid != null && this.sectionGrid.sections != null) {
               for(RenderSection section : this.sectionGrid.sections) {
                  if (section != null) {
                     section.setDirty(false);
                  }
               }

            }
         }
      }
   }

   public void setSectionDirty(int x, int y, int z, boolean flag) {
      this.sectionGrid.setDirty(x, y, z, flag);
      this.renderRegionCache.remove(x, z);
   }

   public SectionGrid getSectionGrid() {
      return this.sectionGrid;
   }

   public ChunkAreaManager getChunkAreaManager() {
      return this.sectionGrid == null ? null : this.sectionGrid.chunkAreaManager;
   }

   public TaskDispatcher getTaskDispatcher() {
      return this.taskDispatcher;
   }

   public short getLastFrame() {
      return this.sectionGraph.getLastFrame();
   }

   public int getRenderDistance() {
      return this.renderDistance;
   }

   public String getChunkStatistics() {
      return this.sectionGraph == null ? null : this.sectionGraph.getStatistics();
   }

   public void cleanUp() {
      if (this.indirectBuffers != null) {
         Arrays.stream(this.indirectBuffers).forEach(Buffer::scheduleFree);
      }

   }

   public static WorldRenderer getInstance() {
      return INSTANCE;
   }

   public static float getTerrainSunDirX() {
      return terrainSunDirX;
   }

   public static float getTerrainSunDirY() {
      return terrainSunDirY;
   }

   public static float getTerrainSunDirZ() {
      return terrainSunDirZ;
   }

   public static class_638 getLevel() {
      return INSTANCE.level;
   }

   public static class_243 getCameraPos() {
      return INSTANCE.cameraPos;
   }

   private static class ShadowVertexConsumer implements class_4588 {
      private final ByteBuffer buffer;
      private int vertexCount;

      ShadowVertexConsumer(ByteBuffer buffer) {
         this.buffer = buffer;
      }

      int getVertexCount() {
         return this.vertexCount;
      }

      public class_4588 method_22912(float x, float y, float z) {
         if (this.buffer.remaining() >= 12) {
            this.buffer.putFloat(x).putFloat(y).putFloat(z);
            ++this.vertexCount;
         }

         return this;
      }

      public class_4588 method_1336(int r, int g, int b, int a) {
         return this;
      }

      public class_4588 method_22913(float u, float v) {
         return this;
      }

      public class_4588 method_60796(int u, int v) {
         return this;
      }

      public class_4588 method_22921(int u, int v) {
         return this;
      }

      public class_4588 method_22914(float x, float y, float z) {
         return this;
      }
   }

   private static class ShadowNodeCollector implements class_11659 {
      private final ShadowVertexConsumer consumer;

      ShadowNodeCollector(ShadowVertexConsumer consumer) {
         this.consumer = consumer;
      }

      public class_11785 method_73529(int i) {
         return this;
      }

      public <S> void method_73490(class_3879<? super S> model, S state, class_4587 poseStack, class_1921 renderType, int light, int overlay, int color, class_1058 sprite, int i, class_11683.class_11792 crumblingOverlay) {
         model.method_60879(poseStack, this.consumer, light, overlay);
      }

      public void method_73494(class_630 part, class_4587 poseStack, class_1921 renderType, int light, int overlay, class_1058 sprite, boolean bl, boolean bl2, int color, class_11683.class_11792 crumblingOverlay, int i) {
         part.method_22698(poseStack, this.consumer, light, overlay);
      }

      public void method_73483(class_4587 poseStack, class_1921 renderType, class_11659.class_11660 renderer) {
         renderer.render(poseStack.method_23760(), this.consumer);
      }

      public void method_73487(class_4587 ps, class_10017 s, class_10933 h) {
      }

      public void method_73479(class_4587 ps, float f, List<class_10017.class_11680> l) {
      }

      public void method_73482(class_4587 ps, class_243 v, int i, class_2561 c, boolean b, int j, double d, class_12075 cs) {
      }

      public void method_73478(class_4587 ps, float f1, float f2, class_5481 seq, boolean b, class_327.class_6415 dm, int i, int j, int k, int l) {
      }

      public void method_73488(class_4587 ps, class_10017 s, Quaternionf q) {
      }

      public void method_73486(class_4587 ps, class_10017.class_10018 ls) {
      }

      public void method_73481(class_4587 ps, class_2680 bs, int i, int j, int k) {
      }

      public void method_73485(class_4587 ps, class_11791 mrs) {
      }

      public void method_73484(class_4587 ps, class_1921 rt, class_1087 bsm, float f1, float f2, float f3, int i, int j, int k) {
      }

      public void method_73480(class_4587 ps, class_811 idc, int i, int j, int k, int[] ia, List<class_777> quads, class_1921 rt, class_10444.class_10445 ft) {
      }

      public void method_74315(class_11659.class_11947 pgr) {
      }
   }
}
