253 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			253 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.client.renderer.entity;
 | |
| 
 | |
| import com.google.common.collect.ImmutableList.Builder;
 | |
| import com.mojang.blaze3d.vertex.PoseStack;
 | |
| import com.mojang.blaze3d.vertex.VertexConsumer;
 | |
| import com.mojang.math.Axis;
 | |
| import net.fabricmc.api.EnvType;
 | |
| import net.fabricmc.api.Environment;
 | |
| import net.minecraft.client.model.dragon.EnderDragonModel;
 | |
| import net.minecraft.client.model.geom.ModelLayers;
 | |
| import net.minecraft.client.renderer.MultiBufferSource;
 | |
| import net.minecraft.client.renderer.RenderType;
 | |
| import net.minecraft.client.renderer.entity.state.EnderDragonRenderState;
 | |
| import net.minecraft.client.renderer.entity.state.HitboxRenderState;
 | |
| import net.minecraft.client.renderer.texture.OverlayTexture;
 | |
| import net.minecraft.core.BlockPos;
 | |
| import net.minecraft.resources.ResourceLocation;
 | |
| import net.minecraft.util.ARGB;
 | |
| import net.minecraft.util.Mth;
 | |
| import net.minecraft.util.RandomSource;
 | |
| import net.minecraft.world.entity.boss.EnderDragonPart;
 | |
| import net.minecraft.world.entity.boss.enderdragon.EndCrystal;
 | |
| import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
 | |
| import net.minecraft.world.entity.boss.enderdragon.phases.DragonPhaseInstance;
 | |
| import net.minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhase;
 | |
| import net.minecraft.world.level.levelgen.Heightmap;
 | |
| import net.minecraft.world.level.levelgen.feature.EndPodiumFeature;
 | |
| import net.minecraft.world.phys.AABB;
 | |
| import net.minecraft.world.phys.Vec3;
 | |
| import org.joml.Quaternionf;
 | |
| import org.joml.Vector3f;
 | |
| 
 | |
| @Environment(EnvType.CLIENT)
 | |
| public class EnderDragonRenderer extends EntityRenderer<EnderDragon, EnderDragonRenderState> {
 | |
| 	public static final ResourceLocation CRYSTAL_BEAM_LOCATION = ResourceLocation.withDefaultNamespace("textures/entity/end_crystal/end_crystal_beam.png");
 | |
| 	private static final ResourceLocation DRAGON_EXPLODING_LOCATION = ResourceLocation.withDefaultNamespace("textures/entity/enderdragon/dragon_exploding.png");
 | |
| 	private static final ResourceLocation DRAGON_LOCATION = ResourceLocation.withDefaultNamespace("textures/entity/enderdragon/dragon.png");
 | |
| 	private static final ResourceLocation DRAGON_EYES_LOCATION = ResourceLocation.withDefaultNamespace("textures/entity/enderdragon/dragon_eyes.png");
 | |
| 	private static final RenderType RENDER_TYPE = RenderType.entityCutoutNoCull(DRAGON_LOCATION);
 | |
| 	private static final RenderType DECAL = RenderType.entityDecal(DRAGON_LOCATION);
 | |
| 	private static final RenderType EYES = RenderType.eyes(DRAGON_EYES_LOCATION);
 | |
| 	private static final RenderType BEAM = RenderType.entitySmoothCutout(CRYSTAL_BEAM_LOCATION);
 | |
| 	private static final float HALF_SQRT_3 = (float)(Math.sqrt(3.0) / 2.0);
 | |
| 	private final EnderDragonModel model;
 | |
| 
 | |
| 	public EnderDragonRenderer(EntityRendererProvider.Context context) {
 | |
| 		super(context);
 | |
| 		this.shadowRadius = 0.5F;
 | |
| 		this.model = new EnderDragonModel(context.bakeLayer(ModelLayers.ENDER_DRAGON));
 | |
| 	}
 | |
| 
 | |
| 	public void render(EnderDragonRenderState renderState, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight) {
 | |
| 		poseStack.pushPose();
 | |
| 		float f = renderState.getHistoricalPos(7).yRot();
 | |
| 		float g = (float)(renderState.getHistoricalPos(5).y() - renderState.getHistoricalPos(10).y());
 | |
| 		poseStack.mulPose(Axis.YP.rotationDegrees(-f));
 | |
| 		poseStack.mulPose(Axis.XP.rotationDegrees(g * 10.0F));
 | |
| 		poseStack.translate(0.0F, 0.0F, 1.0F);
 | |
| 		poseStack.scale(-1.0F, -1.0F, 1.0F);
 | |
| 		poseStack.translate(0.0F, -1.501F, 0.0F);
 | |
| 		this.model.setupAnim(renderState);
 | |
| 		if (renderState.deathTime > 0.0F) {
 | |
| 			float h = renderState.deathTime / 200.0F;
 | |
| 			int i = ARGB.color(Mth.floor(h * 255.0F), -1);
 | |
| 			VertexConsumer vertexConsumer = bufferSource.getBuffer(RenderType.dragonExplosionAlpha(DRAGON_EXPLODING_LOCATION));
 | |
| 			this.model.renderToBuffer(poseStack, vertexConsumer, packedLight, OverlayTexture.NO_OVERLAY, i);
 | |
| 			VertexConsumer vertexConsumer2 = bufferSource.getBuffer(DECAL);
 | |
| 			this.model.renderToBuffer(poseStack, vertexConsumer2, packedLight, OverlayTexture.pack(0.0F, renderState.hasRedOverlay));
 | |
| 		} else {
 | |
| 			VertexConsumer vertexConsumer3 = bufferSource.getBuffer(RENDER_TYPE);
 | |
| 			this.model.renderToBuffer(poseStack, vertexConsumer3, packedLight, OverlayTexture.pack(0.0F, renderState.hasRedOverlay));
 | |
| 		}
 | |
| 
 | |
| 		VertexConsumer vertexConsumer3 = bufferSource.getBuffer(EYES);
 | |
| 		this.model.renderToBuffer(poseStack, vertexConsumer3, packedLight, OverlayTexture.NO_OVERLAY);
 | |
| 		if (renderState.deathTime > 0.0F) {
 | |
| 			float j = renderState.deathTime / 200.0F;
 | |
| 			poseStack.pushPose();
 | |
| 			poseStack.translate(0.0F, -1.0F, -2.0F);
 | |
| 			renderRays(poseStack, j, bufferSource.getBuffer(RenderType.dragonRays()));
 | |
| 			renderRays(poseStack, j, bufferSource.getBuffer(RenderType.dragonRaysDepth()));
 | |
| 			poseStack.popPose();
 | |
| 		}
 | |
| 
 | |
| 		poseStack.popPose();
 | |
| 		if (renderState.beamOffset != null) {
 | |
| 			renderCrystalBeams(
 | |
| 				(float)renderState.beamOffset.x,
 | |
| 				(float)renderState.beamOffset.y,
 | |
| 				(float)renderState.beamOffset.z,
 | |
| 				renderState.ageInTicks,
 | |
| 				poseStack,
 | |
| 				bufferSource,
 | |
| 				packedLight
 | |
| 			);
 | |
| 		}
 | |
| 
 | |
| 		super.render(renderState, poseStack, bufferSource, packedLight);
 | |
| 	}
 | |
| 
 | |
| 	private static void renderRays(PoseStack poseStack, float dragonDeathCompletion, VertexConsumer buffer) {
 | |
| 		poseStack.pushPose();
 | |
| 		float f = Math.min(dragonDeathCompletion > 0.8F ? (dragonDeathCompletion - 0.8F) / 0.2F : 0.0F, 1.0F);
 | |
| 		int i = ARGB.colorFromFloat(1.0F - f, 1.0F, 1.0F, 1.0F);
 | |
| 		int j = 16711935;
 | |
| 		RandomSource randomSource = RandomSource.create(432L);
 | |
| 		Vector3f vector3f = new Vector3f();
 | |
| 		Vector3f vector3f2 = new Vector3f();
 | |
| 		Vector3f vector3f3 = new Vector3f();
 | |
| 		Vector3f vector3f4 = new Vector3f();
 | |
| 		Quaternionf quaternionf = new Quaternionf();
 | |
| 		int k = Mth.floor((dragonDeathCompletion + dragonDeathCompletion * dragonDeathCompletion) / 2.0F * 60.0F);
 | |
| 
 | |
| 		for (int l = 0; l < k; l++) {
 | |
| 			quaternionf.rotationXYZ(
 | |
| 					randomSource.nextFloat() * (float) (Math.PI * 2), randomSource.nextFloat() * (float) (Math.PI * 2), randomSource.nextFloat() * (float) (Math.PI * 2)
 | |
| 				)
 | |
| 				.rotateXYZ(
 | |
| 					randomSource.nextFloat() * (float) (Math.PI * 2),
 | |
| 					randomSource.nextFloat() * (float) (Math.PI * 2),
 | |
| 					randomSource.nextFloat() * (float) (Math.PI * 2) + dragonDeathCompletion * (float) (Math.PI / 2)
 | |
| 				);
 | |
| 			poseStack.mulPose(quaternionf);
 | |
| 			float g = randomSource.nextFloat() * 20.0F + 5.0F + f * 10.0F;
 | |
| 			float h = randomSource.nextFloat() * 2.0F + 1.0F + f * 2.0F;
 | |
| 			vector3f2.set(-HALF_SQRT_3 * h, g, -0.5F * h);
 | |
| 			vector3f3.set(HALF_SQRT_3 * h, g, -0.5F * h);
 | |
| 			vector3f4.set(0.0F, g, h);
 | |
| 			PoseStack.Pose pose = poseStack.last();
 | |
| 			buffer.addVertex(pose, vector3f).setColor(i);
 | |
| 			buffer.addVertex(pose, vector3f2).setColor(16711935);
 | |
| 			buffer.addVertex(pose, vector3f3).setColor(16711935);
 | |
| 			buffer.addVertex(pose, vector3f).setColor(i);
 | |
| 			buffer.addVertex(pose, vector3f3).setColor(16711935);
 | |
| 			buffer.addVertex(pose, vector3f4).setColor(16711935);
 | |
| 			buffer.addVertex(pose, vector3f).setColor(i);
 | |
| 			buffer.addVertex(pose, vector3f4).setColor(16711935);
 | |
| 			buffer.addVertex(pose, vector3f2).setColor(16711935);
 | |
| 		}
 | |
| 
 | |
| 		poseStack.popPose();
 | |
| 	}
 | |
| 
 | |
| 	public static void renderCrystalBeams(
 | |
| 		float offsetX, float offsetY, float offsetZ, float ageInTicks, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight
 | |
| 	) {
 | |
| 		float f = Mth.sqrt(offsetX * offsetX + offsetZ * offsetZ);
 | |
| 		float g = Mth.sqrt(offsetX * offsetX + offsetY * offsetY + offsetZ * offsetZ);
 | |
| 		poseStack.pushPose();
 | |
| 		poseStack.translate(0.0F, 2.0F, 0.0F);
 | |
| 		poseStack.mulPose(Axis.YP.rotation((float)(-Math.atan2(offsetZ, offsetX)) - (float) (Math.PI / 2)));
 | |
| 		poseStack.mulPose(Axis.XP.rotation((float)(-Math.atan2(f, offsetY)) - (float) (Math.PI / 2)));
 | |
| 		VertexConsumer vertexConsumer = bufferSource.getBuffer(BEAM);
 | |
| 		float h = 0.0F - ageInTicks * 0.01F;
 | |
| 		float i = g / 32.0F - ageInTicks * 0.01F;
 | |
| 		int j = 8;
 | |
| 		float k = 0.0F;
 | |
| 		float l = 0.75F;
 | |
| 		float m = 0.0F;
 | |
| 		PoseStack.Pose pose = poseStack.last();
 | |
| 
 | |
| 		for (int n = 1; n <= 8; n++) {
 | |
| 			float o = Mth.sin(n * (float) (Math.PI * 2) / 8.0F) * 0.75F;
 | |
| 			float p = Mth.cos(n * (float) (Math.PI * 2) / 8.0F) * 0.75F;
 | |
| 			float q = n / 8.0F;
 | |
| 			vertexConsumer.addVertex(pose, k * 0.2F, l * 0.2F, 0.0F)
 | |
| 				.setColor(-16777216)
 | |
| 				.setUv(m, h)
 | |
| 				.setOverlay(OverlayTexture.NO_OVERLAY)
 | |
| 				.setLight(packedLight)
 | |
| 				.setNormal(pose, 0.0F, -1.0F, 0.0F);
 | |
| 			vertexConsumer.addVertex(pose, k, l, g)
 | |
| 				.setColor(-1)
 | |
| 				.setUv(m, i)
 | |
| 				.setOverlay(OverlayTexture.NO_OVERLAY)
 | |
| 				.setLight(packedLight)
 | |
| 				.setNormal(pose, 0.0F, -1.0F, 0.0F);
 | |
| 			vertexConsumer.addVertex(pose, o, p, g)
 | |
| 				.setColor(-1)
 | |
| 				.setUv(q, i)
 | |
| 				.setOverlay(OverlayTexture.NO_OVERLAY)
 | |
| 				.setLight(packedLight)
 | |
| 				.setNormal(pose, 0.0F, -1.0F, 0.0F);
 | |
| 			vertexConsumer.addVertex(pose, o * 0.2F, p * 0.2F, 0.0F)
 | |
| 				.setColor(-16777216)
 | |
| 				.setUv(q, h)
 | |
| 				.setOverlay(OverlayTexture.NO_OVERLAY)
 | |
| 				.setLight(packedLight)
 | |
| 				.setNormal(pose, 0.0F, -1.0F, 0.0F);
 | |
| 			k = o;
 | |
| 			l = p;
 | |
| 			m = q;
 | |
| 		}
 | |
| 
 | |
| 		poseStack.popPose();
 | |
| 	}
 | |
| 
 | |
| 	public EnderDragonRenderState createRenderState() {
 | |
| 		return new EnderDragonRenderState();
 | |
| 	}
 | |
| 
 | |
| 	public void extractRenderState(EnderDragon entity, EnderDragonRenderState reusedState, float partialTick) {
 | |
| 		super.extractRenderState(entity, reusedState, partialTick);
 | |
| 		reusedState.flapTime = Mth.lerp(partialTick, entity.oFlapTime, entity.flapTime);
 | |
| 		reusedState.deathTime = entity.dragonDeathTime > 0 ? entity.dragonDeathTime + partialTick : 0.0F;
 | |
| 		reusedState.hasRedOverlay = entity.hurtTime > 0;
 | |
| 		EndCrystal endCrystal = entity.nearestCrystal;
 | |
| 		if (endCrystal != null) {
 | |
| 			Vec3 vec3 = endCrystal.getPosition(partialTick).add(0.0, EndCrystalRenderer.getY(endCrystal.time + partialTick), 0.0);
 | |
| 			reusedState.beamOffset = vec3.subtract(entity.getPosition(partialTick));
 | |
| 		} else {
 | |
| 			reusedState.beamOffset = null;
 | |
| 		}
 | |
| 
 | |
| 		DragonPhaseInstance dragonPhaseInstance = entity.getPhaseManager().getCurrentPhase();
 | |
| 		reusedState.isLandingOrTakingOff = dragonPhaseInstance == EnderDragonPhase.LANDING || dragonPhaseInstance == EnderDragonPhase.TAKEOFF;
 | |
| 		reusedState.isSitting = dragonPhaseInstance.isSitting();
 | |
| 		BlockPos blockPos = entity.level().getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(entity.getFightOrigin()));
 | |
| 		reusedState.distanceToEgg = blockPos.distToCenterSqr(entity.position());
 | |
| 		reusedState.partialTicks = entity.isDeadOrDying() ? 0.0F : partialTick;
 | |
| 		reusedState.flightHistory.copyFrom(entity.flightHistory);
 | |
| 	}
 | |
| 
 | |
| 	protected void extractAdditionalHitboxes(EnderDragon entity, Builder<HitboxRenderState> hitboxes, float partialTick) {
 | |
| 		super.extractAdditionalHitboxes(entity, hitboxes, partialTick);
 | |
| 		double d = -Mth.lerp((double)partialTick, entity.xOld, entity.getX());
 | |
| 		double e = -Mth.lerp((double)partialTick, entity.yOld, entity.getY());
 | |
| 		double f = -Mth.lerp((double)partialTick, entity.zOld, entity.getZ());
 | |
| 
 | |
| 		for (EnderDragonPart enderDragonPart : entity.getSubEntities()) {
 | |
| 			AABB aABB = enderDragonPart.getBoundingBox();
 | |
| 			HitboxRenderState hitboxRenderState = new HitboxRenderState(
 | |
| 				aABB.minX - enderDragonPart.getX(),
 | |
| 				aABB.minY - enderDragonPart.getY(),
 | |
| 				aABB.minZ - enderDragonPart.getZ(),
 | |
| 				aABB.maxX - enderDragonPart.getX(),
 | |
| 				aABB.maxY - enderDragonPart.getY(),
 | |
| 				aABB.maxZ - enderDragonPart.getZ(),
 | |
| 				(float)(d + Mth.lerp((double)partialTick, enderDragonPart.xOld, enderDragonPart.getX())),
 | |
| 				(float)(e + Mth.lerp((double)partialTick, enderDragonPart.yOld, enderDragonPart.getY())),
 | |
| 				(float)(f + Mth.lerp((double)partialTick, enderDragonPart.zOld, enderDragonPart.getZ())),
 | |
| 				0.25F,
 | |
| 				1.0F,
 | |
| 				0.0F
 | |
| 			);
 | |
| 			hitboxes.add(hitboxRenderState);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	protected boolean affectedByCulling(EnderDragon display) {
 | |
| 		return false;
 | |
| 	}
 | |
| }
 |