diff --git a/src/main/java/com/crowsofwar/avatar/AvatarMod.java b/src/main/java/com/crowsofwar/avatar/AvatarMod.java index e4cfdbc51c..f8849d71f8 100644 --- a/src/main/java/com/crowsofwar/avatar/AvatarMod.java +++ b/src/main/java/com/crowsofwar/avatar/AvatarMod.java @@ -38,6 +38,8 @@ import com.crowsofwar.avatar.blocks.AvatarBlocks; import com.crowsofwar.avatar.client.gui.AvatarGuiHandler; import com.crowsofwar.avatar.client.particle.AvatarParticles; +import com.crowsofwar.avatar.client.render.lightning.main.ModEventHandler; +import com.crowsofwar.avatar.client.render.lightning.main.PacketDispatcher; import com.crowsofwar.avatar.common.triggers.AvatarTriggers; import com.crowsofwar.avatar.config.*; import com.crowsofwar.avatar.entity.*; @@ -66,9 +68,14 @@ import com.crowsofwar.avatar.util.windhelper.WindHelper; import net.minecraft.entity.Entity; import net.minecraft.entity.EnumCreatureType; +import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.attributes.RangedAttribute; import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; import net.minecraftforge.common.ForgeChunkManager; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod.EventHandler; @@ -81,11 +88,16 @@ import net.minecraftforge.fml.common.network.NetworkRegistry; import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper; import net.minecraftforge.fml.common.registry.EntityRegistry; +import net.minecraftforge.fml.relauncher.ReflectionHelper; import net.minecraftforge.fml.relauncher.Side; +import org.apache.logging.log4j.Logger; import org.joml.Matrix4f; import org.joml.Vector4f; import java.io.File; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Random; import static com.crowsofwar.avatar.config.ConfigMobs.MOBS_CONFIG; import static com.crowsofwar.avatar.config.ConfigStats.STATS_CONFIG; @@ -112,6 +124,17 @@ public class AvatarMod { private int nextMessageID = 1; private int nextEntityID = 1; + // From Drillgon's MainRegistry + public static Logger logger; + public static int generalOverride = 0; + public static int polaroidID = 1; + public static final int schrabFromUraniumChance = 100; + public static int x; + public static int y; + public static int z; + public static long time; + Random rand = new Random(); + private static void registerAbilities() { /* Air */ @@ -349,7 +372,25 @@ public void preInit(FMLPreInitializationEvent e) { } }**/ - + // From Drillgon's MainRegistry + if(generalOverride > 0 && generalOverride < 19) { + polaroidID = generalOverride; + } else { + polaroidID = rand.nextInt(18) + 1; + while(polaroidID == 4 || polaroidID == 9) + polaroidID = rand.nextInt(18) + 1; + } + if(SharedMonsterAttributes.MAX_HEALTH.clampValue(Integer.MAX_VALUE) <= 2000) + try{ + @SuppressWarnings("deprecation") + Field f = ReflectionHelper.findField(RangedAttribute.class, "maximumValue", "field_111118_b"); + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL); + f.set(SharedMonsterAttributes.MAX_HEALTH, Integer.MAX_VALUE); + } catch(Exception ignored){} + proxy.checkGLCaps(); + reloadConfig(); } @EventHandler @@ -422,10 +463,19 @@ public void init(FMLInitializationEvent e) { proxy.init(); proxy.registerParticles(); + PacketDispatcher.registerPackets(); + MinecraftForge.EVENT_BUS.register(new ModEventHandler()); + AvatarTriggers.init(); } + public static void reloadConfig() { +// Configuration config = new Configuration(new File(proxy.getDataDir().getPath() + "/config/hbm/hbm.cfg")); +// config.load(); +// config.save(); + } + @EventHandler public void postInit(FMLPostInitializationEvent e) { AvatarAnalytics.INSTANCE.init(); @@ -438,10 +488,9 @@ public void postInit(FMLPostInitializationEvent e) { mat.rotate(90, 1, 0, 0); Vector4f v = new Vector4f(2, 1, 1, 1).mul(mat); } - //Allows for BendingContext shenanigans Abilities.all().forEach(Ability::postInit); - + proxy.postInit(e); } @EventHandler diff --git a/src/main/java/com/crowsofwar/avatar/bending/bending/lightning/LightningChargeHandler.java b/src/main/java/com/crowsofwar/avatar/bending/bending/lightning/LightningChargeHandler.java index a92942312e..6ed7781375 100644 --- a/src/main/java/com/crowsofwar/avatar/bending/bending/lightning/LightningChargeHandler.java +++ b/src/main/java/com/crowsofwar/avatar/bending/bending/lightning/LightningChargeHandler.java @@ -1,6 +1,7 @@ package com.crowsofwar.avatar.bending.bending.lightning; import com.crowsofwar.avatar.client.particle.AvatarParticles; +import com.crowsofwar.avatar.client.render.lightning.main.*; import com.crowsofwar.avatar.util.data.AbilityData; import com.crowsofwar.avatar.util.data.BendingData; import com.crowsofwar.avatar.util.data.TickHandler; @@ -9,14 +10,21 @@ import com.crowsofwar.avatar.client.particle.NetworkParticleSpawner; import com.crowsofwar.avatar.client.particle.ParticleSpawner; import com.crowsofwar.gorecore.util.Vector; +import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.ai.attributes.IAttributeInstance; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.SoundCategory; import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import net.minecraftforge.fml.common.network.NetworkRegistry; import javax.annotation.Nullable; import java.util.UUID; @@ -60,53 +68,149 @@ public boolean tick(BendingContext ctx) { int duration = data.getTickHandlerDuration(this); - float movementMultiplier = 0.6f - 0.7f * MathHelper.sqrt(duration / 40f); - applyMovementModifier(entity, MathHelper.clamp(movementMultiplier, 0.1f, 1)); - double inverseRadius = (40F - duration) / 10; - - if (duration % 3 == 0) { - for (int i = 0; i < 8; i++) { - Vector lookpos = Vector.toRectangular(Math.toRadians(entity.rotationYaw + - i * 45), 0).times(inverseRadius).withY(entity.getEyeHeight() / 2); - particleSpawner.spawnParticles(world, AvatarParticles.getParticleElectricity(), 1, 2, lookpos.x() + entity.posX, - lookpos.y() + entity.getEntityBoundingBox().minY, lookpos.z() + entity.posZ, 2, 1.2, 2, true); - } - } - - if (duration >= 40) { - - AbilityData abilityData = getLightningData(ctx); - if (abilityData == null) { - return true; - } - - double speed = abilityData.getLevel() >= 1 ? 30 : 40; - float damage = abilityData.getLevel() >= 2 ? 8 : 6; - float size = 1; - float[] turbulenceValues = { 0.6f, 1.2f }; - - if (abilityData.isMasterPath(AbilityData.AbilityTreePath.FIRST)) { - damage = 12; - size = 0.75f; - turbulenceValues = new float[] { 0.6f, 1.2f, 0.8f }; + EntityPlayer player = (EntityPlayer) entity; + + if(!player.world.isRemote) { + NBTTagCompound perDat = player.getEntityData().getCompoundTag(EntityPlayer.PERSISTED_NBT_TAG); + int lightning = perDat.getInteger("lightningCharge"); + if(lightning > 0){ + lightning ++; + if(lightning == 60){ + RayTraceResult r = Library.rayTraceIncludeEntities(player, 100, 1); + if(r != null && r.typeOfHit != RayTraceResult.Type.MISS){ + NBTTagCompound tag = new NBTTagCompound(); + tag.setString("type", "lightning"); + tag.setString("mode", "beam"); + tag.setDouble("hitX", r.hitVec.x); + tag.setDouble("hitY", r.hitVec.y); + tag.setDouble("hitZ", r.hitVec.z); + Vec3d normal = new Vec3d(r.sideHit.getXOffset(), r.sideHit.getYOffset(), r.sideHit.getZOffset()); + tag.setDouble("normX", normal.x); + tag.setDouble("normY", normal.y); + tag.setDouble("normZ", normal.z); + if(r.typeOfHit == RayTraceResult.Type.ENTITY){ + r.entityHit.attackEntityFrom(ModDamageSource.electricity, 20); + if(r.entityHit instanceof EntityLiving && ((EntityLiving)r.entityHit).getHealth() <= 0){ + r.entityHit.setDead(); + PacketDispatcher.wrapper.sendToAllTracking(new PacketSpecialDeath(r.entityHit, 2, (float)player.getLookVec().x, (float)player.getLookVec().y, (float)player.getLookVec().z), new NetworkRegistry.TargetPoint(player.world.provider.getDimension(), r.entityHit.posX, r.entityHit.posY, r.entityHit.posZ, 0)); + } + tag.setInteger("hitType", 1); + } else if(r.typeOfHit == RayTraceResult.Type.BLOCK){ + tag.setInteger("hitType", 0); + } + Vec3d direction = player.getLookVec().scale(0.75); + switch(r.sideHit.getAxis()){ + case X: + direction = new Vec3d(-direction.x, direction.y, direction.z); + break; + case Y: + direction = new Vec3d(direction.x, -direction.y, direction.z); + break; + case Z: + direction = new Vec3d(direction.x, direction.y, -direction.z); + break; + } + NBTTagCompound tag2 = new NBTTagCompound(); + tag2.setString("type", "spark"); + tag2.setString("mode", "coneBurst"); + tag2.setDouble("posX", r.hitVec.x); + tag2.setDouble("posY", r.hitVec.y); + tag2.setDouble("posZ", r.hitVec.z); + tag2.setDouble("dirX", direction.x); + tag2.setDouble("dirY", direction.y); + tag2.setDouble("dirZ", direction.z); + tag2.setFloat("r", 0.4F); + tag2.setFloat("g", 0.8F); + tag2.setFloat("b", 0.9F); + tag2.setFloat("a", 2F); + tag2.setInteger("lifetime", 5); + tag2.setInteger("randLifetime", 20); + tag2.setFloat("width", 0.04F); + tag2.setFloat("length", 0.7F); + tag2.setFloat("randLength", 1.5F); + tag2.setFloat("gravity", 0.1F); + tag2.setFloat("angle", 80F); + tag2.setInteger("count", 60+player.world.rand.nextInt(20)); + tag2.setFloat("randomVelocity", 0.4F); + PacketDispatcher.wrapper.sendToAllTracking(new AuxParticlePacketNT(tag2, r.hitVec.x, r.hitVec.y, r.hitVec.z), new NetworkRegistry.TargetPoint(player.world.provider.getDimension(), player.posX, player.posY, player.posZ, 0)); + Vec3d ssgChainPos = new Vec3d(-0.18, -0.1, 0.35); + ssgChainPos = ssgChainPos.rotatePitch((float) Math.toRadians(-player.rotationPitch)); + ssgChainPos = ssgChainPos.rotateYaw((float) Math.toRadians(-player.rotationYaw)); + ssgChainPos = ssgChainPos.add(player.posX, player.posY + player.getEyeHeight(), player.posZ); + PacketDispatcher.wrapper.sendToAllTracking(new AuxParticlePacketNT(tag, ssgChainPos.x, ssgChainPos.y, ssgChainPos.z), new NetworkRegistry.TargetPoint(player.world.provider.getDimension(), player.posX, player.posY, player.posZ, 0)); + } else { + NBTTagCompound tag = new NBTTagCompound(); + tag.setString("type", "lightning"); + tag.setString("mode", "beam"); + Vec3d hit = player.getPositionEyes(1).add(player.getLookVec().scale(100)); + tag.setDouble("hitX", hit.x); + tag.setDouble("hitY", hit.y); + tag.setDouble("hitZ", hit.z); + tag.setInteger("hitType", -1); + + Vec3d ssgChainPos = new Vec3d(-0.18, -0.1, 0.35); + ssgChainPos = ssgChainPos.rotatePitch((float) Math.toRadians(-player.rotationPitch)); + ssgChainPos = ssgChainPos.rotateYaw((float) Math.toRadians(-player.rotationYaw)); + ssgChainPos = ssgChainPos.add(player.posX, player.posY + player.getEyeHeight(), player.posZ); + + PacketDispatcher.wrapper.sendToAllTracking(new AuxParticlePacketNT(tag, ssgChainPos.x, ssgChainPos.y, ssgChainPos.z), new NetworkRegistry.TargetPoint(player.world.provider.getDimension(), player.posX, player.posY, player.posZ, 0)); + } + } + if(lightning == 84){ + lightning = 0; + } } - if (abilityData.isMasterPath(AbilityData.AbilityTreePath.SECOND)) { - size = 1.5f; - } - - speed += powerRating / 15; - damage *= ctx.getBender().getDamageMult(Lightningbending.ID); - - fireLightning(world, entity, damage, speed, size, turbulenceValues); - - entity.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).removeModifier(MOVEMENT_MODIFIER_ID); - - world.playSound(null, entity.posX, entity.posY, entity.posZ, SoundEvents.ENTITY_GENERIC_EXPLODE, SoundCategory.PLAYERS, 1, 2); - + perDat.setInteger("lightningCharge", lightning); return true; - } +// float movementMultiplier = 0.6f - 0.7f * MathHelper.sqrt(duration / 40f); +// applyMovementModifier(entity, MathHelper.clamp(movementMultiplier, 0.1f, 1)); +// double inverseRadius = (40F - duration) / 10; + +// if (duration % 3 == 0) { +// for (int i = 0; i < 8; i++) { +// Vector lookpos = Vector.toRectangular(Math.toRadians(entity.rotationYaw + +// i * 45), 0).times(inverseRadius).withY(entity.getEyeHeight() / 2); +// particleSpawner.spawnParticles(world, AvatarParticles.getParticleElectricity(), 1, 2, lookpos.x() + entity.posX, +// lookpos.y() + entity.getEntityBoundingBox().minY, lookpos.z() + entity.posZ, 2, 1.2, 2, true); +// } +// } + +// if (duration >= 40) { +// +// AbilityData abilityData = getLightningData(ctx); +// if (abilityData == null) { +// return true; +// } +// +// double speed = abilityData.getLevel() >= 1 ? 30 : 40; +// float damage = abilityData.getLevel() >= 2 ? 8 : 6; +// float size = 1; +// float[] turbulenceValues = { 0.6f, 1.2f }; +// +// if (abilityData.isMasterPath(AbilityData.AbilityTreePath.FIRST)) { +// damage = 12; +// size = 0.75f; +// turbulenceValues = new float[] { 0.6f, 1.2f, 0.8f }; +// } +// if (abilityData.isMasterPath(AbilityData.AbilityTreePath.SECOND)) { +// size = 1.5f; +// } +// +// speed += powerRating / 15; +// damage *= ctx.getBender().getDamageMult(Lightningbending.ID); +// +// fireLightning(world, entity, damage, speed, size, turbulenceValues); +// +// entity.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).removeModifier(MOVEMENT_MODIFIER_ID); +// +// world.playSound(null, entity.posX, entity.posY, entity.posZ, SoundEvents.ENTITY_GENERIC_EXPLODE, SoundCategory.PLAYERS, 1, 2); +// +// return true; +// +// } + return false; } diff --git a/src/main/java/com/crowsofwar/avatar/client/particles/newparticles/ParticleLightning2.java b/src/main/java/com/crowsofwar/avatar/client/particles/newparticles/ParticleLightning2.java new file mode 100644 index 0000000000..7a45f52fef --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/particles/newparticles/ParticleLightning2.java @@ -0,0 +1,142 @@ +package com.crowsofwar.avatar.client.particles.newparticles; + +import com.crowsofwar.avatar.client.render.lightning.main.ResourceManager; +import com.crowsofwar.avatar.client.render.lightning.math.Vec3; +import com.crowsofwar.avatar.client.render.lightning.render.RenderHelper; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.GlStateManager.DestFactor; +import net.minecraft.client.renderer.GlStateManager.SourceFactor; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import org.apache.commons.lang3.ArrayUtils; +import org.lwjgl.opengl.GL11; + +public class ParticleLightning2 extends ParticleAvatar { + + public int divisions = 7; + public Vec3 direction = Vec3.createVectorHelper(0, -40, 0); + private float[] positions; + + public ParticleLightning2(World worldIn, double posXIn, double posYIn, double posZIn) { + super(worldIn, posXIn, posYIn, posZIn); + this.canCollide = false; + this.particleMaxAge = 60; + this.particleScale = 20F; + regenerateLightning(); + } + + @Override + public void onUpdate() { + this.particleAge++; + if(this.particleAge >= this.particleMaxAge){ + this.setExpired(); + } + } + + public void regenerateLightning(){ + positions = new float[(divisions+2)*3]; + for(int i = 0; i < positions.length; i += 3){ + float magnitude = (i/3)/(divisions+1F); + Vec3 pos = direction.mult(magnitude); + positions[i] = (float) pos.xCoord; + positions[i+1] = (float) pos.yCoord; + positions[i+2] = (float) pos.zCoord; + } + + for(int i = 3; i < positions.length-3; i += 3){ + Vec3 randPos = Vec3.createVectorHelper((world.rand.nextDouble()-0.5)*4, (rand.nextDouble()-0.5)*2, (rand.nextDouble()-0.5)*4); + positions[i] += randPos.xCoord; + positions[i+1] += randPos.yCoord; + positions[i+2] += randPos.zCoord; + } + } + + @Override + public int getFXLayer() { + return 3; + } + + @Override + public void renderParticle(BufferBuilder buffer, Entity entity, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) { + GL11.glPushMatrix(); + + double d0 = this.prevPosX + (this.posX - this.prevPosX) * (double) partialTicks; + double d1 = this.prevPosY + (this.posY - this.prevPosY) * (double) partialTicks; + double d2 = this.prevPosZ + (this.posZ - this.prevPosZ) * (double) partialTicks; + + double d3 = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * (double) partialTicks; + double d4 = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * (double) partialTicks; + double d5 = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * (double) partialTicks; + + GL11.glTranslated(d0 - d3, d1 - d4, d2 - d5); + + float[] vertices = new float[positions.length*2]; + + Vec3d look = entity.getPositionEyes(partialTicks).subtract(d0, d1, d2); + for(int i = 0; i < positions.length-3; i += 3){ + //Vec3 toNextSegment = Vec3.createVectorHelper(positions[i+3], positions[i+4], positions[i+5]).subtract(Vec3.createVectorHelper(positions[i], positions[i+1], positions[i+2])); + Vec3 point1 = Vec3.createVectorHelper(look.x, look.y, look.z).crossProduct(direction).normalize().mult((float) (0.2*particleScale)); + Vec3 point2 = point1.mult(-1); + + vertices[i*2] = (float) point1.xCoord + positions[i]; + vertices[i*2+1] = (float) point1.yCoord + positions[i+1]; + vertices[i*2+2] = (float) point1.zCoord + positions[i+2]; + vertices[i*2+3] = (float) point2.xCoord + positions[i]; + vertices[i*2+4] = (float) point2.yCoord + positions[i+1]; + vertices[i*2+5] = (float) point2.zCoord + positions[i+2]; + + if(i == positions.length - 6){ + int i2 = i + 3; + vertices[i2*2] = (float) point1.xCoord + positions[i2]; + vertices[i2*2+1] = (float) point1.yCoord + positions[i2+1]; + vertices[i2*2+2] = (float) point1.zCoord + positions[i2+2]; + vertices[i2*2+3] = (float) point2.xCoord + positions[i2]; + vertices[i2*2+4] = (float) point2.yCoord + positions[i2+1]; + vertices[i2*2+5] = (float) point2.zCoord + positions[i2+2]; + } + } + + RenderHelper.bindTexture(ResourceManager.bfg_core_lightning); + + GlStateManager.disableCull(); + GlStateManager.enableBlend(); + GlStateManager.depthMask(false); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + + Tessellator tes = Tessellator.getInstance(); + BufferBuilder buf = tes.getBuffer(); + + buf.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + float[] prevPositions = ArrayUtils.subarray(vertices, 0, 6); + + float uStep = 1/(divisions + 1F); + for(int i = 6; i < vertices.length; i += 6){ + float u = (i/6-1)*uStep; + float u2 = u + uStep; + buf.pos(prevPositions[0], prevPositions[1], prevPositions[2]).tex(u, 0).endVertex(); + buf.pos(prevPositions[3], prevPositions[4], prevPositions[5]).tex(u, 1).endVertex(); + buf.pos(vertices[i+3], vertices[i+4], vertices[i+5]).tex(u2, 1).endVertex(); + buf.pos(vertices[i], vertices[i+1], vertices[i+2]).tex(u2, 0).endVertex(); + + prevPositions = ArrayUtils.subarray(vertices, i, i+6); + } + + tes.draw(); + + GlStateManager.enableCull(); + GlStateManager.disableBlend(); + GlStateManager.depthMask(true); + + GL11.glPopMatrix(); + } + + +} diff --git a/src/main/java/com/crowsofwar/avatar/client/particles/newparticles/ParticleLightningFade.java b/src/main/java/com/crowsofwar/avatar/client/particles/newparticles/ParticleLightningFade.java new file mode 100644 index 0000000000..0c200117a7 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/particles/newparticles/ParticleLightningFade.java @@ -0,0 +1,92 @@ +package com.crowsofwar.avatar.client.particles.newparticles; + +import com.crowsofwar.avatar.client.render.lightning.handler.HbmShaderManager2; +import com.crowsofwar.avatar.client.render.lightning.handler.LightningGenerator; +import com.crowsofwar.avatar.client.render.lightning.main.ResourceManager; +import com.crowsofwar.avatar.client.render.lightning.render.TrailRenderer2; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.GlStateManager.DestFactor; +import net.minecraft.client.renderer.GlStateManager.SourceFactor; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import org.lwjgl.opengl.GL11; + +public class ParticleLightningFade extends ParticleAvatar { + + float width; + LightningGenerator.LightningNode node; + + public ParticleLightningFade(World worldIn, double posXIn, double posYIn, double posZIn, double hitX, double hitY, double hitZ, float width, LightningGenerator.LightningGenInfo i) { + super(worldIn, posXIn, posYIn, posZIn); + node = LightningGenerator.generateLightning(new Vec3d(posXIn, posYIn, posZIn), new Vec3d(hitX, hitY, hitZ), i); + this.particleMaxAge = 60; + this.width = width; + } + + @Override + public void onUpdate() { + this.particleAge ++; + if(this.particleAge > this.particleMaxAge){ + this.setExpired(); + } + } + + @Override + public boolean shouldDisableDepth() { + return true; + } + + @Override + public int getFXLayer() { + return 3; + } + + @Override + public void renderParticle(BufferBuilder buffer, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) { + GL11.glPushMatrix(); + GlStateManager.disableCull(); + GlStateManager.disableAlpha(); + GlStateManager.depthMask(false); + double entPosX = entityIn.lastTickPosX + (entityIn.posX - entityIn.lastTickPosX)*partialTicks; + double entPosY = entityIn.lastTickPosY + (entityIn.posY - entityIn.lastTickPosY)*partialTicks; + double entPosZ = entityIn.lastTickPosZ + (entityIn.posZ - entityIn.lastTickPosZ)*partialTicks; + + interpPosX = entPosX; + interpPosY = entPosY; + interpPosZ = entPosZ; + + GL11.glTranslated(-interpPosX, -interpPosY, -interpPosZ); + + ResourceManager.lightning.use(); + ResourceManager.lightning.uniform4f("duck", 1F, 1F, 1F, 1F); + float ageN = ((float)this.particleAge+partialTicks)/((float)this.particleMaxAge); + ResourceManager.lightning.uniform1f("fadeoverride", ageN); + //ResourceManager.test_trail.use(); + //GL20.glUniform4f(GL20.glGetUniformLocation(ResourceManager.test_trail.getShaderId(), "duck"), 1F, 1, 1F, 1F); + TrailRenderer2.IColorGetter cg = pos -> { + float a = MathHelper.clamp((1-pos)-0.5F+ageN*50, 0, 1); + return new float[]{1, 1, 1, a}; + }; + GlStateManager.enableBlend(); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE); + LightningGenerator.render(node, new Vec3d(entPosX, entPosY+entityIn.getEyeHeight(), entPosZ), width, 0, 0, 0, true, cg); + HbmShaderManager2.bloomData.bindFramebuffer(false); + //GL20.glUniform4f(GL20.glGetUniformLocation(ResourceManager.test_trail.getShaderId(), "duck"), 0.6F, 0.8F, 1F, 1F); + ResourceManager.lightning.uniform4f("duck", 0.6F, 0.8F, 1F, 1F); + + LightningGenerator.render(node, new Vec3d(entPosX, entPosY+entityIn.getEyeHeight(), entPosZ), width, 0, 0, 0, true, cg); + LightningGenerator.render(node, new Vec3d(entPosX, entPosY+entityIn.getEyeHeight(), entPosZ), width, 0, 0, 0, true, cg); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); + GlStateManager.disableBlend(); + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + HbmShaderManager2.releaseShader(); + GlStateManager.depthMask(true); + GlStateManager.enableAlpha(); + GL11.glPopMatrix(); + } +} diff --git a/src/main/java/com/crowsofwar/avatar/client/particles/newparticles/ParticleLightningGib.java b/src/main/java/com/crowsofwar/avatar/client/particles/newparticles/ParticleLightningGib.java new file mode 100644 index 0000000000..2944ba8f0d --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/particles/newparticles/ParticleLightningGib.java @@ -0,0 +1,277 @@ +package com.crowsofwar.avatar.client.particles.newparticles; + +import com.crowsofwar.avatar.client.render.lightning.handler.HbmShaderManager2; +import com.crowsofwar.avatar.client.render.lightning.main.ResourceManager; +import com.crowsofwar.avatar.client.render.lightning.math.BobMathUtil; +import com.crowsofwar.avatar.network.AvatarClientProxy; +import net.minecraft.client.Minecraft; +import net.minecraft.client.model.ModelBox; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.GlStateManager.DestFactor; +import net.minecraft.client.renderer.GlStateManager.SourceFactor; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.entity.Entity; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import org.lwjgl.opengl.GL11; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class ParticleLightningGib extends ParticleAvatar { + + ModelBox box; + int dl = -1; + float[] matrix; + //float[] invRot = new float[16]; + List subParticles = new ArrayList<>(); + ParticleLightningStrip[] trails; + Vec3d rotation; + float rotX, rotY, rotZ, prevRotX, prevRotY, prevRotZ = 0; + ResourceLocation tex; + float cubeMidX, cubeMidY, cubeMidZ; + int numParticles; + float boxScale; + + public ParticleLightningGib(World worldIn, double posXIn, double posYIn, double posZIn, ModelBox box, float[] matrix, ResourceLocation tex, float cubeMidX, float cubeMidY, float cubeMidZ, float scale, int trailNum) { + super(worldIn, posXIn, posYIn, posZIn); + this.box = box; + this.matrix = matrix; + /*Matrix4f mat = new Matrix4f(); + AUX_GL_BUFFER.put(matrix); + AUX_GL_BUFFER.rewind(); + mat.load(AUX_GL_BUFFER); + AUX_GL_BUFFER.rewind(); + mat.invert(); + mat.store(AUX_GL_BUFFER); + AUX_GL_BUFFER.rewind(); + AUX_GL_BUFFER.get(invRot); + AUX_GL_BUFFER.rewind(); + invRot[12] = 0; + invRot[13] = 0; + invRot[14] = 0; + invRot[15] = 1;*/ + rotation = new Vec3d((worldIn.rand.nextFloat()-0.5)*50, (worldIn.rand.nextFloat()-0.5)*50, (worldIn.rand.nextFloat()-0.5)*50); + this.tex = tex; + this.particleMaxAge = 90; + this.cubeMidX = cubeMidX; + this.cubeMidY = cubeMidY; + this.cubeMidZ = cubeMidZ; + boxScale = scale; + numParticles = (int) Math.cbrt((Math.abs(box.posX1-box.posX2)*Math.abs(box.posY1-box.posY2)*Math.abs(box.posZ1-box.posZ2)*0.6))+1; + if(numParticles > 15) + numParticles = 15; + + trails = new ParticleLightningStrip[trailNum]; + for(int i = 0; i < trails.length; i ++){ + trails[i] = new ParticleLightningStrip(world, posX, posY, posZ); + trails[i].motionScaleNorm = 0.1F; + trails[i].motionScaleTan = 0.0F; + trails[i].forkChance = 0; + trails[i].minNewPointDist = 1; + trails[i].width = 0.025F; + trails[i].doTransform = true; + } + } + + public void motion(Vec3d motion){ + this.motionX = motion.x; + this.motionY = motion.y; + this.motionZ = motion.z; + } + + @Override + public void onUpdate() { + this.particleAge++; + this.prevPosX = this.posX; + this.prevPosY = this.posY; + this.prevPosZ = this.posZ; + prevRotX = rotX; + prevRotY = rotY; + prevRotZ = rotZ; + move(motionX, motionY, motionZ); + this.motionX *= onGround ? 0.85 : 0.9; + this.motionY *= onGround ? 0.85 : 0.9; + this.motionZ *= onGround ? 0.85 : 0.9; + if(particleAge >= particleMaxAge){ + this.setExpired(); + GL11.glDeleteLists(dl, 1); + return; + } + Iterator itr = subParticles.iterator(); + while(itr.hasNext()){ + Particle p = itr.next(); + p.onUpdate(); + if(!p.isAlive()) + itr.remove(); + } + for(ParticleLightningStrip p : trails){ + p.onUpdate(); + if(particleAge < 20) + p.setNewPoint(new Vec3d(this.posX+(rand.nextFloat()-0.5)*0.5, this.posY+(rand.nextFloat()-0.5)*0.5, this.posZ+(rand.nextFloat()-0.5)*0.5)); + } + rotX += rotation.x; + rotY += rotation.y; + rotZ += rotation.z; + rotation = rotation.scale(onGround ? 0.08 : 0.95); + motionY -= 0.05; + } + + @Override + public void move(double x, double y, double z) { + double d0 = y; + double origX = x; + double origZ = z; + + if (this.canCollide) + { + List list = this.world.getCollisionBoxes((Entity)null, this.getBoundingBox().expand(x, y, z)); + + for (AxisAlignedBB axisalignedbb : list) + { + y = axisalignedbb.calculateYOffset(this.getBoundingBox(), y); + } + + this.setBoundingBox(this.getBoundingBox().offset(0.0D, y, 0.0D)); + + for (AxisAlignedBB axisalignedbb1 : list) + { + x = axisalignedbb1.calculateXOffset(this.getBoundingBox(), x); + } + + this.setBoundingBox(this.getBoundingBox().offset(x, 0.0D, 0.0D)); + + for (AxisAlignedBB axisalignedbb2 : list) + { + z = axisalignedbb2.calculateZOffset(this.getBoundingBox(), z); + } + + this.setBoundingBox(this.getBoundingBox().offset(0.0D, 0.0D, z)); + } + else + { + this.setBoundingBox(this.getBoundingBox().offset(x, y, z)); + } + + this.resetPositionToBB(); + this.onGround = d0 != y && d0 < 0.0D; + + if(d0 != y){ + this.motionY = -motionY*0.75*(rand.nextFloat()*0.8+0.25); + } + + if (origX != x) + { + this.motionX = -motionX*0.75*(rand.nextFloat()*1.12+0.25); + } + + if (origZ != z) + { + this.motionZ = -motionY*0.75*(rand.nextFloat()*1.12+0.25); + } + } + + @Override + public boolean shouldDisableDepth() { + return true; + } + + @Override + public int getFXLayer() { + return 3; + } + + @Override + public void renderParticle(BufferBuilder buffer, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) { + AvatarClientProxy.deferredRenderers.add(() -> { + GL11.glPushMatrix(); + GlStateManager.enableLighting(); + GlStateManager.enableRescaleNormal(); + float f5 = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks - interpPosX); + float f6 = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY); + float f7 = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks - interpPosZ); + float rotateX = (float)(this.prevRotX + (this.rotX - this.prevRotX) * (double)partialTicks); + float rotateY = (float)(this.prevRotY + (this.rotY - this.prevRotY) * (double)partialTicks); + float rotateZ = (float)(this.prevRotZ + (this.rotZ - this.prevRotZ) * (double)partialTicks); + + GL11.glTranslated(f5, f6, f7); + Minecraft.getMinecraft().getTextureManager().bindTexture(tex); + if(dl == -1){ + dl = GL11.glGenLists(1); + GL11.glNewList(dl, GL11.GL_COMPILE); + //Moves it so the origin is in the middle. I hope this makes for slightly better rotations. + buffer.setTranslation(-cubeMidX, -cubeMidY, -cubeMidZ); + box.render(buffer, 0.0625F); + buffer.setTranslation(0, 0, 0); + GL11.glEndList(); + } + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, AvatarClientProxy.AUX_GL_BUFFER); + //Ah yes, spaghetti code. + AvatarClientProxy.AUX_GL_BUFFER2.put(matrix); + AvatarClientProxy.AUX_GL_BUFFER2.rewind(); + GL11.glMultMatrix(AvatarClientProxy.AUX_GL_BUFFER2); + GL11.glRotated(rotateX, 1, 0, 0); + GL11.glRotated(rotateY, 0, 1, 0); + GL11.glRotated(rotateZ, 0, 0, 1); + + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240); + RenderHelper.enableStandardItemLighting(); + GlStateManager.enableBlend(); + GlStateManager.alphaFunc(GL11.GL_GREATER, 0.001F); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); + float a = 1- BobMathUtil.remap01_clamp(particleAge+partialTicks, 65, 67); + GlStateManager.color(1F, 1F, 1F, a); + ResourceManager.lightning_gib.use(); + float age = this.particleAge + partialTicks; + ResourceManager.lightning_gib.uniform1f("age", age); + int i = this.getBrightnessForRender(partialTicks); + int j = i >> 16 & 65535; + int k = i & 65535; + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, k, j); + ResourceManager.lightning_gib.uniform1i("bloom", 0); + GL11.glCallList(dl); + HbmShaderManager2.bloomData.bindFramebuffer(false); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE); + ResourceManager.lightning_gib.uniform1i("bloom", 1); + GL11.glCallList(dl); + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + HbmShaderManager2.releaseShader(); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + RenderHelper.disableStandardItemLighting(); + //AUX_GL_BUFFER.put(invRot); + //AUX_GL_BUFFER.rewind(); + //GL11.glMultMatrix(AUX_GL_BUFFER); + //GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, AUX_GL_BUFFER); + //AUX_GL_BUFFER.rewind(); + //AUX_GL_BUFFER.put(matrix, 0, 12); + //AUX_GL_BUFFER.rewind(); + //GL11.glLoadMatrix(AUX_GL_BUFFER); + + + + Minecraft.getMinecraft().getTextureManager().bindTexture(ResourceManager.fresnel_ms); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + GlStateManager.depthMask(false); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE); + for(Particle p : subParticles){ + p.renderParticle(buffer, entityIn, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ); + } + GlStateManager.enableAlpha(); + GlStateManager.disableBlend(); + GlStateManager.depthMask(true); + + GlStateManager.disableRescaleNormal(); + GL11.glPopMatrix(); + for(ParticleLightningStrip p : trails){ + p.renderParticle(buffer, entityIn, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ); + } + }); + } + +} \ No newline at end of file diff --git a/src/main/java/com/crowsofwar/avatar/client/particles/newparticles/ParticleLightningHandGlow.java b/src/main/java/com/crowsofwar/avatar/client/particles/newparticles/ParticleLightningHandGlow.java new file mode 100644 index 0000000000..ab248d7b66 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/particles/newparticles/ParticleLightningHandGlow.java @@ -0,0 +1,100 @@ +package com.crowsofwar.avatar.client.particles.newparticles; + +import com.crowsofwar.avatar.client.render.lightning.main.ResourceManager; +import com.crowsofwar.avatar.network.AvatarClientProxy; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.GlStateManager.DestFactor; +import net.minecraft.client.renderer.GlStateManager.SourceFactor; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; +import org.lwjgl.opengl.GL11; + +public class ParticleLightningHandGlow extends ParticleAvatar { + + public ParticleLightningHandGlow(World worldIn, double posXIn, double posYIn, double posZIn, float scale, int age) { + super(worldIn, posXIn, posYIn, posZIn); + this.particleScale = scale; + this.particleMaxAge = age; + } + + public ParticleLightningHandGlow color(float r, float g, float b, float a){ + this.particleRed = r; + this.particleGreen = g; + this.particleBlue = b; + this.particleAlpha = a; + return this; + } + + @Override + public void onUpdate() { + this.particleAge ++; + if(particleAge >= particleMaxAge){ + setExpired(); + return; + } + } + + @Override + public int getFXLayer() { + return 3; + } + + @Override + public boolean shouldDisableDepth() { + return true; + } + + @Override + public void renderParticle(BufferBuilder buffer, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) { + GL11.glPushMatrix(); + GlStateManager.disableDepth(); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE); + GlStateManager.disableAlpha(); + + float f5 = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks); + float f6 = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks); + float f7 = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks); + GL11.glTranslated(f5, f6, f7); + + + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, AvatarClientProxy.AUX_GL_BUFFER); + AvatarClientProxy.AUX_GL_BUFFER.put(0, 1); + AvatarClientProxy.AUX_GL_BUFFER.put(1, 0); + AvatarClientProxy.AUX_GL_BUFFER.put(2, 0); + + AvatarClientProxy.AUX_GL_BUFFER.put(4, 0); + AvatarClientProxy.AUX_GL_BUFFER.put(5, 1); + AvatarClientProxy.AUX_GL_BUFFER.put(6, 0); + + AvatarClientProxy.AUX_GL_BUFFER.put(8, 0); + AvatarClientProxy.AUX_GL_BUFFER.put(9, 0); + AvatarClientProxy.AUX_GL_BUFFER.put(10, 1); + + GL11.glLoadMatrix(AvatarClientProxy.AUX_GL_BUFFER); + + + float ageN = (float)(this.particleAge+partialTicks)/(float)this.particleMaxAge; + float scale = MathHelper.clamp(ageN*2, 0, 1)* MathHelper.clamp(2-ageN*2+0.1F, 0, 1); + float f4 = 0.1F * this.particleScale * scale; + + Minecraft.getMinecraft().getTextureManager().bindTexture(ResourceManager.fresnel_ms); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP); + buffer.pos(f4, f4, 0).tex(1, 1).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(240, 240).endVertex(); + buffer.pos(-f4, f4, 0).tex(1, 0).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(240, 240).endVertex(); + buffer.pos(-f4, -f4, 0).tex(0, 0).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(240, 240).endVertex(); + buffer.pos(f4, -f4, 0).tex(0, 1).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(240, 240).endVertex(); + Tessellator.getInstance().draw(); + + GlStateManager.enableAlpha(); + GlStateManager.disableBlend(); + GlStateManager.enableDepth(); + GL11.glPopMatrix(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/crowsofwar/avatar/client/particles/newparticles/ParticleLightningStrip.java b/src/main/java/com/crowsofwar/avatar/client/particles/newparticles/ParticleLightningStrip.java new file mode 100644 index 0000000000..8a426e9789 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/particles/newparticles/ParticleLightningStrip.java @@ -0,0 +1,305 @@ +package com.crowsofwar.avatar.client.particles.newparticles; + +import java.util.ArrayList; +import java.util.List; + +import com.crowsofwar.avatar.client.render.lightning.handler.HbmShaderManager2; +import com.crowsofwar.avatar.client.render.lightning.main.ResourceManager; +import com.crowsofwar.avatar.client.render.lightning.math.BobMathUtil; +import com.crowsofwar.avatar.client.render.lightning.render.TrailRenderer2; +import com.crowsofwar.avatar.client.render.lightning.handler.LightningGenerator; +import com.crowsofwar.avatar.client.render.lightning.handler.LightningGenerator.LightningGenInfo; +import com.crowsofwar.avatar.client.render.lightning.handler.LightningGenerator.LightningNode; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import org.lwjgl.opengl.GL11; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.GlStateManager.DestFactor; +import net.minecraft.client.renderer.GlStateManager.SourceFactor; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class ParticleLightningStrip extends ParticleTargeted { + + /** + * Half the width of the outermost layer. + */ + private static final float THICKNESS = 0.04f; + /** + * Maximum length of a segment. + */ + private static final double MAX_SEGMENT_LENGTH = 0.6; + /** + * Minimum length of a segment. + */ + private static final double MIN_SEGMENT_LENGTH = 0.2; + /** + * Maximum deviation (in x or y, as drawn before transformations) from the centreline. + */ + private static final double VERTEX_JITTER = 0.15; + /** + * Maximum number of segments a fork can have before ending. + */ + private static final int MAX_FORK_SEGMENTS = 3; + /** + * Probability (as a fraction) that a vertex will have a fork. + */ + private static final float FORK_CHANCE = 0.3f; + /** + * Number of ticks to wait before the arc changes shape again. + */ + private static final int UPDATE_PERIOD = 1; + + public List points = new ArrayList<>(); + public float forkChance = 0.2F; + public float minNewPointDist = 0.1F; + public float motionScaleTan = 0.03F; + public float motionScaleNorm = 0.01F; + public float width = 0.004F; + public boolean doTransform = false; + + public ParticleLightningStrip(World worldIn, double posXIn, double posYIn, double posZIn) { + super(worldIn, posXIn, posYIn, posZIn); + this.particleMaxAge = 122; + } + + public void setNewPoint(Vec3d point){ + float scale = 0.01F; + float scale2 = 0.002F; + Vec3d pos = point.add((world.rand.nextFloat()*2-1)*scale, (world.rand.nextFloat()*2-1)*scale, (world.rand.nextFloat()*2-1)*scale); + Vec3d motion = new Vec3d((world.rand.nextFloat()*2-1)*scale2, (world.rand.nextFloat()*2-1)*scale2, (world.rand.nextFloat()*2-1)*scale2); + LightningNode fork = null; + if(points.size() >= 1){ + Vec3d direction = point.subtract(points.get(points.size()-1).ogPos); + double dot = direction.dotProduct(pos.subtract(points.get(points.size()-1).ogPos)); + Vec3d project = direction.scale(dot/direction.lengthSquared()); + direction = direction.normalize(); + motion = motion.add(pos.subtract(project).normalize().scale(motionScaleTan)).add(direction.scale(motionScaleNorm)); + if(world.rand.nextFloat() < forkChance){ + LightningGenInfo i = new LightningGenInfo(); + i.randAmount = 0.03F; + i.subdivisions = 3; + i.subdivRecurse = 1; + i.forkChance = 0.1F; + fork = LightningGenerator.generateLightning(new Vec3d(0, 0, 0), BobMathUtil.randVecInCone(direction, 20).scale(-0.3F), i); + } + } + LightningPoint lPoint = new LightningPoint(point, pos, motion); + + lPoint.fork = fork; + points.add(lPoint); + if(points.size() >= 3 && points.get(points.size()-3).pos.squareDistanceTo(point) < minNewPointDist*minNewPointDist){ + points.remove(points.size()-2); + } + } + + @Override + public void onUpdate() { + this.particleAge ++; + if(this.particleAge > this.particleMaxAge){ + this.setExpired(); + } + for(LightningPoint p : points){ + p.prevPos = p.pos; + p.pos = p.pos.add(p.motion); + p.motion = p.motion.scale(0.96); + } + } + + @Override + public void renderParticle(BufferBuilder buffer, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) { + if(points.size() >= 2){ + if(doTransform){ + GL11.glPushMatrix(); + GL11.glTranslated(-interpPosX, -interpPosY, -interpPosZ); + } + GlStateManager.enableBlend(); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE); + ResourceManager.lightning.use(); + ResourceManager.lightning.uniform4f("duck", 1F, 1F, 1F, 1F); + ResourceManager.lightning.uniform1f("age", this.particleAge+partialTicks); + int list = GL11.glGenLists(1); + GL11.glNewList(list, GL11.GL_COMPILE); + float time = (this.particleAge+partialTicks)*0.012F; + List currentPoints = new ArrayList<>(points.size()); + for(int i = 0; i < points.size(); i++){ + LightningPoint p = points.get(i); + Vec3d pos = BobMathUtil.lerp(p.prevPos, p.pos, partialTicks); + float override = (float)(i)/(float)points.size(); + + override = 1-MathHelper.clamp(override-time*time*time, 0.001F, 1F); + ResourceManager.lightning.uniform1f("fadeoverride", override); + if(p.fork != null){ + if(doTransform){ + LightningGenerator.render(p.fork, new Vec3d(interpPosX, interpPosY+entityIn.getEyeHeight(), interpPosZ), width*0.5F, (float)pos.x, (float)pos.y, (float)pos.z, false, null); + } else { + LightningGenerator.render(p.fork, new Vec3d(0, 0, 0), width*0.5F, (float)pos.x, (float)pos.y, (float)pos.z, false, null); + } + } + currentPoints.add(pos); + } + ResourceManager.lightning.uniform1f("fadeoverride", 1F); + ResourceManager.lightning.uniform1i("vertices", currentPoints.size()*3+2); + if(doTransform){ + TrailRenderer2.draw(new Vec3d(interpPosX, interpPosY+entityIn.getEyeHeight(), interpPosZ), currentPoints, width); + } else { + TrailRenderer2.draw(new Vec3d(0, 0, 0), currentPoints, width); + } + GL11.glEndList(); + GL11.glCallList(list); + HbmShaderManager2.bloomData.bindFramebuffer(false); + ResourceManager.lightning.uniform4f("duck", 0.6F, 0.8F, 1F, 1F); + GL11.glCallList(list); + GL11.glCallList(list); + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + GL11.glDeleteLists(list, 1); + HbmShaderManager2.releaseShader(); + GlStateManager.disableBlend(); + if(doTransform){ + GL11.glPopMatrix(); + } + } + } + + @Override + protected void draw(Tessellator tessellator, double length, float partialTicks) { +// GlStateManager.disableLighting(); +// GlStateManager.enableBlend(); +// GlStateManager.disableTexture2D(); +// GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE); +// OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); +// +// // The direction of the arc drawn by the tessellator is always along the z axis and is rotated to the +// // correct orientation, that way there isn't a ton of trigonometry and the code is way neater. +// +// boolean freeEnd = this.target == null; +// +// int numberOfSegments = (int) Math.round(length / MAX_SEGMENT_LENGTH); // Number of segments +// +// for (int layer = 0; layer < 3; layer++) { +// +// double px = 0, py = 0, pz = 0; +// // Creates a random from the arc's seed field + the number of ticks it has existed/the update period. +// // By using a seed, we can ensure the vertex positions and forks are identical a) for each layer, even +// // though they are rendered sequentially, and b) across many frames (and ticks, if updateTime > 1). +// random.setSeed(this.seed + this.particleAge / UPDATE_PERIOD); +// +// // numberOfSegments-1 because the last segment is handled separately. +// for (int i = 0; i < numberOfSegments - 1; i++) { +// +// double px2 = (random.nextDouble() * 2 - 1) * VERTEX_JITTER * particleScale; +// double py2 = (random.nextDouble() * 2 - 1) * VERTEX_JITTER * particleScale; +// double pz2 = pz + length / (double) numberOfSegments; // For now they are all the same length +// +// drawSegment(tessellator, layer, px, py, pz, px2, py2, pz2, THICKNESS * particleScale); +// +// // Forks +// if (random.nextFloat() < FORK_CHANCE) { +// +// double px3 = px, py3 = py, pz3 = pz; +// +// for (int j = 0; j < random.nextInt(MAX_FORK_SEGMENTS - 1) + 1; j++) { +// // Forks set their centreline to the x/y coordinates of the vertex they originate from +// double px4 = px3 + (random.nextDouble() * 2 - 1) * VERTEX_JITTER * particleScale; +// double py4 = py3 + (random.nextDouble() * 2 - 1) * VERTEX_JITTER * particleScale; +// double pz4 = pz3 + MIN_SEGMENT_LENGTH + random.nextDouble() * (MAX_SEGMENT_LENGTH - MIN_SEGMENT_LENGTH); +// +// drawSegment(tessellator, layer, px3, py3, pz3, px4, py4, pz4, THICKNESS * 0.8f * particleScale); +// +// // Forks of forks +// if (random.nextFloat() < FORK_CHANCE) { +// +// double px5 = px3 + (random.nextDouble() * 2 - 1) * VERTEX_JITTER * particleScale; +// double py5 = py3 + (random.nextDouble() * 2 - 1) * VERTEX_JITTER * particleScale; +// double pz5 = pz3 + MIN_SEGMENT_LENGTH + random.nextDouble() * (MAX_SEGMENT_LENGTH - MIN_SEGMENT_LENGTH); +// +// drawSegment(tessellator, layer, px3, py3, pz3, px5, py5, pz5, THICKNESS * 0.6f * particleScale); +// } +// +// px3 = px4; +// py3 = py4; +// pz3 = pz4; +// } +// } +// +// px = px2; +// py = py2; +// pz = pz2; +// } +// +// // Last segment has a specific end position and cannot fork. +// double px2 = freeEnd ? (random.nextDouble() * 2 - 1) * VERTEX_JITTER * particleScale : 0; +// double py2 = freeEnd ? (random.nextDouble() * 2 - 1) * VERTEX_JITTER * particleScale : 0; +// drawSegment(tessellator, layer, px, py, pz, px2, py2, length, THICKNESS * particleScale); +// +// } +// +// GlStateManager.enableTexture2D(); +// GlStateManager.enableLighting(); +// GlStateManager.disableBlend(); + } + + private void drawSegment(Tessellator tessellator, int layer, double x1, double y1, double z1, double x2, double y2, double z2, float thickness) { + + BufferBuilder buffer = tessellator.getBuffer(); + buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_COLOR); + + switch (layer) { + + case 0: + drawShearedBox(buffer, x1, y1, z1, x2, y2, z2, 0.25f * thickness, 1, 1, 1, 1); + break; + + case 1: + drawShearedBox(buffer, x1, y1, z1, x2, y2, z2, 0.6f * thickness, (particleRed + 1) / 2, (particleGreen + 1) / 2, + (particleBlue + 1) / 2, 0.65f); + break; + + case 2: + drawShearedBox(buffer, x1, y1, z1, x2, y2, z2, thickness, particleRed, particleGreen, particleBlue, 0.3f); + break; + } + + tessellator.draw(); + } + + /** + * Draws a single box for one segment of the arc, from the point (x1, y1, z1) to the point (x2, y2, z2), with given width and colour. + */ + private void drawShearedBox(BufferBuilder buffer, double x1, double y1, double z1, double x2, double y2, double z2, float width, float r, float g, float b, float a) { + + buffer.pos(x1 - width, y1 - width, z1).color(r, g, b, a).endVertex(); + buffer.pos(x2 - width, y2 - width, z2).color(r, g, b, a).endVertex(); + buffer.pos(x1 - width, y1 + width, z1).color(r, g, b, a).endVertex(); + buffer.pos(x2 - width, y2 + width, z2).color(r, g, b, a).endVertex(); + buffer.pos(x1 + width, y1 + width, z1).color(r, g, b, a).endVertex(); + buffer.pos(x2 + width, y2 + width, z2).color(r, g, b, a).endVertex(); + buffer.pos(x1 + width, y1 - width, z1).color(r, g, b, a).endVertex(); + buffer.pos(x2 + width, y2 - width, z2).color(r, g, b, a).endVertex(); + buffer.pos(x1 - width, y1 - width, z1).color(r, g, b, a).endVertex(); + buffer.pos(x2 - width, y2 - width, z2).color(r, g, b, a).endVertex(); + } + + + public static class LightningPoint { + Vec3d ogPos; + Vec3d pos; + Vec3d prevPos; + Vec3d motion; + LightningNode fork = null; + + public LightningPoint(Vec3d ogPos, Vec3d pos, Vec3d motion) { + this.ogPos = ogPos; + this.pos = pos; + this.prevPos = pos; + this.motion = motion; + } + } + +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/RenderLightningStripHbm.java b/src/main/java/com/crowsofwar/avatar/client/render/RenderLightningStripHbm.java new file mode 100644 index 0000000000..567c0b82d2 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/RenderLightningStripHbm.java @@ -0,0 +1,181 @@ +package com.crowsofwar.avatar.client.render; + +import com.crowsofwar.avatar.client.particles.newparticles.ParticleLightningHandGlow; +import com.crowsofwar.avatar.client.render.lightning.animloader.AnimationWrapper; +import com.crowsofwar.avatar.client.render.lightning.handler.HbmShaderManager2; +import com.crowsofwar.avatar.client.render.lightning.main.ResourceManager; +import com.crowsofwar.avatar.client.particles.newparticles.ParticleLightningStrip; +import com.crowsofwar.avatar.AvatarInfo; + +import com.crowsofwar.avatar.client.render.lightning.math.BobMathUtil; +import com.crowsofwar.avatar.client.render.lightning.render.Tessellator; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraftforge.client.event.RenderHandEvent; +import org.lwjgl.input.Keyboard; +import org.lwjgl.opengl.GL11; +import org.lwjgl.util.glu.Project; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraftforge.client.event.EntityViewRenderEvent.CameraSetup; +import net.minecraftforge.client.event.RenderWorldLastEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent.Phase; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import org.lwjgl.util.vector.Vector4f; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Random; + +/** + * This is a port of Drillgon200's implementation of HBM's nuclear mod + * with lightning particle animations. All relevant references to code + * and imports were placed in their respective packages based on their + * purpose. + * (i.e.: ParticleLightningStrip which extended Particle is located at + * com.crowsofwar.avatar.client.particles.newparticles + * and now extends ParticleAvatar) + * Any other relevant code was placed in its own package wholesale. + * Move, modify and rename it however you see fit! + + * Source Code Base: + + * @author Drillgon200, modified by jakeee51 + * @see com.crowsofwar.avatar.client.render.lightning Relevant Resources + * @since AvatarMod 1.6.0 + */ + +@SideOnly(Side.CLIENT) +@Mod.EventBusSubscriber(value = Side.CLIENT, modid = AvatarInfo.MOD_ID) +public class RenderLightningStripHbm { + + public static int ticksActive = -1; + private static long renderTime; + public static AnimationWrapper wrapper; + public static List lightning_strips = new ArrayList<>(); + public static List particles = new ArrayList<>(); + + @SubscribeEvent + public static void renderHand(RenderHandEvent e) { + if(ticksActive < 0) + return; + e.setCanceled(true); + HbmShaderManager2.postProcess(); + } + + @SubscribeEvent + public static void doDepthRender(CameraSetup e){ + if(Minecraft.getMinecraft().gameSettings.thirdPersonView != 0 || ticksActive < 0) + return; + + GlStateManager.matrixMode(GL11.GL_PROJECTION); + GL11.glPushMatrix(); + GL11.glLoadIdentity(); + Project.gluPerspective(70, (float) Minecraft.getMinecraft().displayWidth / (float) Minecraft.getMinecraft().displayHeight, 0.05F, Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16F * 2.0F); + GlStateManager.matrixMode(GL11.GL_MODELVIEW); + GL11.glLoadIdentity(); + GL11.glPushMatrix(); + + GL11.glTranslated(-0.3, 0, -2.25); + GL11.glRotated(90, 0, 1, 0); + + ResourceManager.lightning_fp.controller.setAnim(wrapper); + GlStateManager.colorMask(false, false, false, false); + ResourceManager.maxdepth.use(); + ResourceManager.lightning_fp.renderAnimated(renderTime = System.currentTimeMillis()); + HbmShaderManager2.releaseShader(); + GlStateManager.colorMask(true, true, true, true); + GL11.glPopMatrix(); + GlStateManager.matrixMode(GL11.GL_PROJECTION); + GL11.glPopMatrix(); + GlStateManager.matrixMode(GL11.GL_MODELVIEW); + } + + @SubscribeEvent + public static void doHandRendering(RenderWorldLastEvent e) { + if(Minecraft.getMinecraft().gameSettings.thirdPersonView != 0) + return; + + GlStateManager.clear(GL11.GL_DEPTH_BUFFER_BIT); + GlStateManager.matrixMode(GL11.GL_PROJECTION); + GL11.glPushMatrix(); + GL11.glLoadIdentity(); + Project.gluPerspective(70, (float) Minecraft.getMinecraft().displayWidth / (float) Minecraft.getMinecraft().displayHeight, 0.05F, Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16F * 2.0F); + GlStateManager.matrixMode(GL11.GL_MODELVIEW); + GL11.glLoadIdentity(); + GL11.glPushMatrix(); + + if(ticksActive >= 0){ + GL11.glPushMatrix(); + GL11.glTranslated(-0.3, 0, -2.25); + GL11.glRotated(90, 0, 1, 0); + + RenderHelper.enableStandardItemLighting(); + Minecraft.getMinecraft().getTextureManager().bindTexture(ResourceManager.skin); + ResourceManager.lightning_fp.controller.setAnim(wrapper); + ResourceManager.lightning_fp.renderAnimated(renderTime, (last, first, model, diffN, name) -> { + if(name.equals("lower")){ + if(ticksActive < 55) + for(ParticleLightningStrip p : lightning_strips){ + p.setNewPoint(BobMathUtil.viewFromLocal(new Vector4f(0.156664F, -0.60966F, -0.252432F, 1))[0]); + } + for(Particle p : particles){ + p.renderParticle(Tessellator.getInstance().getBuffer(), Minecraft.getMinecraft().getRenderViewEntity(), e.getPartialTicks(), 0, 0, 0, 0, 0); + } + } + return false; + }); + GL11.glPopMatrix(); + } + Minecraft.getMinecraft().getTextureManager().bindTexture(ResourceManager.turbofan_blades_tex); + for(ParticleLightningStrip p : lightning_strips){ + if(p != null) + p.renderParticle(Tessellator.getBuffer(), Minecraft.getMinecraft().getRenderViewEntity(), e.getPartialTicks(), 0, 0, 0, 0, 0); + } + + GL11.glPopMatrix(); + GlStateManager.matrixMode(GL11.GL_PROJECTION); + GL11.glPopMatrix(); + GlStateManager.matrixMode(GL11.GL_MODELVIEW); + } + + @SubscribeEvent + public static void worldTick(TickEvent.ClientTickEvent e){ + if(e.phase == Phase.END || Minecraft.getMinecraft().world == null) + return; + Random rand = Minecraft.getMinecraft().world.rand; + if(ticksActive >= 0){ + ticksActive ++; + if(ticksActive >= 84){ + ticksActive = -1; + } + particles.add(new ParticleLightningHandGlow(Minecraft.getMinecraft().world, 0.156664F, -0.60966F, -0.252432F, 2+rand.nextFloat()*0.5F, 3+rand.nextInt(3)).color(0.8F, 0.9F, 1F, 1F)); + } else if(Keyboard.isKeyDown(Keyboard.KEY_I)) { + ticksActive = 0; + wrapper = new AnimationWrapper(System.currentTimeMillis(), ResourceManager.lightning_fp_anim).onEnd(new AnimationWrapper.EndResult(AnimationWrapper.EndType.END, null)); + lightning_strips.clear(); + lightning_strips.add(new ParticleLightningStrip(Minecraft.getMinecraft().world, 0, 0, 0)); + lightning_strips.add(new ParticleLightningStrip(Minecraft.getMinecraft().world, 0, 0, 0)); + } + Iterator iter = lightning_strips.iterator(); + while(iter.hasNext()){ + Particle p = iter.next(); + p.onUpdate(); + if(!p.isAlive()) + iter.remove(); + } + Iterator iter2 = particles.iterator(); + while(iter2.hasNext()){ + Particle p = iter2.next(); + p.onUpdate(); + if(!p.isAlive()) + iter2.remove(); + } + } +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/animloader/AnimatedModel.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/animloader/AnimatedModel.java new file mode 100644 index 0000000000..e0a70bc194 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/animloader/AnimatedModel.java @@ -0,0 +1,153 @@ +package com.crowsofwar.avatar.client.render.lightning.animloader; + +import com.crowsofwar.avatar.client.render.lightning.math.BobMathUtil; +import com.crowsofwar.avatar.client.render.lightning.math.Transform; + +import net.minecraft.client.renderer.GLAllocation; +import net.minecraft.util.math.MathHelper; +import org.lwjgl.opengl.GL11; + +import java.nio.FloatBuffer; +import java.util.ArrayList; +import java.util.List; + +public class AnimatedModel { + + public static FloatBuffer auxGLMatrix = GLAllocation.createDirectFloatBuffer(16); + + //Pointless... + public AnimationController controller; + + public String name = ""; + + public float[] transform; + + boolean hasGeometry = true; + boolean hasTransform = false; + + public String geo_name = ""; + public AnimatedModel parent; + public List children = new ArrayList(); + int callList; + + public AnimatedModel() { + } + + public void renderAnimated(long sysTime) { + renderAnimated(sysTime, null); + } + + public void renderAnimated(long sysTime, IAnimatedModelCallback c) { + if(controller.activeAnim == AnimationWrapper.EMPTY) { + render(c); + return; + } + + AnimationWrapper activeAnim = controller.activeAnim; + int numKeyFrames = activeAnim.anim.numKeyFrames; + int diff = (int) (sysTime - activeAnim.startTime); + diff *= activeAnim.speedScale; + if(diff > activeAnim.anim.length) { + int diff2 = diff % activeAnim.anim.length; + switch(activeAnim.endResult.type) { + case END: + controller.activeAnim = AnimationWrapper.EMPTY; + render(c); + return; + case REPEAT: + activeAnim.startTime = sysTime - diff2; + break; + case REPEAT_REVERSE: + activeAnim.startTime = sysTime - diff2; + activeAnim.reverse = !activeAnim.reverse; + break; + case START_NEW: + activeAnim.cloneStats(activeAnim.endResult.next); + activeAnim.startTime = sysTime - diff2; + break; + case STAY: + activeAnim.startTime = sysTime - activeAnim.anim.length; + break; + } + } + diff = (int) (sysTime - activeAnim.startTime); + if(activeAnim.reverse) + diff = activeAnim.anim.length - diff; + diff *= activeAnim.speedScale; + float remappedTime = MathHelper.clamp(BobMathUtil.remap(diff, 0, activeAnim.anim.length, 0, numKeyFrames - 1), 0, numKeyFrames - 1); + float diffN = BobMathUtil.remap01_clamp(diff, 0, activeAnim.anim.length); + int index = (int) remappedTime; + int first = index; + int next; + if(index < numKeyFrames - 1) { + next = index + 1; + } else { + next = first; + } + + renderWithIndex((float) fract(remappedTime), first, next, diffN, c); + controller.activeAnim.prevFrame = first; + } + + protected void renderWithIndex(float inter, int firstIndex, int nextIndex, float diffN, IAnimatedModelCallback c) { + GL11.glPushMatrix(); + boolean hidden = false; + if(hasTransform) { + Transform[] transforms = controller.activeAnim.anim.objectTransforms.get(name); + if(transforms != null) { + hidden = transforms[firstIndex].hidden; + transforms[firstIndex].interpolateAndApply(transforms[nextIndex], inter); + } else { + auxGLMatrix.put(transform); + auxGLMatrix.rewind(); + GL11.glMultMatrix(auxGLMatrix); + } + } + if(c != null) + hidden |= c.onRender(controller.activeAnim.prevFrame, firstIndex, callList, diffN, name); + if(hasGeometry && !hidden) { + GL11.glCallList(callList); + } + if(c != null) + c.postRender(controller.activeAnim.prevFrame, firstIndex, callList, diffN, name); + for(AnimatedModel m : children) { + m.renderWithIndex(inter, firstIndex, nextIndex, diffN, c); + } + GL11.glPopMatrix(); + } + + public void render() { + render(null); + } + + public void render(IAnimatedModelCallback c) { + GL11.glPushMatrix(); + if(hasTransform) { + auxGLMatrix.put(transform); + auxGLMatrix.rewind(); + GL11.glMultMatrix(auxGLMatrix); + } + boolean hidden = false; + if(c != null) + hidden = c.onRender(-1, -1, callList, -1, name); + if(hasGeometry && !hidden) { + GL11.glCallList(callList); + } + if(c != null) + c.postRender(-1, -1, callList, -1, name); + for(AnimatedModel m : children) { + m.render(c); + } + GL11.glPopMatrix(); + } + + private static float fract(float number) { + return (float) (number - Math.floor(number)); + } + + public static interface IAnimatedModelCallback { + //(prevFrame, currentFrame, model, diffN, modelName) + public boolean onRender(int prevFrame, int currentFrame, int model, float diffN, String modelName); + public default void postRender(int prevFrame, int currentFrame, int model, float diffN, String modelName){}; + } +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/animloader/Animation.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/animloader/Animation.java new file mode 100644 index 0000000000..edcb1f6bc3 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/animloader/Animation.java @@ -0,0 +1,24 @@ +package com.crowsofwar.avatar.client.render.lightning.animloader; + +import com.crowsofwar.avatar.client.render.lightning.math.Transform; + +import java.util.HashMap; +import java.util.Map; + +public class Animation { + + public static final Animation EMPTY = createBlankAnimation(); + + public int length; + public int numKeyFrames; + public Map objectTransforms = new HashMap(); + + private static Animation createBlankAnimation(){ + Animation anim = new Animation(); + anim.numKeyFrames = 0; + anim.length = 0; + anim.objectTransforms = new HashMap(); + return anim; + } + +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/animloader/AnimationController.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/animloader/AnimationController.java new file mode 100644 index 0000000000..485a42d30f --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/animloader/AnimationController.java @@ -0,0 +1,22 @@ +package com.crowsofwar.avatar.client.render.lightning.animloader; + +public class AnimationController { + + //Drillgon200: You know what? I'm pretty sure this class is entirely pointless and just acts as a stupid getter/setter for the wrapper. + //TODO delete + + protected AnimationWrapper activeAnim = AnimationWrapper.EMPTY; + + public void setAnim(AnimationWrapper w) { + activeAnim = w; + } + + public void stopAnim() { + activeAnim = AnimationWrapper.EMPTY; + } + + public AnimationWrapper getAnim() { + return activeAnim; + } + +} \ No newline at end of file diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/animloader/AnimationWrapper.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/animloader/AnimationWrapper.java new file mode 100644 index 0000000000..29ad537dbe --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/animloader/AnimationWrapper.java @@ -0,0 +1,87 @@ +package com.crowsofwar.avatar.client.render.lightning.animloader; + +import javax.annotation.Nullable; + +public class AnimationWrapper { + + public static final AnimationWrapper EMPTY = new AnimationWrapper(Animation.EMPTY){ + public AnimationWrapper onEnd(EndResult res) { + return this; + }; + }; + + public Animation anim; + + public long startTime; + public float speedScale = 1; + public boolean reverse; + public EndResult endResult = EndResult.END; + public int prevFrame = 0; + + public AnimationWrapper(Animation a){ + this.anim = a; + this.startTime = System.currentTimeMillis(); + } + + public AnimationWrapper(long startTime, Animation a){ + this.anim = a; + this.startTime = startTime; + } + + public AnimationWrapper(long startTime, float scale, Animation a){ + this.anim = a; + this.speedScale = scale; + this.startTime = startTime; + } + + public AnimationWrapper onEnd(EndResult res){ + this.endResult = res; + return this; + } + + public AnimationWrapper reverse(){ + this.reverse = !reverse; + return this; + } + + public AnimationWrapper cloneStats(AnimationWrapper other){ + this.anim = other.anim; + this.startTime = other.startTime; + this.reverse = other.reverse; + this.endResult = other.endResult; + return this; + } + + public AnimationWrapper cloneStatsWithoutTime(AnimationWrapper other){ + this.anim = other.anim; + this.reverse = other.reverse; + this.endResult = other.endResult; + return this; + } + + public enum EndType { + END, + REPEAT, + REPEAT_REVERSE, + START_NEW, + STAY; + } + + public static class EndResult { + + public static final EndResult END = new EndResult(EndType.END, null); + + EndType type; + AnimationWrapper next; + + public EndResult(EndType type) { + this(type, null); + } + + public EndResult(EndType type, @Nullable AnimationWrapper next) { + this.type = type; + this.next = next; + } + + } +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/animloader/ColladaLoader.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/animloader/ColladaLoader.java new file mode 100644 index 0000000000..4f3e95202b --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/animloader/ColladaLoader.java @@ -0,0 +1,413 @@ +package com.crowsofwar.avatar.client.render.lightning.animloader; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import com.crowsofwar.avatar.AvatarMod; +import com.crowsofwar.avatar.client.render.lightning.math.Transform; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.logging.log4j.Level; +import org.lwjgl.opengl.GL11; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.resources.IResource; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class ColladaLoader { + //Drillgon200: This code is only slightly less terrible than the first time. I hate XML. + + /* + * My attempt at making a collada loader. + * Some things to note: You can't use child of constraints with it with complete accuracy, + * as this will break the linear interpolation and I don't know how to fix it + * To get around this, you can put multiple objects with different parents or origins and toggle their visibility. + * It's hacky, but it works, at least if you don't need an object affected by multiple bones at the same time. + */ + + public static AnimatedModel load(ResourceLocation file) { + return load(file, false); + } + + public static AnimatedModel load(ResourceLocation file, boolean flipV) { + IResource res; + try { + res = Minecraft.getMinecraft().getResourceManager().getResource(file); + Document doc; + try { + doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(res.getInputStream()); + return parse(doc.getDocumentElement(), flipV); + } catch(SAXException e) { + e.printStackTrace(); + } catch(IOException e) { + e.printStackTrace(); + } catch(ParserConfigurationException e) { + e.printStackTrace(); + } + } catch(IOException e) { + e.printStackTrace(); + } + AvatarMod.logger.log(Level.ERROR, "FAILED TO LOAD MODEL: " + file); + return null; + } + + //Model loading section + + private static AnimatedModel parse(Element root, boolean flipV){ + //Should get the first bone + Element scene = getFirstElement((Element)root.getElementsByTagName("library_visual_scenes").item(0)); + AnimatedModel structure = new AnimatedModel(){ + @Override + protected void renderWithIndex(float inter, int firstIndex, int nextIndex, float diffN, IAnimatedModelCallback c) { + for(AnimatedModel m : children){ + m.renderWithIndex(inter, firstIndex, nextIndex, diffN, c); + } + } + @Override + public void render() { + for(AnimatedModel m : children){ + m.render(); + } + } + }; + for(Element node : getChildElements(scene)){ + if(node.getElementsByTagName("instance_geometry").getLength() > 0){ + structure.children.add(parseStructure(node)); + } + } + Map geometry = parseGeometry((Element)root.getElementsByTagName("library_geometries").item(0), flipV); + addGeometry(structure, geometry); + setAnimationController(structure, new AnimationController()); + + return structure; + } + + private static void setAnimationController(AnimatedModel model, AnimationController control){ + model.controller = control; + for(AnimatedModel m : model.children) + setAnimationController(m, control); + } + + private static Element getFirstElement(Node root){ + NodeList nodes = root.getChildNodes(); + for(int i = 0; i < nodes.getLength(); i ++){ + Node node = nodes.item(i); + if(node.getNodeType() == Node.ELEMENT_NODE){ + return (Element)node; + } + } + return null; + } + + private static List getElementsByName(Element e, String name){ + List elements = new ArrayList(); + NodeList n = e.getChildNodes(); + for(int i = 0; i < n.getLength(); i ++){ + Node node = n.item(i); + if(node.getNodeType() == Node.ELEMENT_NODE && node.getNodeName().equals(name)){ + elements.add((Element) node); + } + } + return elements; + } + + private static List getChildElements(Element e){ + List elements = new ArrayList(); + if(e == null) + return elements; + NodeList n = e.getChildNodes(); + for(int i = 0; i < n.getLength(); i ++){ + Node node = n.item(i); + if(node.getNodeType() == Node.ELEMENT_NODE){ + elements.add((Element) node); + } + } + return elements; + } + + private static AnimatedModel parseStructure(Element root){ + AnimatedModel model = new AnimatedModel(); + model.name = root.getAttribute("name"); + + NodeList children = root.getChildNodes(); + for(int i = 0; i < children.getLength(); i ++){ + Node node = children.item(i); + if(node.getNodeType() != Node.ELEMENT_NODE) + continue; + Element ele = (Element) node; + if("transform".equals(ele.getAttribute("sid"))){ + //Do I even need to flip the matrix here? No idea! + model.transform = flipMatrix(parseFloatArray(ele.getTextContent())); + model.hasTransform = true; + } else if("instance_geometry".equals(ele.getTagName())){ + model.geo_name = ele.getAttribute("url").substring(1); + } else if(ele.getElementsByTagName("instance_geometry").getLength() > 0){ + AnimatedModel childModel = parseStructure(ele); + childModel.parent = model; + model.children.add(childModel); + } + } + return model; + } + + /*private static void addStructureChildren(Element root, AnimatedModel model){ + NodeList children = root.getChildNodes(); + for(int i = 0; i < children.getLength(); i ++){ + Node node = children.item(i); + if(node.getNodeType() == Node.ELEMENT_NODE){ + Element element = (Element) node;if(getElementsByName(element, "instance_geometry").size() > 0){ + addGeoNamesToModel(element, model); + } else if(getElementsByName(element, "node").size() > 0 && "JOINT".equals(((Element)getElementsByName(element, "node").get(0)).getAttribute("type"))){ + AnimatedModel m = parseStructure(element); + model.children.add(m); + m.parent = model; + } + } + } + } + + private static void addGeoNamesToModel(Element root, AnimatedModel model){ + List geo_names = getElementsByName(root, "instance_geometry"); + for(Element e : geo_names){ + String name = e.getAttribute("url").substring(1); + model.geo_names.add(name); + } + }*/ + + + //Geometry loading section + + //Map of geometry name to display list id + private static Map parseGeometry(Element root, boolean flipV){ + Map allGeometry = new HashMap(); + for(Element e : getElementsByName(root, "geometry")){ + String name = e.getAttribute("id"); + Element mesh = getElementsByName(e, "mesh").get(0); + + float[] positions = new float[0]; + float[] normals = new float[0]; + float[] texCoords = new float[0]; + int[] indices = new int[0]; + + for(Element section : getChildElements(mesh)){ + String id = section.getAttribute("id"); + if(id.endsWith("mesh-positions")){ + positions = parsePositions(section); + } else if(id.endsWith("mesh-normals")){ + normals = parseNormals(section); + } else if(id.endsWith("mesh-map-0")){ + texCoords = parseTexCoords(section); + } else if(section.getNodeName().equals("triangles")){ + indices = ArrayUtils.addAll(indices, parseIndices(section)); + } + } + if(positions.length == 0) + continue; + + int displayList = GL11.glGenLists(1); + GL11.glNewList(displayList, GL11.GL_COMPILE); + BufferBuilder buf = Tessellator.getInstance().getBuffer(); + buf.begin(GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION_TEX_NORMAL); + if(indices.length > 0){ + for(int i = 0; i < indices.length; i += 3){ + float v = texCoords[indices[i+2]*2+1]; + if(flipV){ + v = 1-v; + } + buf.pos(positions[indices[i]*3], positions[indices[i]*3+1], positions[indices[i]*3+2]) + .tex(texCoords[indices[i+2]*2], v) + .normal(normals[indices[i+1]*3], normals[indices[i+1]*3+1], normals[indices[i+1]*3+2]) + .endVertex(); + } + } else { + + } + + Tessellator.getInstance().draw(); + GL11.glEndList(); + + allGeometry.put(name, displayList); + } + return allGeometry; + } + + private static float[] parsePositions(Element root){ + String content = root.getElementsByTagName("float_array").item(0).getTextContent(); + return parseFloatArray(content); + } + + private static float[] parseNormals(Element root){ + String content = root.getElementsByTagName("float_array").item(0).getTextContent(); + return parseFloatArray(content); + } + + private static float[] parseTexCoords(Element root){ + String content = root.getElementsByTagName("float_array").item(0).getTextContent(); + return parseFloatArray(content); + } + + private static int[] parseIndices(Element root){ + String content = root.getElementsByTagName("p").item(0).getTextContent(); + return parseIntegerArray(content); + } + + private static float[] parseFloatArray(String s){ + if(s.isEmpty()){ + return new float[0]; + } + String[] numbers = s.split(" "); + float[] arr = new float[numbers.length]; + for(int i = 0; i < numbers.length; i ++){ + arr[i] = Float.parseFloat(numbers[i]); + } + return arr; + } + private static int[] parseIntegerArray(String s){ + String[] numbers = s.split(" "); + int[] arr = new int[numbers.length]; + for(int i = 0; i < numbers.length; i ++){ + arr[i] = Integer.parseInt(numbers[i]); + } + return arr; + } + + private static void addGeometry(AnimatedModel m, Map geometry){ + if(!"".equals(m.geo_name) && geometry.containsKey(m.geo_name)) + m.callList = geometry.get(m.geo_name); + else { + m.hasGeometry = false; + m.callList = -1; + } + for(AnimatedModel child : m.children){ + addGeometry(child, geometry); + } + } + + + + + //Animation loading section + public static Animation loadAnim(int length, ResourceLocation file){ + IResource res; + try { + res = Minecraft.getMinecraft().getResourceManager().getResource(file); + Document doc; + try { + doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(res.getInputStream()); + return parseAnim(doc.getDocumentElement(), length); + } catch(SAXException e) { + e.printStackTrace(); + } catch(IOException e) { + e.printStackTrace(); + } catch(ParserConfigurationException e) { + e.printStackTrace(); + } + } catch(IOException e) { + e.printStackTrace(); + } + AvatarMod.logger.log(Level.ERROR, "FAILED TO LOAD MODEL: " + file); + return null; + } + + private static Animation parseAnim(Element root, int length){ + Element anim_section = (Element)root.getElementsByTagName("library_animations").item(0); + Animation anim = new Animation(); + anim.length = length; + for(Element e : getChildElements(anim_section)){ + if("animation".equals(e.getNodeName())){ + String name = e.getAttribute("name"); + Transform[] t = null; + List elements2 = getChildElements(e); + if(elements2.isEmpty()){ + continue; + } + for(Element e2 : elements2){ + if(e2.getAttribute("id").endsWith("transform")){ + t = parseTransforms(e2); + } else if(e2.getAttribute("id").endsWith("hide_viewport")){ + setViewportHiddenKeyframes(t, e2); + } + } + anim.objectTransforms.put(name, t); + anim.numKeyFrames = t.length; + } + } + return anim; + } + + private static Transform[] parseTransforms(Element root){ + String output = getOutputLocation(root); + for(Element e : getChildElements(root)){ + if(e.getAttribute("id").equals(output)){ + return parseTransformsFromText(e.getElementsByTagName("float_array").item(0).getTextContent()); + } + } + System.out.println("Failed to parse transforms! This will not work!"); + System.out.println("Node name: " + root.getTagName()); + return null; + } + + private static void setViewportHiddenKeyframes(Transform[] t, Element root){ + String output = getOutputLocation(root); + for(Element e : getChildElements(root)){ + if(e.getAttribute("id").equals(output)){ + int[] hiddenFrames = parseIntegerArray(e.getElementsByTagName("float_array").item(0).getTextContent()); + for(int i = 0; i < hiddenFrames.length; i ++){ + t[i].hidden = hiddenFrames[i] > 0 ? true : false; + } + } + } + } + + private static String getOutputLocation(Element root){ + Element sampler = (Element) root.getElementsByTagName("sampler").item(0); + for(Element e : getChildElements(sampler)){ + if("OUTPUT".equals(e.getAttribute("semantic"))){ + return e.getAttribute("source").substring(1); + } + } + return null; + } + + private static Transform[] parseTransformsFromText(String data){ + float[] floats = parseFloatArray(data); + Transform[] transforms = new Transform[floats.length/16]; + for(int i = 0; i < floats.length/16; i++){ + float[] rawTransform = new float[16]; + for(int j = 0; j < 16; j ++) + rawTransform[j] = floats[i*16 + j]; + transforms[i] = new Transform(rawTransform); + } + return transforms; + } + + private static float[] flipMatrix(float[] f){ + if(f.length != 16){ + System.out.println("Error flipping matrix: array length not 16. This will not work!"); + System.out.println("Matrix: " + f); + } + return new float[]{ + f[0], f[4], f[8], f[12], + f[1], f[5], f[9], f[13], + f[2], f[6], f[10], f[14], + f[3], f[7], f[11], f[15] + }; + } + +} \ No newline at end of file diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/configs/CommonConfig.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/configs/CommonConfig.java new file mode 100644 index 0000000000..ed6a0c8077 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/configs/CommonConfig.java @@ -0,0 +1,59 @@ +package com.crowsofwar.avatar.client.render.lightning.configs; + +import com.crowsofwar.avatar.AvatarMod; +import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.common.config.Property; + +public class CommonConfig { + + public static boolean createConfigBool(Configuration config, String category, String name, String comment, boolean def) { + + Property prop = config.get(category, name, def); + prop.setComment(comment); + return prop.getBoolean(); + } + + public static String createConfigString(Configuration config, String category, String name, String comment, String def) { + + Property prop = config.get(category, name, def); + prop.setComment(comment); + return prop.getString(); + } + + public static String[] createConfigStringList(Configuration config, String category, String name, String comment) { + + Property prop = config.get(category, name, new String[] { "PLACEHOLDER" }); + prop.setComment(comment); + return prop.getStringList(); + } + + public static int createConfigInt(Configuration config, String category, String name, String comment, int def) { + + Property prop = config.get(category, name, def); + prop.setComment(comment); + return prop.getInt(); + } + + public static int setDefZero(int value, int def) { + + if(value < 0) { + AvatarMod.logger.error("Fatal error config: Randomizer value has been below zero, despite bound having to be positive integer!"); + AvatarMod.logger.error(String.format("Errored value will default back to %d, PLEASE REVIEW CONFIGURATION DESCRIPTION BEFORE MEDDLING WITH VALUES!", def)); + return def; + } + + return value; + } + + public static int setDef(int value, int def) { + + if(value <= 0) { + AvatarMod.logger.error("Fatal error config: Randomizer value has been set to zero, despite bound having to be positive integer!"); + AvatarMod.logger.error(String.format("Errored value will default back to %d, PLEASE REVIEW CONFIGURATION DESCRIPTION BEFORE MEDDLING WITH VALUES!", def)); + return def; + } + + return value; + } + +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/configs/LightningConfig.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/configs/LightningConfig.java new file mode 100644 index 0000000000..7f0d6b0987 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/configs/LightningConfig.java @@ -0,0 +1,28 @@ +package com.crowsofwar.avatar.client.render.lightning.configs; + +public class LightningConfig { + + public static boolean instancedParticles = true; + public static boolean callListModels = true; + public static boolean useShaders = false; + public static boolean useShaders2 = true; + public static boolean bloom = true; + public static boolean heatDistortion = true; + public static boolean recipes = true; + public static boolean shapeless = true; + public static boolean shaped = true; + public static boolean jei = true; + public static boolean depthEffects = true; + + public static int crucibleMaxCharges = 3; + + public static boolean enable528 = false; + public static boolean enable528ReasimBoilers = true; + public static boolean enable528ColtanDeposit = true; + public static boolean enable528ColtanSpawn = false; + public static boolean enable528BedrockDeposit = true; + public static boolean enable528BedrockSpawn = false; + public static boolean enableReflectorCompat = false; + public static int coltanRate = 2; + public static int bedrockRate = 50; +} \ No newline at end of file diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/handler/HbmShaderManager2.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/handler/HbmShaderManager2.java new file mode 100644 index 0000000000..3a43140ee3 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/handler/HbmShaderManager2.java @@ -0,0 +1,483 @@ +package com.crowsofwar.avatar.client.render.lightning.handler; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +import com.crowsofwar.avatar.AvatarMod; +import com.crowsofwar.avatar.client.render.lightning.main.ResourceManager; +import com.crowsofwar.avatar.client.render.lightning.render.GLCompat; +import com.crowsofwar.avatar.client.render.lightning.configs.LightningConfig; +import com.crowsofwar.avatar.client.render.lightning.handler.HbmShaderManager2.Shader.Uniform; + +import com.crowsofwar.avatar.network.AvatarClientProxy; +import org.apache.commons.io.IOUtils; +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; +import org.lwjgl.opengl.GL14; +import org.lwjgl.util.vector.Matrix4f; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GLAllocation; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.GlStateManager.DestFactor; +import net.minecraft.client.renderer.GlStateManager.SourceFactor; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.shader.Framebuffer; +import net.minecraft.util.ResourceLocation; + +//Same as the other class except with less junk (hopefully) +public class HbmShaderManager2 { + + public static final FloatBuffer AUX_GL_BUFFER = GLAllocation.createDirectFloatBuffer(16); + + public static final Uniform MODELVIEW_PROJECTION_MATRIX = shader -> { + //No idea if all these rewind calls are necessary. I'll have to check that later. + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, AUX_GL_BUFFER); + AUX_GL_BUFFER.rewind(); + Matrix4f mvMatrix = new Matrix4f(); + mvMatrix.load(AUX_GL_BUFFER); + AUX_GL_BUFFER.rewind(); + + GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, AUX_GL_BUFFER); + AUX_GL_BUFFER.rewind(); + Matrix4f pMatrix = new Matrix4f(); + pMatrix.load(AUX_GL_BUFFER); + AUX_GL_BUFFER.rewind(); + + Matrix4f.mul(pMatrix, mvMatrix, mvMatrix).store(AUX_GL_BUFFER); + AUX_GL_BUFFER.rewind(); + + shader.uniformMatrix4("modelViewProjectionMatrix", false, AUX_GL_BUFFER); + }; + + public static final Uniform MODELVIEW_MATRIX = shader -> { + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, AUX_GL_BUFFER); + AUX_GL_BUFFER.rewind(); + shader.uniformMatrix4("modelview", false, AUX_GL_BUFFER); + }; + + public static final Uniform PROJECTION_MATRIX = shader -> { + GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, AUX_GL_BUFFER); + AUX_GL_BUFFER.rewind(); + shader.uniformMatrix4("projection", false, AUX_GL_BUFFER); + }; + + public static final Uniform LIGHTMAP = shader -> { + shader.uniform1i("lightmap", 1); + }; + + public static final Uniform WINDOW_SIZE = shader -> { + shader.uniform2f("windowSize", Minecraft.getMinecraft().displayWidth, Minecraft.getMinecraft().displayHeight); + }; + + public static int height = 0; + public static int width = 0; + + public static final int bloomLayers = 4; + public static Framebuffer[] bloomBuffers; + public static Framebuffer bloomData; + public static Framebuffer distortionBuffer; + + public static int depthFrameBuffer = -1; + public static int depthTexture = -1; + + public static float[] inv_ViewProjectionMatrix = new float[16]; + + public static void createInvMVP(){ + GL11.glPushMatrix(); + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, AvatarClientProxy.AUX_GL_BUFFER); + GL11.glPopMatrix(); + GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, AvatarClientProxy.AUX_GL_BUFFER2); + Matrix4f view = new Matrix4f(); + Matrix4f proj = new Matrix4f(); + view.load(AvatarClientProxy.AUX_GL_BUFFER); + proj.load(AvatarClientProxy.AUX_GL_BUFFER2); + AvatarClientProxy.AUX_GL_BUFFER.rewind(); + AvatarClientProxy.AUX_GL_BUFFER2.rewind(); + view.invert(); + proj.invert(); + Matrix4f.mul(view, proj, view); + view.store(AvatarClientProxy.AUX_GL_BUFFER); + AvatarClientProxy.AUX_GL_BUFFER.rewind(); + AvatarClientProxy.AUX_GL_BUFFER.get(inv_ViewProjectionMatrix); + AvatarClientProxy.AUX_GL_BUFFER.rewind(); + } + + public static void blitDepth(){ + if(!LightningConfig.depthEffects) + return; + if(height != Minecraft.getMinecraft().displayHeight || width != Minecraft.getMinecraft().displayWidth || depthFrameBuffer == -1){ + GL11.glDeleteTextures(depthTexture); + GLCompat.deleteFramebuffers(depthFrameBuffer); + + depthFrameBuffer = GLCompat.genFramebuffers(); + GLCompat.bindFramebuffer(OpenGlHelper.GL_FRAMEBUFFER, depthFrameBuffer); + depthTexture = GL11.glGenTextures(); + GlStateManager.bindTexture(depthTexture); + GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL14.GL_DEPTH_COMPONENT24, Minecraft.getMinecraft().displayWidth, Minecraft.getMinecraft().displayHeight, 0, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, (FloatBuffer)null); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); + GLCompat.framebufferTexture2D(OpenGlHelper.GL_FRAMEBUFFER, OpenGlHelper.GL_DEPTH_ATTACHMENT, GL11.GL_TEXTURE_2D, depthTexture, 0); + int bruh = OpenGlHelper.glCheckFramebufferStatus(OpenGlHelper.GL_FRAMEBUFFER); + if(bruh != OpenGlHelper.GL_FRAMEBUFFER_COMPLETE){ + System.out.println("Failed to create depth texture framebuffer! This is an error!"); + } + } + GLCompat.bindFramebuffer(GLCompat.GL_READ_FRAMEBUFFER, Minecraft.getMinecraft().getFramebuffer().framebufferObject); + GLCompat.bindFramebuffer(GLCompat.GL_DRAW_FRAMEBUFFER, depthFrameBuffer); + GLCompat.blitFramebuffer(0, 0, width, height, 0, 0, width, height, GL11.GL_DEPTH_BUFFER_BIT, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + + public static void postProcess(){ + if(!LightningConfig.useShaders2) + return; + if(height != Minecraft.getMinecraft().displayHeight || width != Minecraft.getMinecraft().displayWidth){ + height = Minecraft.getMinecraft().displayHeight; + width = Minecraft.getMinecraft().displayWidth; + if(LightningConfig.bloom) + recreateBloomFBOs(); + if(LightningConfig.heatDistortion) + recreateDistortionBuffer(); + } + if(LightningConfig.bloom){ + bloom(); + } + GlStateManager.enableDepth(); + } + + + private static void bloom(){ + downsampleBloomData(); + GlStateManager.enableBlend(); + for(int i = bloomLayers-1; i >= 0; i --){ + GlStateManager.blendFunc(SourceFactor.ONE, DestFactor.ZERO); + bloomBuffers[i*2+1].bindFramebuffer(true); + ResourceManager.bloom_h.use(); + GLCompat.uniform1f(GLCompat.getUniformLocation(ResourceManager.bloom_h.getShaderId(), "frag_width"), 1F/(float)bloomBuffers[i*2].framebufferWidth); + renderFboTriangle(bloomBuffers[i*2], bloomBuffers[i*2+1].framebufferWidth, bloomBuffers[i*2+1].framebufferHeight); + + GlStateManager.blendFunc(SourceFactor.ONE, DestFactor.ONE); + int tWidth, tHeight; + if(i == 0){ + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(true); + tWidth = Minecraft.getMinecraft().getFramebuffer().framebufferWidth; + tHeight = Minecraft.getMinecraft().getFramebuffer().framebufferHeight; + } else { + GLCompat.blendEquation(GLCompat.GL_MAX); + bloomBuffers[(i-1)*2].bindFramebuffer(true); + tWidth = bloomBuffers[(i-1)*2].framebufferWidth; + tHeight = bloomBuffers[(i-1)*2].framebufferHeight; + } + ResourceManager.bloom_v.use(); + GLCompat.uniform1f(GLCompat.getUniformLocation(ResourceManager.bloom_v.getShaderId(), "frag_height"), 1F/(float)bloomBuffers[i*2].framebufferHeight); + renderFboTriangle(bloomBuffers[i*2+1], tWidth, tHeight); + GLCompat.blendEquation(GLCompat.GL_FUNC_ADD); + } + releaseShader(); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); + GlStateManager.disableBlend(); + bloomData.bindFramebuffer(true); + GlStateManager.clearColor(bloomData.framebufferColor[0], bloomData.framebufferColor[1], bloomData.framebufferColor[2], bloomData.framebufferColor[3]); + GlStateManager.clear(GL11.GL_COLOR_BUFFER_BIT); + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(true); + + GlStateManager.enableAlpha(); + GlStateManager.enableLighting(); + GlStateManager.enableDepth(); + } + + public static void downsampleBloomData(){ + bloomBuffers[0].bindFramebuffer(true); + ResourceManager.downsample.use(); + GLCompat.uniform2f(GLCompat.getUniformLocation(ResourceManager.downsample.getShaderId(), "texel"), 1F/(float)bloomData.framebufferTextureWidth, 1F/(float)bloomData.framebufferTextureHeight); + renderFboTriangle(bloomData, bloomBuffers[0].framebufferWidth, bloomBuffers[0].framebufferHeight); + for(int i = 1; i < bloomLayers; i ++){ + bloomBuffers[i*2].bindFramebuffer(true); + GLCompat.uniform2f(GLCompat.getUniformLocation(ResourceManager.downsample.getShaderId(), "texel"), 1F/(float)bloomBuffers[(i-1)*2].framebufferTextureWidth, 1F/(float)bloomBuffers[(i-1)*2].framebufferTextureHeight); + renderFboTriangle(bloomBuffers[(i-1)*2], bloomBuffers[i*2].framebufferWidth, bloomBuffers[i*2].framebufferHeight); + } + releaseShader(); + } + + public static void recreateDistortionBuffer(){ + if(distortionBuffer != null){ + distortionBuffer.deleteFramebuffer(); + } + distortionBuffer = new Framebuffer(width, height, true); + distortionBuffer.bindFramebufferTexture(); + GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GLCompat.GL_RGBA16F, width, height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_SHORT, (IntBuffer)null); + distortionBuffer.bindFramebuffer(false); + GLCompat.bindRenderbuffer(GLCompat.GL_RENDERBUFFER, Minecraft.getMinecraft().getFramebuffer().depthBuffer); + OpenGlHelper.glFramebufferRenderbuffer(OpenGlHelper.GL_FRAMEBUFFER, OpenGlHelper.GL_DEPTH_ATTACHMENT, OpenGlHelper.GL_RENDERBUFFER, Minecraft.getMinecraft().getFramebuffer().depthBuffer); + distortionBuffer.setFramebufferFilter(GL11.GL_LINEAR); + distortionBuffer.setFramebufferColor(0, 0, 0, 0); + distortionBuffer.framebufferClear(); + } + + public static void recreateBloomFBOs(){ + if(bloomBuffers != null) + for(Framebuffer buf : bloomBuffers){ + buf.deleteFramebuffer(); + } + if(bloomData != null) + bloomData.deleteFramebuffer(); + bloomData = new Framebuffer(width, height, true); + bloomData.bindFramebufferTexture(); + GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GLCompat.GL_RGBA16F, width, height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_SHORT, (IntBuffer)null); + bloomData.bindFramebuffer(false); + GLCompat.bindRenderbuffer(GLCompat.GL_RENDERBUFFER, Minecraft.getMinecraft().getFramebuffer().depthBuffer); + GLCompat.framebufferRenderbuffer(GLCompat.GL_FRAMEBUFFER, GLCompat.GL_DEPTH_ATTACHMENT, GLCompat.GL_RENDERBUFFER, Minecraft.getMinecraft().getFramebuffer().depthBuffer); + bloomData.setFramebufferFilter(GL11.GL_LINEAR); + bloomData.setFramebufferColor(0, 0, 0, 0); + bloomData.framebufferClear(); + bloomBuffers = new Framebuffer[bloomLayers*2]; + float bloomW = width; + float bloomH = height; + for(int i = 0; i < bloomLayers; i ++){ + + bloomBuffers[i*2] = new Framebuffer((int)bloomW, (int)bloomH, false); + bloomBuffers[i*2+1] = new Framebuffer((int)bloomW, (int)bloomH, false); + bloomBuffers[i*2].bindFramebufferTexture(); + GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GLCompat.GL_RGBA16F, (int)bloomW, (int)bloomH, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_SHORT, (IntBuffer)null); + bloomBuffers[i*2+1].bindFramebufferTexture(); + GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GLCompat.GL_RGBA16F, (int)bloomW, (int)bloomH, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_SHORT, (IntBuffer)null); + bloomBuffers[i*2].setFramebufferFilter(GL11.GL_LINEAR); + bloomBuffers[i*2+1].setFramebufferFilter(GL11.GL_LINEAR); + bloomBuffers[i*2].setFramebufferColor(0, 0, 0, 0); + bloomBuffers[i*2+1].setFramebufferColor(0, 0, 0, 0); + if(i < 2){ + bloomW *= 0.25F; + bloomH *= 0.25F; + } else { + bloomW *= 0.5F; + bloomH *= 0.5F; + } + } + } + + public static void renderFboTriangle(Framebuffer buf){ + renderFboTriangle(buf, buf.framebufferWidth, buf.framebufferHeight); + } + + public static void renderFboTriangle(Framebuffer buf, int width, int height){ + GlStateManager.colorMask(true, true, true, false); + GlStateManager.disableDepth(); + GlStateManager.depthMask(false); + GlStateManager.viewport(0, 0, width, height); + GlStateManager.enableTexture2D(); + GlStateManager.disableLighting(); + GlStateManager.disableAlpha(); + + GlStateManager.enableColorMaterial(); + + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + buf.bindFramebufferTexture(); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + bufferbuilder.begin(GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION_TEX); + bufferbuilder.pos(-1, -1, 0.0D).tex(0, 0).endVertex(); + bufferbuilder.pos(3, -1, 0.0D).tex(2, 0).endVertex(); + bufferbuilder.pos(-1, 3, 0.0D).tex(0, 2).endVertex(); + tessellator.draw(); + buf.unbindFramebufferTexture(); + GlStateManager.depthMask(true); + GlStateManager.enableDepth(); + GlStateManager.enableAlpha(); + GlStateManager.colorMask(true, true, true, true); + } + + public static Framebuffer buf; + + /* public static void doPostProcess(){ + if(height != Minecraft.getMinecraft().displayHeight || width != Minecraft.getMinecraft().displayWidth){ + recreateFBOs(); + height = Minecraft.getMinecraft().displayHeight; + width = Minecraft.getMinecraft().displayWidth; + } + GL11.glPushMatrix(); + + buf.bindFramebuffer(false); + + ResourceManager.testlut.use(); + GlStateManager.setActiveTexture(GL13.GL_TEXTURE3); + Minecraft.getMinecraft().getTextureManager().bindTexture(ResourceManager.lut); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); + GlStateManager.setActiveTexture(GL13.GL_TEXTURE0); + GL20.glUniform1i(GL20.glGetUniformLocation(ResourceManager.testlut.getShaderId(), "tempTest"), 3); + + Minecraft.getMinecraft().getFramebuffer().framebufferRender(buf.framebufferWidth, buf.framebufferHeight); + + HbmShaderManager2.releaseShader(); + + GL30.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, buf.framebufferObject); + GL30.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, Minecraft.getMinecraft().getFramebuffer().framebufferObject); + GL30.glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL11.GL_COLOR_BUFFER_BIT, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + + GL11.glPopMatrix(); + GlStateManager.enableDepth(); + } + + public static void recreateFBOs(){ + if(buf != null) + buf.deleteFramebuffer(); + buf = new Framebuffer(Minecraft.getMinecraft().displayWidth, Minecraft.getMinecraft().displayHeight, false); + }*/ + + public static Shader loadShader(ResourceLocation file) { + return loadShader(file, null); + } + + public static Shader loadShader(ResourceLocation file, Consumer attribBinder) { + if(!LightningConfig.useShaders2){ + return new Shader(0); + } + int vertexShader = 0; + int fragmentShader = 0; + try { + int program = GLCompat.createProgram(); + + vertexShader = GLCompat.createShader(GLCompat.GL_VERTEX_SHADER); + GLCompat.shaderSource(vertexShader, readFileToBuf(new ResourceLocation(file.getNamespace(), file.getPath() + ".vert"))); + GLCompat.compileShader(vertexShader); + if(GLCompat.getShaderi(vertexShader, GLCompat.GL_COMPILE_STATUS) == GL11.GL_FALSE) { + AvatarMod.logger.error(GLCompat.getShaderInfoLog(vertexShader, GLCompat.GL_INFO_LOG_LENGTH)); + throw new RuntimeException("Error creating vertex shader: " + file); + } + + fragmentShader = GLCompat.createShader(GLCompat.GL_FRAGMENT_SHADER); + GLCompat.shaderSource(fragmentShader, readFileToBuf(new ResourceLocation(file.getNamespace(), file.getPath() + ".frag"))); + GLCompat.compileShader(fragmentShader); + if(GLCompat.getShaderi(fragmentShader, GLCompat.GL_COMPILE_STATUS) == GL11.GL_FALSE) { + AvatarMod.logger.error(GLCompat.getShaderInfoLog(fragmentShader, GLCompat.GL_INFO_LOG_LENGTH)); + throw new RuntimeException("Error creating fragment shader: " + file); + } + + GLCompat.attachShader(program, vertexShader); + GLCompat.attachShader(program, fragmentShader); + if(attribBinder != null) + attribBinder.accept(program); + GLCompat.linkProgram(program); + if(GLCompat.getProgrami(program, GLCompat.GL_LINK_STATUS) == GL11.GL_FALSE) { + AvatarMod.logger.error(GLCompat.getProgramInfoLog(program, GLCompat.GL_INFO_LOG_LENGTH)); + throw new RuntimeException("Error linking shader: " + file); + } + + GLCompat.deleteShader(vertexShader); + GLCompat.deleteShader(fragmentShader); + + return new Shader(program); + } catch(Exception x) { + GLCompat.deleteShader(vertexShader); + GLCompat.deleteShader(fragmentShader); + x.printStackTrace(); + } + return new Shader(0); + } + + private static ByteBuffer readFileToBuf(ResourceLocation file) throws IOException { + InputStream in = Minecraft.getMinecraft().getResourceManager().getResource(file).getInputStream(); + byte[] bytes = IOUtils.toByteArray(in); + IOUtils.closeQuietly(in); + ByteBuffer buf = BufferUtils.createByteBuffer(bytes.length); + buf.put(bytes); + buf.rewind(); + return buf; + } + + public static void releaseShader(){ + GLCompat.useProgram(0); + } + + public static class Shader { + + private int shader; + private List uniforms = new ArrayList<>(2); + + public Shader(int shader) { + this.shader = shader; + } + + public Shader withUniforms(Uniform... uniforms){ + for(Uniform u : uniforms){ + this.uniforms.add(u); + } + return this; + } + + public void use(){ + if(shader == 0) + return; + GLCompat.useProgram(shader); + for(Uniform u : uniforms){ + u.apply(this); + } + } + + public int getShaderId(){ + return shader; + } + + public void uniform1i(String name, int v0){ + if(shader == 0) + return; + GLCompat.uniform1i(GLCompat.getUniformLocation(shader, name), v0); + } + + public void uniform1f(String name, float v0){ + if(shader == 0) + return; + GLCompat.uniform1f(GLCompat.getUniformLocation(shader, name), v0); + } + + public void uniform2f(String name, float v0, float v1){ + if(shader == 0) + return; + GLCompat.uniform2f(GLCompat.getUniformLocation(shader, name), v0, v1); + } + + public void uniform3f(String name, float v0, float v1, float v2){ + if(shader == 0) + return; + GLCompat.uniform3f(GLCompat.getUniformLocation(shader, name), v0, v1, v2); + } + + public void uniform4f(String name, float v0, float v1, float v2, float v3){ + if(shader == 0) + return; + GLCompat.uniform4f(GLCompat.getUniformLocation(shader, name), v0, v1, v2, v3); + } + + public void uniformMatrix3(String name, boolean transpose, FloatBuffer matrix){ + if(shader == 0) + return; + GLCompat.uniformMatrix3(GLCompat.getUniformLocation(shader, name), transpose, matrix); + } + + public void uniformMatrix4(String name, boolean transpose, FloatBuffer matrix){ + if(shader == 0) + return; + GLCompat.uniformMatrix4(GLCompat.getUniformLocation(shader, name), transpose, matrix); + } + + public static interface Uniform { + public void apply(Shader shader); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/handler/LightningGenerator.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/handler/LightningGenerator.java new file mode 100644 index 0000000000..9e9a176b23 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/handler/LightningGenerator.java @@ -0,0 +1,121 @@ +package com.crowsofwar.avatar.client.render.lightning.handler; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import javax.annotation.Nullable; + +import com.crowsofwar.avatar.client.render.lightning.math.BobMathUtil; +import com.crowsofwar.avatar.client.render.lightning.render.TrailRenderer2; +import net.minecraft.client.Minecraft; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class LightningGenerator { + + private static Random rand = new Random(); + + public static LightningNode generateLightning(Vec3d from, Vec3d to, LightningGenInfo info){ + rand.setSeed(Minecraft.getMinecraft().world.getTotalWorldTime()); + LightningNode lfrom = new LightningNode(from); + LightningNode lto = new LightningNode(to); + lfrom.children.add(lto); + lto.parent = lfrom; + generateLightning(lfrom, info); + return lfrom; + } + + public static void generateLightning(LightningNode node, LightningGenInfo info){ + Vec3d from = node.pos; + Vec3d to = node.children.get(0).pos; + subdivide(node, info.subdivisions, info.subdivMult, info.subdivRecurse-1, info.randAmount, info.randAmountSubdivMultiplier); + LightningNode child = node.children.get(0); + float value = 0; + while(child.children.size() > 0){ + value += 0.02F; + LightningNode next = child.children.get(0); + if(rand.nextFloat() < info.forkChance-value){ + Vec3d randVec = BobMathUtil.randVecInCone(to.subtract(from).normalize(), info.forkConeDegrees, rand); + LightningNode fork1 = new LightningNode(child.pos); + float len = 1+rand.nextFloat()*info.forkLengthRandom; + LightningNode fork2 = new LightningNode(child.pos.add(randVec.scale(len*from.subtract(to).length()*0.25F))); + fork1.children.add(fork2); + fork2.parent = fork1; + subdivide(fork1, (int) (len*0.75*info.forkSubdivisions), info.forkSubdivMult, info.forkSubdivRecurse, info.forkRandAmount*info.randAmount*rand.nextFloat()*0.8F, info.forkRandAmountSubdivMultiplier); + child.children.add(fork1); + } + child = next; + } + } + + public static void subdivide(LightningNode n, int subdivisions, float subdivMult, int recurse, float randAmount, float randAmountSubdivMultiplier){ + LightningNode parent = n; + LightningNode child = n.children.get(0); + float subdivision = 1F/(float)(subdivisions+1); + for(int i = 1; i <= subdivisions; i ++){ + Vec3d newPos = BobMathUtil.mix(n.pos, child.pos, subdivision*i).add((rand.nextFloat()*2-1)*randAmount, (rand.nextFloat()*2-1)*randAmount, (rand.nextFloat()*2-1)*randAmount); + LightningNode insert = new LightningNode(newPos); + insert.parent = parent; + insert.children.add(child); + parent.children.set(0, insert); + child.parent = insert; + parent = insert; + } + if(recurse <= 0) + return; + child = n; + while(child.children.size() > 0){ + LightningNode next = child.children.get(0); + subdivide(child, (int)(subdivisions*subdivMult), subdivMult, recurse-1, randAmount*randAmountSubdivMultiplier, randAmountSubdivMultiplier); + child = next; + } + } + + @SideOnly(Side.CLIENT) + public static void render(LightningNode n, Vec3d playerPos, float scale){ + render(n, playerPos, scale, 0, 0, 0, false, null); + } + + @SideOnly(Side.CLIENT) + public static void render(LightningNode n, Vec3d playerPos, float scale, float x, float y, float z, boolean fadeEnd, @Nullable TrailRenderer2.IColorGetter c){ + List toRender = new ArrayList<>(); + toRender.add(n.pos.add(x, y, z)); + while(n.children.size() > 0){ + //Render forks + for(int i = 1; i < n.children.size(); i ++){ + render(n.children.get(i), playerPos, scale*0.5F, x, y, z, fadeEnd, c); + } + n = n.children.get(0); + toRender.add(n.pos.add(x, y, z)); + } + TrailRenderer2.draw(playerPos, toRender, scale, fadeEnd, true, c); + } + + public static class LightningNode { + public LightningNode parent = null; + public List children = new ArrayList<>(1); + public Vec3d pos; + + public LightningNode(Vec3d pos) { + this.pos = pos; + } + } + + public static class LightningGenInfo { + public int subdivisions = 4; + public int subdivRecurse = 2; + public float randAmount = 0.2F; + public float forkChance = 0.1F; + public float forkSubdivMult = 1F; + public float forkSubdivisions = 1; + public int forkSubdivRecurse = 1; + public float forkLengthRandom = 4; + public float forkRandAmount = 0.2F; + public float forkRandAmountSubdivMultiplier = 0.25F; + public float randAmountSubdivMultiplier = 0.25F; + public float forkConeDegrees = 25; + public float subdivMult = 1.5F; + } +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/AuxButtonPacket.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/AuxButtonPacket.java new file mode 100644 index 0000000000..3ff535c38c --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/AuxButtonPacket.java @@ -0,0 +1,75 @@ +package com.crowsofwar.avatar.client.render.lightning.main; + +import io.netty.buffer.ByteBuf; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.math.BlockPos; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +public class AuxButtonPacket implements IMessage { + + int x; + int y; + int z; + int value; + int id; + + public AuxButtonPacket() + { + + } + + public AuxButtonPacket(int x, int y, int z, int value, int id) + { + this.x = x; + this.y = y; + this.z = z; + this.value = value; + this.id = id; + } + + public AuxButtonPacket(BlockPos pos, int value, int id){ + this(pos.getX(), pos.getY(), pos.getZ(), value, id); + } + + @Override + public void fromBytes(ByteBuf buf) { + x = buf.readInt(); + y = buf.readInt(); + z = buf.readInt(); + value = buf.readInt(); + id = buf.readInt(); + } + + @Override + public void toBytes(ByteBuf buf) { + buf.writeInt(x); + buf.writeInt(y); + buf.writeInt(z); + buf.writeInt(value); + buf.writeInt(id); + } + + public static class Handler implements IMessageHandler { + + @Override + public IMessage onMessage(AuxButtonPacket m, MessageContext ctx) { + ctx.getServerHandler().player.getServer().addScheduledTask(() -> { + EntityPlayer p = ctx.getServerHandler().player; + BlockPos pos = new BlockPos(m.x, m.y, m.z); + + if(m.value == 1000){ + NBTTagCompound perDat = p.getEntityData().getCompoundTag(EntityPlayer.PERSISTED_NBT_TAG); + int lightning = perDat.getInteger("lightningCharge"); + if(lightning == 0){ + perDat.setInteger("lightningCharge", 1); + } + } + }); + return null; + } + } + +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/AuxParticlePacketNT.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/AuxParticlePacketNT.java new file mode 100644 index 0000000000..f5721eaeb5 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/AuxParticlePacketNT.java @@ -0,0 +1,74 @@ +package com.crowsofwar.avatar.client.render.lightning.main; + +import com.crowsofwar.avatar.AvatarMod; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import net.minecraft.client.Minecraft; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +import java.io.IOException; + +public class AuxParticlePacketNT implements IMessage { + + PacketBuffer buffer; + + public AuxParticlePacketNT() { } + + public AuxParticlePacketNT(NBTTagCompound nbt, double x, double y, double z) { + + this.buffer = new PacketBuffer(Unpooled.buffer()); + + nbt.setDouble("posX", x); + nbt.setDouble("posY", y); + nbt.setDouble("posZ", z); + + buffer.writeCompoundTag(nbt); + } + + @Override + public void fromBytes(ByteBuf buf) { + + if (buffer == null) { + buffer = new PacketBuffer(Unpooled.buffer()); + } + buffer.writeBytes(buf); + } + + @Override + public void toBytes(ByteBuf buf) { + + if (buffer == null) { + buffer = new PacketBuffer(Unpooled.buffer()); + } + buf.writeBytes(buffer); + } + + public static class Handler implements IMessageHandler { + + @Override + public IMessage onMessage(AuxParticlePacketNT m, MessageContext ctx) { + Minecraft.getMinecraft().addScheduledTask(() -> { + if(Minecraft.getMinecraft().world == null) + return; + + try { + + NBTTagCompound nbt = m.buffer.readCompoundTag(); + + if(nbt != null) + AvatarMod.proxy.effectNT(nbt); + + } catch (IOException e) { + e.printStackTrace(); + } + }); + + return null; + } + } + +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/Library.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/Library.java new file mode 100644 index 0000000000..d912496978 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/Library.java @@ -0,0 +1,526 @@ +package com.crowsofwar.avatar.client.render.lightning.main; + +import com.crowsofwar.avatar.client.render.lightning.math.BobMathUtil; +import com.google.common.base.Predicates; +import com.google.common.collect.Sets; +import net.minecraft.block.Block; +import net.minecraft.block.BlockDoor; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EntitySelectors; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.WeightedRandom; +import net.minecraft.util.math.*; +import net.minecraft.util.math.BlockPos.MutableBlockPos; +import net.minecraft.util.math.RayTraceResult.Type; +import net.minecraft.world.Explosion; +import net.minecraft.world.World; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.oredict.OreDictionary; +import org.apache.commons.lang3.tuple.Pair; + +import javax.annotation.Nullable; +import java.util.*; + +@Spaghetti("this whole class") +public class Library { + + static Random rand = new Random(); + + //this is a list of UUIDs used for various things, primarily for accessories. + //for a comprehensive list, check RenderAccessoryUtility.java + public static String HbMinecraft = "192af5d7-ed0f-48d8-bd89-9d41af8524f8"; + public static String TacoRedneck = "5aee1e3d-3767-4987-a222-e7ce1fbdf88e"; + // Earl0fPudding + public static String LPkukin = "937c9804-e11f-4ad2-a5b1-42e62ac73077"; + public static String Dafnik = "3af1c262-61c0-4b12-a4cb-424cc3a9c8c0"; + // anna20 + public static String a20 = "4729b498-a81c-42fd-8acd-20d6d9f759e0"; + public static String rodolphito = "c3f5e449-6d8c-4fe3-acc9-47ef50e7e7ae"; + public static String Ducxkskiziko = "122fe98f-be19-49ca-a96b-d4dee4f0b22e"; + public static String Drillgon = "41ebd03f-7a12-42f3-b037-0caa4d6f235b"; + + + //the old list that allowed superuser mode for the ZOMG + //currently unused + public static List superuser = new ArrayList(); + + public static boolean isObstructed(World world, double x, double y, double z, double a, double b, double c) { + RayTraceResult pos = world.rayTraceBlocks(new Vec3d(x, y, z), new Vec3d(a, b, c), false, true, true); + return pos != null && pos.typeOfHit != Type.MISS; + } + + public static EntityPlayer getClosestPlayerForSound(World world, double x, double y, double z, double radius) { + double d4 = -1.0D; + EntityPlayer entity = null; + + for (int i = 0; i < world.loadedEntityList.size(); ++i) { + Entity entityplayer1 = (Entity)world.loadedEntityList.get(i); + + if (entityplayer1.isEntityAlive() && entityplayer1 instanceof EntityPlayer) { + double d5 = entityplayer1.getDistanceSq(x, y, z); + double d6 = radius; + + if ((radius < 0.0D || d5 < d6 * d6) && (d4 == -1.0D || d5 < d4)) { + d4 = d5; + entity = (EntityPlayer)entityplayer1; + } + } + } + + return entity; + } + + public static RayTraceResult rayTrace(EntityPlayer player, double length, float interpolation) { + Vec3d vec3 = getPosition(interpolation, player); + vec3 = vec3.add(0D, (double) player.eyeHeight, 0D); + Vec3d vec31 = player.getLook(interpolation); + Vec3d vec32 = vec3.add(vec31.x * length, vec31.y * length, vec31.z * length); + return player.world.rayTraceBlocks(vec3, vec32, false, false, true); + } + + public static RayTraceResult rayTrace(EntityPlayer player, double length, float interpolation, boolean b1, boolean b2, boolean b3) { + Vec3d vec3 = getPosition(interpolation, player); + vec3 = vec3.add(0D, (double) player.eyeHeight, 0D); + Vec3d vec31 = player.getLook(interpolation); + Vec3d vec32 = vec3.add(vec31.x * length, vec31.y * length, vec31.z * length); + return player.world.rayTraceBlocks(vec3, vec32, b1, b2, b3); + } + + public static AxisAlignedBB rotateAABB(AxisAlignedBB box, EnumFacing facing){ + switch(facing){ + case NORTH: + return new AxisAlignedBB(box.minX, box.minY, 1-box.minZ, box.maxX, box.maxY, 1-box.maxZ); + case SOUTH: + return box; + case EAST: + return new AxisAlignedBB(box.minZ, box.minY, box.minX, box.maxZ, box.maxY, box.maxX); + case WEST: + return new AxisAlignedBB(1-box.minZ, box.minY, box.minX, 1-box.maxZ, box.maxY, box.maxX); + default: + return box; + } + } + + public static RayTraceResult rayTraceIncludeEntities(EntityPlayer player, double d, float f) { + Vec3d vec3 = getPosition(f, player); + vec3 = vec3.add(0D, (double) player.eyeHeight, 0D); + Vec3d vec31 = player.getLook(f); + Vec3d vec32 = vec3.add(vec31.x * d, vec31.y * d, vec31.z * d); + return rayTraceIncludeEntities(player.world, vec3, vec32, player); + } + + public static RayTraceResult rayTraceIncludeEntitiesCustomDirection(EntityPlayer player, Vec3d look, double d, float f) { + Vec3d vec3 = getPosition(f, player); + vec3 = vec3.add(0D, (double) player.eyeHeight, 0D); + Vec3d vec32 = vec3.add(look.x * d, look.y * d, look.z * d); + return rayTraceIncludeEntities(player.world, vec3, vec32, player); + } + + public static Vec3d changeByAngle(Vec3d oldDir, float yaw, float pitch){ + Vec3d dir = new Vec3d(0, 0, 1); + dir = dir.rotatePitch((float) Math.toRadians(pitch)).rotateYaw((float) Math.toRadians(yaw)); + Vec3d angles = BobMathUtil.getEulerAngles(oldDir); + return dir.rotatePitch((float) Math.toRadians(angles.y+90)).rotateYaw((float)Math.toRadians(angles.x)); + } + + public static RayTraceResult rayTraceIncludeEntities(World w, Vec3d vec3, Vec3d vec32, @Nullable Entity excluded) { + RayTraceResult result = w.rayTraceBlocks(vec3, vec32, false, true, true); + if(result != null) + vec32 = result.hitVec; + + AxisAlignedBB box = new AxisAlignedBB(vec3.x, vec3.y, vec3.z, vec32.x, vec32.y, vec32.z).grow(1D); + List ents = w.getEntitiesInAABBexcluding(excluded, box, Predicates.and(EntitySelectors.IS_ALIVE, entity -> entity instanceof EntityLivingBase)); + for(Entity ent : ents){ + RayTraceResult test = ent.getEntityBoundingBox().grow(0.3D).calculateIntercept(vec3, vec32); + if(test != null){ + if(result == null || vec3.squareDistanceTo(result.hitVec) > vec3.squareDistanceTo(test.hitVec)){ + test.typeOfHit = Type.ENTITY; + test.entityHit = ent; + result = test; + } + } + } + + return result; + } + + public static Pair> rayTraceEntitiesOnLine(EntityPlayer player, double d, float f){ + Vec3d vec3 = getPosition(f, player); + vec3 = vec3.add(0D, (double) player.eyeHeight, 0D); + Vec3d vec31 = player.getLook(f); + Vec3d vec32 = vec3.add(vec31.x * d, vec31.y * d, vec31.z * d); + RayTraceResult result = player.world.rayTraceBlocks(vec3, vec32, false, true, true); + if(result != null) + vec32 = result.hitVec; + AxisAlignedBB box = new AxisAlignedBB(vec3.x, vec3.y, vec3.z, vec32.x, vec32.y, vec32.z).grow(1D); + List ents = player.world.getEntitiesInAABBexcluding(player, box, Predicates.and(EntitySelectors.IS_ALIVE, entity -> entity instanceof EntityLiving)); + Iterator itr = ents.iterator(); + while(itr.hasNext()){ + Entity ent = itr.next(); + AxisAlignedBB entityBox = ent.getEntityBoundingBox().grow(0.1); + RayTraceResult entTrace = entityBox.calculateIntercept(vec3, vec32); + if(entTrace == null || entTrace.typeOfHit == Type.MISS){ + itr.remove(); + } + } + return Pair.of(rayTraceIncludeEntities(player, d, f), ents); + } + + public static RayTraceResult rayTraceEntitiesInCone(EntityPlayer player, double d, float f, float degrees) { + double cosDegrees = Math.cos(Math.toRadians(degrees)); + Vec3d vec3 = getPosition(f, player); + vec3 = vec3.add(0D, (double) player.eyeHeight, 0D); + Vec3d vec31 = player.getLook(f); + Vec3d vec32 = vec3.add(vec31.x * d, vec31.y * d, vec31.z * d); + + RayTraceResult result = player.world.rayTraceBlocks(vec3, vec32, false, true, true); + double runningDot = Double.MIN_VALUE; + + AxisAlignedBB box = new AxisAlignedBB(vec3.x, vec3.y, vec3.z, vec3.x, vec3.y, vec3.z).grow(1D+d); + List ents = player.world.getEntitiesInAABBexcluding(player, box, Predicates.and(EntitySelectors.IS_ALIVE, entity -> entity instanceof EntityLiving)); + for(Entity ent : ents){ + Vec3d entPos = closestPointOnBB(ent.getEntityBoundingBox(), vec3, vec32); + Vec3d relativeEntPos = entPos.subtract(vec3).normalize(); + double dot = relativeEntPos.dotProduct(vec31); + + if(dot > cosDegrees && dot > runningDot && !isObstructed(player.world, vec3.x, vec3.y, vec3.z, ent.posX, ent.posY + ent.getEyeHeight()*0.75, ent.posZ)){ + runningDot = dot; + result = new RayTraceResult(ent); + result.hitVec = new Vec3d(ent.posX, ent.posY + ent.getEyeHeight()/2, ent.posZ); + } + + } + + return result; + } + + //Drillgon200: Turns out the closest point on a bounding box to a line is a pretty good method for determine if a cone and an AABB intersect. + //Actually that was a pretty garbage method. Changing it out for a slightly less efficient sphere culling algorithm that only gives false positives. + //https://bartwronski.com/2017/04/13/cull-that-cone/ + //Idea is that we find the closest point on the cone to the center of the sphere and check if it's inside the sphere. + public static boolean isBoxCollidingCone(AxisAlignedBB box, Vec3d coneStart, Vec3d coneEnd, float degrees){ + Vec3d center = box.getCenter(); + double radius = center.distanceTo(new Vec3d(box.maxX, box.maxY, box.maxZ)); + Vec3d V = center.subtract(coneStart); + double VlenSq = V.lengthSquared(); + Vec3d direction = coneEnd.subtract(coneStart); + double size = direction.length(); + double V1len = V.dotProduct(direction.normalize()); + double angRad = Math.toRadians(degrees); + double distanceClosestPoint = Math.cos(angRad) * Math.sqrt(VlenSq - V1len*V1len) - V1len * Math.sin(angRad); + + boolean angleCull = distanceClosestPoint > radius; + boolean frontCull = V1len > radius + size; + boolean backCull = V1len < -radius; + return !(angleCull || frontCull || backCull); + } + + //Drillgon200: Basically the AxisAlignedBB calculateIntercept method except it clamps to edge instead of returning null + public static Vec3d closestPointOnBB(AxisAlignedBB box, Vec3d vecA, Vec3d vecB){ + + Vec3d vec3d = collideWithXPlane(box, box.minX, vecA, vecB); + Vec3d vec3d1 = collideWithXPlane(box, box.maxX, vecA, vecB); + + if (vec3d1 != null && isClosest(vecA, vecB, vec3d, vec3d1)) + { + vec3d = vec3d1; + } + + vec3d1 = collideWithYPlane(box, box.minY, vecA, vecB); + + if (vec3d1 != null && isClosest(vecA, vecB, vec3d, vec3d1)) + { + vec3d = vec3d1; + } + + vec3d1 = collideWithYPlane(box, box.maxY, vecA, vecB); + + if (vec3d1 != null && isClosest(vecA, vecB, vec3d, vec3d1)) + { + vec3d = vec3d1; + } + + vec3d1 = collideWithZPlane(box, box.minZ, vecA, vecB); + + if (vec3d1 != null && isClosest(vecA, vecB, vec3d, vec3d1)) + { + vec3d = vec3d1; + } + + vec3d1 = collideWithZPlane(box, box.maxZ, vecA, vecB); + + if (vec3d1 != null && isClosest(vecA, vecB, vec3d, vec3d1)) + { + vec3d = vec3d1; + } + + return vec3d; + } + + protected static Vec3d collideWithXPlane(AxisAlignedBB box, double p_186671_1_, Vec3d p_186671_3_, Vec3d p_186671_4_) + { + Vec3d vec3d = getIntermediateWithXValue(p_186671_3_, p_186671_4_, p_186671_1_); + return clampToBox(box, vec3d); + //return vec3d != null && box.intersectsWithYZ(vec3d) ? vec3d : null; + } + + protected static Vec3d collideWithYPlane(AxisAlignedBB box, double p_186663_1_, Vec3d p_186663_3_, Vec3d p_186663_4_) + { + Vec3d vec3d = getIntermediateWithYValue(p_186663_3_, p_186663_4_, p_186663_1_); + return clampToBox(box, vec3d); + //return vec3d != null && box.intersectsWithXZ(vec3d) ? vec3d : null; + } + + protected static Vec3d collideWithZPlane(AxisAlignedBB box, double p_186665_1_, Vec3d p_186665_3_, Vec3d p_186665_4_) + { + Vec3d vec3d = getIntermediateWithZValue(p_186665_3_, p_186665_4_, p_186665_1_); + return clampToBox(box, vec3d); + //return vec3d != null && box.intersectsWithXY(vec3d) ? vec3d : null; + } + + protected static Vec3d clampToBox(AxisAlignedBB box, Vec3d vec) + { + return new Vec3d(MathHelper.clamp(vec.x, box.minX, box.maxX), MathHelper.clamp(vec.y, box.minY, box.maxY), MathHelper.clamp(vec.z, box.minZ, box.maxZ)); + } + + protected static boolean isClosest(Vec3d line1, Vec3d line2, @Nullable Vec3d p_186661_2_, Vec3d p_186661_3_) + { + if(p_186661_2_ == null) + return true; + double d1 = dist_to_segment_squared(p_186661_3_, line1, line2); + double d2 = dist_to_segment_squared(p_186661_2_, line1, line2); + if(Math.abs(d1-d2) < 0.01) + return line1.squareDistanceTo(p_186661_3_) < line1.squareDistanceTo(p_186661_2_); + return d1 < d2; + } + + //Drillgon200: https://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment + //Drillgon200: I'm not figuring this out myself. + protected static double dist_to_segment_squared(Vec3d point, Vec3d linePoint1, Vec3d linePoint2) { + double line_dist = linePoint1.squareDistanceTo(linePoint2); + if (line_dist == 0) return point.squareDistanceTo(linePoint1); + double t = ((point.x - linePoint1.x) * (linePoint2.x - linePoint1.x) + (point.y - linePoint1.y) * (linePoint2.y - linePoint1.y) + (point.z - linePoint1.z) * (linePoint2.z - linePoint1.z)) / line_dist; + t = MathHelper.clamp(t, 0, 1); + Vec3d pointOnLine = new Vec3d(linePoint1.x + t * (linePoint2.x - linePoint1.x), linePoint1.y + t * (linePoint2.y - linePoint1.y), linePoint1.z + t * (linePoint2.z - linePoint1.z)); + return point.squareDistanceTo(pointOnLine); + } + + /** + * Returns a new vector with x value equal to the second parameter, along the line between this vector and the + * passed in vector, or null if not possible. + */ + @Nullable + public static Vec3d getIntermediateWithXValue(Vec3d vec1, Vec3d vec, double x) + { + double d0 = vec.x - vec1.x; + double d1 = vec.y - vec1.y; + double d2 = vec.z - vec1.z; + + if (d0 * d0 < 1.0000000116860974E-7D) + { + return vec; + } + else + { + double d3 = (x - vec1.x) / d0; + if(d3 < 0){ + return new Vec3d(x, vec.y, vec.z); + } else if(d3 > 1){ + return new Vec3d(x, vec1.y, vec1.z); + } else { + return new Vec3d(vec1.x + d0 * d3, vec1.y + d1 * d3, vec1.z + d2 * d3); + } + //return d3 >= 0.0D && d3 <= 1.0D ? new Vec3d(vec1.x + d0 * d3, vec1.y + d1 * d3, vec1.z + d2 * d3) : null; + } + } + + /** + * Returns a new vector with y value equal to the second parameter, along the line between this vector and the + * passed in vector, or null if not possible. + */ + @Nullable + public static Vec3d getIntermediateWithYValue(Vec3d vec1, Vec3d vec, double y) + { + double d0 = vec.x - vec1.x; + double d1 = vec.y - vec1.y; + double d2 = vec.z - vec1.z; + + if (d1 * d1 < 1.0000000116860974E-7D) + { + return vec; + } + else + { + double d3 = (y - vec1.y) / d1; + if(d3 < 0){ + return new Vec3d(vec.x, y, vec.z); + } else if(d3 > 1){ + return new Vec3d(vec1.x, y, vec1.z); + } else { + return new Vec3d(vec1.x + d0 * d3, vec1.y + d1 * d3, vec1.z + d2 * d3); + } + //return d3 >= 0.0D && d3 <= 1.0D ? new Vec3d(vec1.x + d0 * d3, vec1.y + d1 * d3, vec1.z + d2 * d3) : null; + } + } + + /** + * Returns a new vector with z value equal to the second parameter, along the line between this vector and the + * passed in vector, or null if not possible. + */ + @Nullable + public static Vec3d getIntermediateWithZValue(Vec3d vec1, Vec3d vec, double z) + { + double d0 = vec.x - vec1.x; + double d1 = vec.y - vec1.y; + double d2 = vec.z - vec1.z; + + if (d2 * d2 < 1.0000000116860974E-7D) + { + return vec; + } + else + { + double d3 = (z - vec1.z) / d2; + if(d3 < 0){ + return new Vec3d(vec.x, vec.y, z); + } else if(d3 > 1){ + return new Vec3d(vec1.x, vec1.y, z); + } else { + return new Vec3d(vec1.x + d0 * d3, vec1.y + d1 * d3, vec1.z + d2 * d3); + } + //return d3 >= 0.0D && d3 <= 1.0D ? new Vec3d(vec1.x + d0 * d3, vec1.y + d1 * d3, vec1.z + d2 * d3) : null; + } + } + + public static Vec3d getEuler(Vec3d vec){ + double yaw = Math.toDegrees(Math.atan2(vec.x, vec.z)); + double sqrt = MathHelper.sqrt(vec.x * vec.x + vec.z * vec.z); + double pitch = Math.toDegrees(Math.atan2(vec.y, sqrt)); + return new Vec3d(yaw, pitch, 0); + } + + //Drillgon200: https://thebookofshaders.com/glossary/?search=smoothstep + public static double smoothstep(double t, double edge0, double edge1){ + t = MathHelper.clamp((t - edge0) / (edge1 - edge0), 0.0, 1.0); + return t * t * (3.0 - 2.0 * t); + } + public static float smoothstep(float t, float edge0, float edge1){ + t = MathHelper.clamp((t - edge0) / (edge1 - edge0), 0.0F, 1.0F); + return t * t * (3.0F - 2.0F * t); + } + + public static Vec3d getPosition(float interpolation, EntityPlayer player) { + if(interpolation == 1.0F) { + return new Vec3d(player.posX, player.posY + (player.getEyeHeight() - player.getDefaultEyeHeight()), player.posZ); + } else { + double d0 = player.prevPosX + (player.posX - player.prevPosX) * interpolation; + double d1 = player.prevPosY + (player.posY - player.prevPosY) * interpolation + (player.getEyeHeight() - player.getDefaultEyeHeight()); + double d2 = player.prevPosZ + (player.posZ - player.prevPosZ) * interpolation; + return new Vec3d(d0, d1, d2); + } + } + + public static boolean hasInventoryItem(InventoryPlayer inventory, Item ammo) { + for(int i = 0; i < inventory.getSizeInventory(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + if(stack.getItem() == ammo) { + return true; + } + } + return false; + } + + public static int countInventoryItem(InventoryPlayer inventory, Item ammo) { + int count = 0; + for(int i = 0; i < inventory.getSizeInventory(); i++) { + ItemStack stack = inventory.getStackInSlot(i); + if(stack.getItem() == ammo) { + count += stack.getCount(); + } + } + return count; + } + + /** + * Same as ItemStack.areItemStacksEqual, except the second one's tag only has to contain all the first one's tag, rather than being exactly equal. + */ + public static boolean areItemStacksCompatible(ItemStack base, ItemStack toTest, boolean shouldCompareSize){ + if (base.isEmpty() && toTest.isEmpty()) + { + return true; + } + else + { + if(!base.isEmpty() && !toTest.isEmpty()){ + + if(shouldCompareSize && base.getCount() != toTest.getCount()){ + return false; + } + else if (base.getItem() != toTest.getItem()) + { + return false; + } + else if (base.getMetadata() != toTest.getMetadata() && !(base.getMetadata() == OreDictionary.WILDCARD_VALUE)) + { + return false; + } + else if (base.getTagCompound() == null && toTest.getTagCompound() != null) + { + return false; + } + else + { + return (base.getTagCompound() == null || tagContainsOther(base.getTagCompound(), toTest.getTagCompound())) && base.areCapsCompatible(toTest); + } + } + } + return false; + } + + /** + * Returns true if the second compound contains all the tags and values of the first one, but it can have more. This helps with intermod compatibility + */ + public static boolean tagContainsOther(NBTTagCompound tester, NBTTagCompound container){ + if(tester == null && container == null){ + return true; + } if(tester == null ^ container == null){ + return false; + } else { + for(String s : tester.getKeySet()){ + if(!container.hasKey(s)){ + return false; + } else { + NBTBase nbt1 = tester.getTag(s); + NBTBase nbt2 = container.getTag(s); + if(nbt1 instanceof NBTTagCompound && nbt2 instanceof NBTTagCompound){ + if(!tagContainsOther((NBTTagCompound)nbt1, (NBTTagCompound) nbt2)) + return false; + } else { + if(!nbt1.equals(nbt2)) + return false; + } + } + } + } + return true; + } + + public static Vec3d normalFromRayTrace(RayTraceResult r) { + Vec3i n = r.sideHit.getDirectionVec(); + return new Vec3d(n.getX(), n.getY(), n.getZ()); + } + +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/ModDamageSource.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/ModDamageSource.java new file mode 100644 index 0000000000..7a5fcb3afb --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/ModDamageSource.java @@ -0,0 +1,30 @@ +package com.crowsofwar.avatar.client.render.lightning.main; + +import net.minecraft.util.DamageSource; +import net.minecraft.util.EntityDamageSourceIndirect; + +public class ModDamageSource extends DamageSource { + + public static DamageSource cheater = (new DamageSource("cheater")).setDamageIsAbsolute().setDamageBypassesArmor().setDamageAllowedInCreativeMode(); + + public static DamageSource blast = (new DamageSource("blast")).setExplosion().setDamageBypassesArmor().setDamageIsAbsolute(); + public static DamageSource electricity = (new DamageSource("electricity")).setDamageIsAbsolute().setDamageBypassesArmor(); + public static DamageSource crucible = new DamageSource("crucible").setDamageIsAbsolute().setDamageBypassesArmor(); + + public ModDamageSource(String p_i1566_1_) { + super(p_i1566_1_); + } + +// public static DamageSource causeDischargeDamage(EntityDischarge p_76353_0_, Entity p_76353_1_) +// { +// return (new EntityDamageSourceIndirect("electrified", p_76353_0_, p_76353_1_)).setDamageBypassesArmor(); +// } + + public static boolean getIsDischarge(DamageSource source) { + if(source instanceof EntityDamageSourceIndirect) + { + return ((EntityDamageSourceIndirect)source).damageType.equals("electrified"); + } + return false; + } +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/ModEventHandler.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/ModEventHandler.java new file mode 100644 index 0000000000..d0ef8c2bbb --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/ModEventHandler.java @@ -0,0 +1,151 @@ +package com.crowsofwar.avatar.client.render.lightning.main; + +import com.crowsofwar.avatar.client.render.lightning.math.Vec3; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent.Phase; +import net.minecraftforge.fml.common.network.NetworkRegistry; +import org.lwjgl.input.Keyboard; + +import java.util.Random; + +public class ModEventHandler { + + public static Random rand = new Random(); + int c = 0; // Cali's brute force for lightning + +// @SubscribeEvent +// public void soundRegistering(RegistryEvent.Register evt) { +// +// for(SoundEvent e : HBMSoundHandler.ALL_SOUNDS) { +// evt.getRegistry().register(e); +// } +// } + + @SubscribeEvent + public void onPlayerTick(TickEvent.PlayerTickEvent event) { + EntityPlayer player = event.player; + + if(!player.world.isRemote && event.phase == TickEvent.Phase.START) { + NBTTagCompound perDat = player.getEntityData().getCompoundTag(EntityPlayer.PERSISTED_NBT_TAG); +// int lightning = perDat.getInteger("lightningCharge"); + if(Keyboard.isKeyDown(Keyboard.KEY_I)) + c = 1; + int lightning = c; + if(lightning > 0){ + lightning++; c++; + if(lightning == 60){ + RayTraceResult r = Library.rayTraceIncludeEntities(player, 100, 1); + if(r != null && r.typeOfHit != RayTraceResult.Type.MISS){ + NBTTagCompound tag = new NBTTagCompound(); + tag.setString("type", "lightning"); + tag.setString("mode", "beam"); + tag.setDouble("hitX", r.hitVec.x); + tag.setDouble("hitY", r.hitVec.y); + tag.setDouble("hitZ", r.hitVec.z); + Vec3d normal = new Vec3d(r.sideHit.getXOffset(), r.sideHit.getYOffset(), r.sideHit.getZOffset()); + tag.setDouble("normX", normal.x); + tag.setDouble("normY", normal.y); + tag.setDouble("normZ", normal.z); + if(r.typeOfHit == RayTraceResult.Type.ENTITY){ + r.entityHit.attackEntityFrom(ModDamageSource.electricity, 20); + if(r.entityHit instanceof EntityLiving && ((EntityLiving)r.entityHit).getHealth() <= 0){ + r.entityHit.setDead(); + PacketDispatcher.wrapper.sendToAllTracking(new PacketSpecialDeath(r.entityHit, 2, (float)player.getLookVec().x, (float)player.getLookVec().y, (float)player.getLookVec().z), new NetworkRegistry.TargetPoint(player.world.provider.getDimension(), r.entityHit.posX, r.entityHit.posY, r.entityHit.posZ, 0)); + } + tag.setInteger("hitType", 1); + } else if(r.typeOfHit == RayTraceResult.Type.BLOCK){ + tag.setInteger("hitType", 0); + } + + Vec3d direction = player.getLookVec().scale(0.75); + switch(r.sideHit.getAxis()){ + case X: + direction = new Vec3d(-direction.x, direction.y, direction.z); + break; + case Y: + direction = new Vec3d(direction.x, -direction.y, direction.z); + break; + case Z: + direction = new Vec3d(direction.x, direction.y, -direction.z); + break; + } + + NBTTagCompound tag2 = new NBTTagCompound(); + tag2.setString("type", "spark"); + tag2.setString("mode", "coneBurst"); + tag2.setDouble("posX", r.hitVec.x); + tag2.setDouble("posY", r.hitVec.y); + tag2.setDouble("posZ", r.hitVec.z); + tag2.setDouble("dirX", direction.x); + tag2.setDouble("dirY", direction.y); + tag2.setDouble("dirZ", direction.z); + tag2.setFloat("r", 0.4F); + tag2.setFloat("g", 0.8F); + tag2.setFloat("b", 0.9F); + tag2.setFloat("a", 2F); + tag2.setInteger("lifetime", 5); + tag2.setInteger("randLifetime", 20); + tag2.setFloat("width", 0.04F); + tag2.setFloat("length", 0.7F); + tag2.setFloat("randLength", 1.5F); + tag2.setFloat("gravity", 0.1F); + tag2.setFloat("angle", 80F); + tag2.setInteger("count", 60+player.world.rand.nextInt(20)); + tag2.setFloat("randomVelocity", 0.4F); + PacketDispatcher.wrapper.sendToAllTracking(new AuxParticlePacketNT(tag2, r.hitVec.x, r.hitVec.y, r.hitVec.z), new NetworkRegistry.TargetPoint(player.world.provider.getDimension(), player.posX, player.posY, player.posZ, 0)); + Vec3d ssgChainPos = new Vec3d(-0.18, -0.1, 0.35); + ssgChainPos = ssgChainPos.rotatePitch((float) Math.toRadians(-player.rotationPitch)); + ssgChainPos = ssgChainPos.rotateYaw((float) Math.toRadians(-player.rotationYaw)); + ssgChainPos = ssgChainPos.add(player.posX, player.posY + player.getEyeHeight(), player.posZ); + PacketDispatcher.wrapper.sendToAllTracking(new AuxParticlePacketNT(tag, ssgChainPos.x, ssgChainPos.y, ssgChainPos.z), new NetworkRegistry.TargetPoint(player.world.provider.getDimension(), player.posX, player.posY, player.posZ, 0)); + } else { + NBTTagCompound tag = new NBTTagCompound(); + tag.setString("type", "lightning"); + tag.setString("mode", "beam"); + Vec3d hit = player.getPositionEyes(1).add(player.getLookVec().scale(100)); + tag.setDouble("hitX", hit.x); + tag.setDouble("hitY", hit.y); + tag.setDouble("hitZ", hit.z); + tag.setInteger("hitType", -1); + + Vec3d ssgChainPos = new Vec3d(-0.18, -0.1, 0.35); + ssgChainPos = ssgChainPos.rotatePitch((float) Math.toRadians(-player.rotationPitch)); + ssgChainPos = ssgChainPos.rotateYaw((float) Math.toRadians(-player.rotationYaw)); + ssgChainPos = ssgChainPos.add(player.posX, player.posY + player.getEyeHeight(), player.posZ); + + PacketDispatcher.wrapper.sendToAllTracking(new AuxParticlePacketNT(tag, ssgChainPos.x, ssgChainPos.y, ssgChainPos.z), new NetworkRegistry.TargetPoint(player.world.provider.getDimension(), player.posX, player.posY, player.posZ, 0)); + } + } + if(lightning == 84){ + lightning = 0; c = 0; + } + } + perDat.setInteger("lightningCharge", lightning); + } + + + if(player.world.isRemote && event.phase == Phase.START && !player.isInvisible() && !player.isSneaking()) { + + if(player.getUniqueID().toString().equals(Library.HbMinecraft)) { + + int i = player.ticksExisted * 3; + + Vec3 vec = Vec3.createVectorHelper(3, 0, 0); + + vec.rotateAroundY((float) (i * Math.PI / 180D)); + for(int k = 0; k < 5; k++) { + + vec.rotateAroundY((float) (1F * Math.PI / 180D)); + player.world.spawnParticle(EnumParticleTypes.TOWN_AURA, player.posX + vec.xCoord, player.posY + 1 + player.world.rand.nextDouble() * 0.05, player.posZ + vec.zCoord, 0.0, 0.0, 0.0); + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/ModEventHandlerClient.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/ModEventHandlerClient.java new file mode 100644 index 0000000000..c370b7a3e9 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/ModEventHandlerClient.java @@ -0,0 +1,60 @@ +package com.crowsofwar.avatar.client.render.lightning.main; + +import com.crowsofwar.avatar.client.render.lightning.particle.ParticleFirstPerson; +import com.google.common.collect.Queues; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.EntityLivingBase; +import org.lwjgl.opengl.Display; + +import java.util.ArrayDeque; +import java.util.HashSet; +import java.util.Set; + +public class ModEventHandlerClient { + + public static Set specialDeathEffectEntities = new HashSet<>(); + public static ArrayDeque firstPersonAuxParticles = Queues.newArrayDeque(); + + public static float deltaMouseX; + public static float deltaMouseY; + + public static float currentFOV = 70; + + public static void updateMouseDelta() { + Minecraft mc = Minecraft.getMinecraft(); + if(mc.inGameHasFocus && Display.isActive()) { + mc.mouseHelper.mouseXYChange(); + float f = mc.gameSettings.mouseSensitivity * 0.6F + 0.2F; + float f1 = f * f * f * 8.0F; + deltaMouseX = (float) mc.mouseHelper.deltaX * f1; + deltaMouseY = (float) mc.mouseHelper.deltaY * f1; + } else { + deltaMouseX = 0; + deltaMouseY = 0; + } + } + +// @SubscribeEvent +// public void renderHand(RenderHandEvent e){ +// if(Minecraft.getMinecraft().player.getHeldItemMainhand().getItem() instanceof IPostRender || Minecraft.getMinecraft().player.getHeldItemOffhand().getItem() instanceof IPostRender){ +// e.setCanceled(true); +// Minecraft mc = Minecraft.getMinecraft(); +// boolean flag = mc.getRenderViewEntity() instanceof EntityLivingBase && ((EntityLivingBase)mc.getRenderViewEntity()).isPlayerSleeping(); +// if (mc.gameSettings.thirdPersonView == 0 && !flag && !mc.gameSettings.hideGUI && !mc.playerController.isSpectator()) +// { +// mc.entityRenderer.enableLightmap(); +// mc.entityRenderer.itemRenderer.renderItemInFirstPerson(e.getPartialTicks()); +// mc.entityRenderer.disableLightmap(); +// } +// HbmShaderManager2.postProcess(); +// } +// } + +// @SubscribeEvent(priority = EventPriority.HIGHEST) +// public void cancelVanished(RenderLivingEvent.Pre event){ +// if(AvatarMod.proxy.isVanished(event.getEntity())){ +// event.setCanceled(true); +// } +// } + +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/PacketDispatcher.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/PacketDispatcher.java new file mode 100644 index 0000000000..0ddd40ab64 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/PacketDispatcher.java @@ -0,0 +1,27 @@ +package com.crowsofwar.avatar.client.render.lightning.main; + +import com.crowsofwar.avatar.AvatarInfo; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraftforge.fml.common.network.NetworkRegistry; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper; +import net.minecraftforge.fml.relauncher.Side; + +public class PacketDispatcher { + + public static final SimpleNetworkWrapper wrapper = NetworkRegistry.INSTANCE.newSimpleChannel(AvatarInfo.MOD_ID); + + public static void registerPackets(){ + int i = 0; + wrapper.registerMessage(AuxParticlePacketNT.Handler.class, AuxParticlePacketNT.class, i++, Side.CLIENT); + wrapper.registerMessage(AuxButtonPacket.Handler.class, AuxButtonPacket.class, i++, Side.SERVER); + wrapper.registerMessage(PacketSpecialDeath.Handler.class, PacketSpecialDeath.class, i++, Side.CLIENT); + + } + + public static void sendTo(IMessage message, EntityPlayerMP player){ + if(player != null) + wrapper.sendTo(message, player); + } + +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/PacketSpecialDeath.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/PacketSpecialDeath.java new file mode 100644 index 0000000000..7410b86f23 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/PacketSpecialDeath.java @@ -0,0 +1,90 @@ +package com.crowsofwar.avatar.client.render.lightning.main; + +import com.crowsofwar.avatar.client.render.lightning.math.Vec3; +import com.crowsofwar.avatar.client.render.lightning.particle.DisintegrationParticleHandler; +import io.netty.buffer.ByteBuf; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.DamageSource; +import net.minecraft.util.math.MathHelper; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; +import net.minecraftforge.fml.relauncher.ReflectionHelper; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import java.lang.reflect.Method; + +public class PacketSpecialDeath implements IMessage { + + public static Method rGetHurtSound; + + Entity serverEntity; + int entId; + int effectId; + float[] auxData; + Object auxObj; + + public PacketSpecialDeath() { + } + + public PacketSpecialDeath(Entity ent, int effectId, float... auxData) { + serverEntity = ent; + this.effectId = effectId; + this.entId = ent.getEntityId(); + this.auxData = auxData; + } + + @Override + public void fromBytes(ByteBuf buf) { + entId = buf.readInt(); + effectId = buf.readInt(); + int len = buf.readByte(); + auxData = new float[len]; + for(int i = 0; i < len; i++){ + auxData[i] = buf.readFloat(); + } + } + + @Override + public void toBytes(ByteBuf buf) { + buf.writeInt(entId); + buf.writeInt(effectId); + buf.writeByte(auxData.length); + for(float f : auxData){ + buf.writeFloat(f); + } + } + + public static class Handler implements IMessageHandler { + + @SuppressWarnings("deprecation") + @Override + @SideOnly(Side.CLIENT) + public IMessage onMessage(PacketSpecialDeath m, MessageContext ctx) { + Minecraft.getMinecraft().addScheduledTask(() -> { + Entity ent = Minecraft.getMinecraft().world.getEntityByID(m.entId); + if(ent instanceof EntityLivingBase){ + ent.setDead(); + ModEventHandlerClient.specialDeathEffectEntities.add((EntityLivingBase) ent); + DisintegrationParticleHandler.spawnLightningDisintegrateParticles(ent, new Vec3(m.auxData[0], m.auxData[1], m.auxData[2])); + } + }); + return null; + } + + } + + //Epic games lighting model falloff + public static float pointLightFalloff(float radius, float dist){ + float distOverRad = dist/radius; + float distOverRad2 = distOverRad*distOverRad; + float distOverRad4 = distOverRad2*distOverRad2; + + float falloff = MathHelper.clamp(1-distOverRad4, 0, 1); + return (falloff * falloff)/(dist*dist + 1); + } + +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/ResourceManager.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/ResourceManager.java new file mode 100644 index 0000000000..c92e09840f --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/ResourceManager.java @@ -0,0 +1,129 @@ +package com.crowsofwar.avatar.client.render.lightning.main; + +import com.crowsofwar.avatar.AvatarInfo; +import com.crowsofwar.avatar.client.render.lightning.animloader.AnimatedModel; +import com.crowsofwar.avatar.client.render.lightning.animloader.Animation; +import com.crowsofwar.avatar.client.render.lightning.animloader.ColladaLoader; +import com.crowsofwar.avatar.client.render.lightning.handler.HbmShaderManager2; +import com.crowsofwar.avatar.client.render.lightning.handler.HbmShaderManager2.Shader; +import com.crowsofwar.avatar.client.render.lightning.render.*; +import org.lwjgl.opengl.GL11; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.shader.Framebuffer; +import net.minecraft.util.ResourceLocation; + +public class ResourceManager { + + //God + public static final IModelCustom error = AdvancedModelLoader.loadModel(new ResourceLocation(AvatarInfo.MOD_ID, "models/error.obj")); + + //Drillgon200 model loading test + //Hey it worked! I wonder if I can edit the tessellator to call 1.12.2 builder buffer commands, because that's a lot less laggy. + + ////Obj Items + + //Shimmer Sledge + + ////Texture Items + + //Texture Entities + public static final ResourceLocation white = new ResourceLocation(AvatarInfo.MOD_ID, "textures/misc/white.png"); + public static final ResourceLocation turbofan_blades_tex = new ResourceLocation(AvatarInfo.MOD_ID, "textures/models/turbofan_blades.png"); + + //Blast + public static final ResourceLocation fireball = new ResourceLocation(AvatarInfo.MOD_ID, "textures/models/explosion/fireball.png"); + public static final ResourceLocation balefire = new ResourceLocation(AvatarInfo.MOD_ID, "textures/models/explosion/balefire.png"); + public static final ResourceLocation tomblast = new ResourceLocation(AvatarInfo.MOD_ID, "textures/models/explosion/tomblast.png"); + public static final ResourceLocation dust = new ResourceLocation(AvatarInfo.MOD_ID, "textures/models/explosion/dust.png"); + + //Lightning + public static final ResourceLocation fresnel_ms = new ResourceLocation(AvatarInfo.MOD_ID, "textures/models/bfg/fresnel_ms.png"); + public static final ResourceLocation bfg_ring_4 = new ResourceLocation(AvatarInfo.MOD_ID, "textures/models/bfg/ring3_lighter.png"); + public static final ResourceLocation bfg_lightning_1 = new ResourceLocation(AvatarInfo.MOD_ID, "textures/models/bfg/lightning_isolated.png"); + public static final ResourceLocation bfg_lightning_2 = new ResourceLocation(AvatarInfo.MOD_ID, "textures/models/bfg/multi_tester.png"); + public static final ResourceLocation bfg_core_lightning = new ResourceLocation(AvatarInfo.MOD_ID, "textures/models/bfg/additivebeam.png"); + public static final ResourceLocation bfg_beam = new ResourceLocation(AvatarInfo.MOD_ID, "textures/models/bfg/why.png"); + public static final ResourceLocation bfg_beam1 = new ResourceLocation(AvatarInfo.MOD_ID, "textures/models/bfg/why2.png"); + public static final ResourceLocation bfg_beam2 = new ResourceLocation(AvatarInfo.MOD_ID, "textures/models/bfg/beam_test0.png"); + public static final ResourceLocation bfg_prefire = new ResourceLocation(AvatarInfo.MOD_ID, "textures/models/bfg/perlin_fresnel.png"); + public static final ResourceLocation bfg_particle = new ResourceLocation(AvatarInfo.MOD_ID, "textures/models/bfg/particle.png"); + public static final ResourceLocation bfg_smoke = new ResourceLocation(AvatarInfo.MOD_ID, "textures/models/bfg/smoke3_bright2.png"); + + //Debug + public static final ResourceLocation uv_debug = new ResourceLocation(AvatarInfo.MOD_ID, "textures/misc/uv_debug.png"); + + public static final ResourceLocation noise_1 = new ResourceLocation(AvatarInfo.MOD_ID, "textures/misc/noise_1.png"); + public static final ResourceLocation noise_2 = new ResourceLocation(AvatarInfo.MOD_ID, "textures/misc/noise_2.png"); + public static final ResourceLocation noise_3 = new ResourceLocation(AvatarInfo.MOD_ID, "textures/misc/fract_noise.png"); + + public static ResourceLocation skin = new ResourceLocation(AvatarInfo.MOD_ID, "textures/models/ducc_st_engineer.png"); + + //ANIMATIONS + public static AnimatedModel lightning_fp; + public static Animation lightning_fp_anim; + + public static Shader downsample = HbmShaderManager2.loadShader(new ResourceLocation(AvatarInfo.MOD_ID, "shaders/downsample")); + public static Shader bloom_h = HbmShaderManager2.loadShader(new ResourceLocation(AvatarInfo.MOD_ID, "shaders/bloom_h")); + public static Shader bloom_v = HbmShaderManager2.loadShader(new ResourceLocation(AvatarInfo.MOD_ID, "shaders/bloom_v")); + public static Shader bloom_test = HbmShaderManager2.loadShader(new ResourceLocation(AvatarInfo.MOD_ID, "shaders/bloom_test")); + public static Shader lightning = HbmShaderManager2.loadShader(new ResourceLocation(AvatarInfo.MOD_ID, "shaders/lightning/lightning"), shader ->{ + GLCompat.bindAttribLocation(shader, 0, "pos"); + GLCompat.bindAttribLocation(shader, 1, "tex"); + GLCompat.bindAttribLocation(shader, 2, "color"); + }).withUniforms(shader -> { + GLCompat.activeTexture(GLCompat.GL_TEXTURE0+4); + Minecraft.getMinecraft().getTextureManager().bindTexture(ResourceManager.noise_2); + shader.uniform1i("noise", 4); + GLCompat.activeTexture(GLCompat.GL_TEXTURE0); + }); + public static Shader maxdepth = HbmShaderManager2.loadShader(new ResourceLocation(AvatarInfo.MOD_ID, "shaders/maxdepth")); + public static Shader lightning_gib = HbmShaderManager2.loadShader(new ResourceLocation(AvatarInfo.MOD_ID, "shaders/lightning/lightning_gib")).withUniforms(HbmShaderManager2.LIGHTMAP, shader -> { + GLCompat.activeTexture(GLCompat.GL_TEXTURE0+4); + Minecraft.getMinecraft().getTextureManager().bindTexture(ResourceManager.noise_2); + shader.uniform1i("noise", 4); + GLCompat.activeTexture(GLCompat.GL_TEXTURE0); + }); + public static Shader testlut = HbmShaderManager2.loadShader(new ResourceLocation(AvatarInfo.MOD_ID, "shaders/testlut")); + public static Shader flashlight_nogeo = HbmShaderManager2.loadShader(new ResourceLocation(AvatarInfo.MOD_ID, "shaders/flashlight_nogeo")); + public static Shader flashlight_deferred = HbmShaderManager2.loadShader(new ResourceLocation(AvatarInfo.MOD_ID, "shaders/flashlight_deferred")).withUniforms(shader -> { + shader.uniform2f("windowSize", Minecraft.getMinecraft().displayWidth, Minecraft.getMinecraft().displayHeight); + }); + + public static Shader crucible_lightning = HbmShaderManager2.loadShader(new ResourceLocation(AvatarInfo.MOD_ID, "shaders/crucible_lightning"), shader ->{ + GLCompat.bindAttribLocation(shader, 0, "pos"); + GLCompat.bindAttribLocation(shader, 1, "tex"); + GLCompat.bindAttribLocation(shader, 2, "in_color"); + }).withUniforms(shader -> { + GLCompat.activeTexture(GLCompat.GL_TEXTURE0+4); + Minecraft.getMinecraft().getTextureManager().bindTexture(ResourceManager.noise_2); + shader.uniform1i("noise", 4); + GLCompat.activeTexture(GLCompat.GL_TEXTURE0); + }); + + public static Shader gpu_particle_udpate = HbmShaderManager2.loadShader(new ResourceLocation(AvatarInfo.MOD_ID, "shaders/gpu_particle_update")).withUniforms(shader -> { + shader.uniform1i("particleData0", 2); + shader.uniform1i("particleData1", 3); + shader.uniform1i("particleData2", 4); + }); + + public static final Vbo test = Vbo.setupTestVbo(); + + public static void loadAnimatedModels(){ + + lightning_fp = ColladaLoader.load(new ResourceLocation(AvatarInfo.MOD_ID, "models/anim/lightning_fp_anim0.dae")); + lightning_fp_anim = ColladaLoader.loadAnim(4160, new ResourceLocation(AvatarInfo.MOD_ID, "models/anim/lightning_fp_anim0.dae")); + + } + + public static void init() { + Minecraft.getMinecraft().getTextureManager().bindTexture(fresnel_ms); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + Minecraft.getMinecraft().getTextureManager().bindTexture(noise_1); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + Minecraft.getMinecraft().getTextureManager().bindTexture(noise_2); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + } + +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/Spaghetti.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/Spaghetti.java new file mode 100644 index 0000000000..94e4c93035 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/main/Spaghetti.java @@ -0,0 +1,8 @@ +package com.crowsofwar.avatar.client.render.lightning.main; + +//Universal notation for shitty code +//I know TODO is a thing, but it's nice to hover over a class and see wtf is wrong with it +public @interface Spaghetti { + + public String value(); +} \ No newline at end of file diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/math/BobMathUtil.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/math/BobMathUtil.java new file mode 100644 index 0000000000..7b105a0469 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/math/BobMathUtil.java @@ -0,0 +1,244 @@ +package com.crowsofwar.avatar.client.render.lightning.math; + +import java.lang.reflect.Field; +import java.nio.FloatBuffer; +import java.util.Random; + +import javax.annotation.Nullable; +import javax.vecmath.Matrix3f; +import javax.vecmath.Quat4f; + +import com.crowsofwar.avatar.AvatarMod; +import com.crowsofwar.avatar.network.AvatarClientProxy; +import org.lwjgl.opengl.GL11; +import org.lwjgl.util.vector.Matrix4f; +import org.lwjgl.util.vector.Vector4f; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.ActiveRenderInfo; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.fml.relauncher.ReflectionHelper; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class BobMathUtil { + + public static Field r_viewMat; + public static Random rand = new Random(); + + public static double getAngleFrom2DVecs(double x1, double z1, double x2, double z2) { + + double upper = x1 * x2 + z1 * z2; + double lower = Math.sqrt(x1 * x1 + z1 * z1) * Math.sqrt(x2 * x2 + z2 * z2); + + double result = Math.toDegrees(Math.cos(upper / lower)); + + if(result >= 180) + result -= 180; + + return result; + } + + public static double getCrossAngle(Vec3d vel, Vec3d rel) { + + vel = vel.normalize(); + rel = rel.normalize(); + + double angle = Math.toDegrees(Math.acos(vel.dotProduct(rel))); + + if(angle >= 180) + angle -= 180; + + return angle; + } + + public static double getCrossAngle(Vec3 vel, Vec3 rel) { + + vel = vel.normalize(); + rel = rel.normalize(); + + double angle = Math.toDegrees(Math.acos(vel.dotProduct(rel))); + + if(angle >= 180) + angle -= 180; + + return angle; + } + + public static float remap(float num, float min1, float max1, float min2, float max2){ + return ((num - min1) / (max1 - min1)) * (max2 - min2) + min2; + } + + public static float remap01(float num, float min1, float max1){ + return (num - min1) / (max1 - min1); + } + + public static float remap01_clamp(float num, float min1, float max1){ + return MathHelper.clamp((num - min1) / (max1 - min1), 0, 1); + } + + public static Vec3d lerp(Vec3d vec0, Vec3d vec1, float interp){ + return new Vec3d( + vec0.x + (vec1.x - vec0.x)*interp, + vec0.y + (vec1.y - vec0.y)*interp, + vec0.z + (vec1.z - vec0.z)*interp); + } + + public static Vec3 getEulerAngles(Vec3 vec) { + double yaw = Math.toDegrees(Math.atan2(vec.xCoord, vec.zCoord)); + double sqrt = MathHelper.sqrt(vec.xCoord * vec.xCoord + vec.zCoord * vec.zCoord); + double pitch = Math.toDegrees(Math.atan2(vec.yCoord, sqrt)); + return Vec3.createVectorHelper(yaw, pitch, 0); + } + + /** + * + * @param vec vector + * @return vec3 containing yaw, pitch, nothing. + */ + public static Vec3d getEulerAngles(Vec3d vec) { + double yaw = Math.toDegrees(Math.atan2(vec.x, vec.z)); + double sqrt = MathHelper.sqrt(vec.x * vec.x + vec.z * vec.z); + double pitch = Math.toDegrees(Math.atan2(vec.y, sqrt)); + return new Vec3d(yaw, pitch-90, 0); + } + + public static Vec3d getVectorFromAngle(float yaw, float pitch){ + Vec3d vec = new Vec3d(0, 1, 0); + return vec.rotatePitch((float) Math.toRadians(pitch)).rotateYaw((float) Math.toRadians(yaw)); + } + + public static Vec3d getVectorFromAngle(Vec3d vec){ + return getVectorFromAngle((float)vec.x, (float)vec.y); + } + + /** + * !!EXPERIMENTAL!! + * Gets the minecraft world position from the opengl local positions. + * @param positions - the list of positions to be returned in world space + * @return an array of newly transformed vectors + */ + + @SideOnly(Side.CLIENT) + public static Vec3d[] viewFromLocal(Vector4f... positions){ + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, AvatarClientProxy.AUX_GL_BUFFER); + Matrix4f mv_mat = new Matrix4f(); + mv_mat.load(AvatarClientProxy.AUX_GL_BUFFER); + AvatarClientProxy.AUX_GL_BUFFER.rewind(); + Vec3d[] retArr = new Vec3d[positions.length]; + for(int i = 0; i < positions.length; i ++){ + Vector4f pos = new Vector4f(positions[i].x, positions[i].y, positions[i].z, positions[i].w); + Matrix4f.transform(mv_mat, pos, pos); + Vec3d pos2 = new Vec3d(pos.x, pos.y, pos.z); + retArr[i] = pos2; + } + return retArr; + } + + @SideOnly(Side.CLIENT) + public static Vec3d[] viewToLocal(Vector4f... positions){ + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, AvatarClientProxy.AUX_GL_BUFFER); + Matrix4f mv_mat = new Matrix4f(); + mv_mat.load(AvatarClientProxy.AUX_GL_BUFFER); + mv_mat.invert(); + AvatarClientProxy.AUX_GL_BUFFER.rewind(); + Vec3d[] retArr = new Vec3d[positions.length]; + for(int i = 0; i < positions.length; i ++){ + Vector4f pos = new Vector4f(positions[i].x, positions[i].y, positions[i].z, positions[i].w); + Matrix4f.transform(mv_mat, pos, pos); + Vec3d pos2 = new Vec3d(pos.x, pos.y, pos.z); + retArr[i] = pos2; + } + return retArr; + } + + //https://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/index.htm + //TODO See if I can replace with the more optimized looking version from glm? + public static void matrixFromQuat(Matrix3f m, Quat4f q){ + m.m00 = 1-2*q.y*q.y-2*q.z*q.z; + m.m01 = 2*q.x*q.y-2*q.z*q.w; + m.m02 = 2*q.x*q.z+2*q.y*q.w; + + m.m10 = 2*q.x*q.y+2*q.z*q.w; + m.m11 = 1-2*q.x*q.x-2*q.z*q.z; + m.m12 = 2*q.y*q.z-2*q.x*q.w; + + m.m20 = 2*q.x*q.z-2*q.y*q.w; + m.m21 = 2*q.y*q.z+2*q.x*q.w; + m.m22 = 1-2*q.x*q.x-2*q.y*q.y; + } + + public static boolean epsilonEquals(float num1, float num2, float eps){ + float diff = num1-num2; + return Math.abs(diff) < eps; + } + + public static boolean epsilonEquals(double num1, double num2, double eps){ + double diff = num1-num2; + return Math.abs(diff) < eps; + } + + public static boolean epsilonEquals(Vec3d a, Vec3d b, double eps){ + double dx = Math.abs(a.x-b.x); + double dy = Math.abs(a.y-b.y); + double dz = Math.abs(a.z-b.z); + + return dx < eps && dy < eps && dz < eps; + } + + public static int absMaxIdx(double... numbers){ + int idx = 0; + double max = -Double.MAX_VALUE; + for(int i = 0; i < numbers.length; i ++){ + double num = Math.abs(numbers[i]); + if(num > max){ + idx = i; + max = num; + } + } + return idx; + } + + public static Vec3 randVecInCone(Vec3 coneDirection, float angle){ + return randVecInCone(coneDirection, angle, rand); + } + + public static Vec3 randVecInCone(Vec3 coneDirection, float angle, Random rand){ + //Gets a random vector rotated within a cone and then rotates it to the particle data's direction + //Create a new vector and rotate it randomly about the x axis within the angle specified, then rotate that by random degrees to get the random cone vector + Vec3 up = Vec3.createVectorHelper(0, 1, 0); + up.rotateAroundX((float) Math.toRadians(rand.nextFloat()*(angle+rand.nextFloat()*angle))); + up.rotateAroundY((float) Math.toRadians(rand.nextFloat()*360)); + //Finds the angles for the particle direction and rotate our random cone vector to it. + Vec3 direction = Vec3.createVectorHelper(coneDirection.xCoord, coneDirection.yCoord, coneDirection.zCoord); + Vec3 angles = BobMathUtil.getEulerAngles(direction); + Vec3 newDirection = Vec3.createVectorHelper(up.xCoord, up.yCoord, up.zCoord); + newDirection.rotateAroundX((float) Math.toRadians(angles.yCoord-90)); + newDirection.rotateAroundY((float) Math.toRadians(angles.xCoord)); + return newDirection; + } + + public static Vec3d randVecInCone(Vec3d coneDirection, float angle){ + return randVecInCone(new Vec3(coneDirection), angle).toVec3d(); + } + + public static Vec3d randVecInCone(Vec3d coneDirection, float angle, Random rand){ + return randVecInCone(new Vec3(coneDirection), angle, rand).toVec3d(); + } + + public static Vec3d mix(Vec3d a, Vec3d b, float amount){ + return new Vec3d(a.x + (b.x - a.x)*amount, a.y + (b.y - a.y)*amount, a.z + (b.z - a.z)*amount); + } + + public static Vec3d mat4Transform(Vec3d vec, @Nullable Matrix4f mat){ + if(mat != null){ + double x = mat.m00 * vec.x + mat.m10 * vec.y + mat.m20 * vec.z + mat.m30; + double y = mat.m01 * vec.x + mat.m11 * vec.y + mat.m21 * vec.z + mat.m31; + double z = mat.m02 * vec.x + mat.m12 * vec.y + mat.m22 * vec.z + mat.m32; + return new Vec3d(x, y, z); + } + return vec; + } +} \ No newline at end of file diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/math/Transform.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/math/Transform.java new file mode 100644 index 0000000000..63131b0a28 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/math/Transform.java @@ -0,0 +1,131 @@ +package com.crowsofwar.avatar.client.render.lightning.math; + +import java.nio.FloatBuffer; + +import org.lwjgl.util.vector.Matrix4f; +import org.lwjgl.util.vector.Quaternion; + +import net.minecraft.client.renderer.GLAllocation; +import net.minecraft.client.renderer.GlStateManager; + +public class Transform { + + protected static FloatBuffer auxGLMatrix = GLAllocation.createDirectFloatBuffer(16); + + Vec3 scale; + Vec3 translation; + Quaternion rotation; + + public boolean hidden = false; + + public Transform(float[] matrix){ + scale = getScaleFromMatrix(matrix); + auxGLMatrix.put(matrix); + auxGLMatrix.rewind(); + rotation = new Quaternion().setFromMatrix((Matrix4f) new Matrix4f().load(auxGLMatrix)); + translation = Vec3.createVectorHelper(matrix[0*4+3], matrix[1*4+3], matrix[2*4+3]); + auxGLMatrix.rewind(); + } + + private Vec3 getScaleFromMatrix(float[] matrix){ + float scaleX = (float) Vec3.createVectorHelper(matrix[0], matrix[1], matrix[2]).lengthVector(); + float scaleY = (float) Vec3.createVectorHelper(matrix[4], matrix[5], matrix[6]).lengthVector(); + float scaleZ = (float) Vec3.createVectorHelper(matrix[8], matrix[9], matrix[10]).lengthVector(); + + matrix[0] = matrix[0]/scaleX; + matrix[1] = matrix[1]/scaleX; + matrix[2] = matrix[2]/scaleX; + + matrix[4] = matrix[4]/scaleY; + matrix[5] = matrix[5]/scaleY; + matrix[6] = matrix[6]/scaleY; + + matrix[8] = matrix[8]/scaleZ; + matrix[9] = matrix[9]/scaleZ; + matrix[10] = matrix[10]/scaleZ; + return Vec3.createVectorHelper(scaleX, scaleY, scaleZ); + } + + public void interpolateAndApply(Transform other, float inter){ + Vec3 trans = translation.interpolate(other.translation, inter); + Vec3 scale = this.scale.interpolate(other.scale, inter); + Quaternion rot = slerp(rotation, other.rotation, inter); + GlStateManager.quatToGlMatrix(auxGLMatrix, rot); + scale(auxGLMatrix, scale); + auxGLMatrix.put(12, (float) trans.xCoord); + auxGLMatrix.put(13, (float) trans.yCoord); + auxGLMatrix.put(14, (float) trans.zCoord); + + //for(int i = 0; i < 16; i ++){ + //System.out.print(auxGLMatrix.get(i) + " "); + //} + //System.out.println(); + GlStateManager.multMatrix(auxGLMatrix); + } + + private void scale(FloatBuffer matrix, Vec3 scale){ + matrix.put(0, (float) (matrix.get(0)*scale.xCoord)); + matrix.put(4, (float) (matrix.get(4)*scale.xCoord)); + matrix.put(8, (float) (matrix.get(8)*scale.xCoord)); + matrix.put(12, (float) (matrix.get(12)*scale.xCoord)); + + matrix.put(1, (float) (matrix.get(1)*scale.yCoord)); + matrix.put(5, (float) (matrix.get(5)*scale.yCoord)); + matrix.put(9, (float) (matrix.get(9)*scale.yCoord)); + matrix.put(13, (float) (matrix.get(13)*scale.yCoord)); + + matrix.put(2, (float) (matrix.get(2)*scale.zCoord)); + matrix.put(6, (float) (matrix.get(6)*scale.zCoord)); + matrix.put(10, (float) (matrix.get(10)*scale.zCoord)); + matrix.put(14, (float) (matrix.get(14)*scale.zCoord)); + } + + //Thanks, wikipedia + //God, I wish java had operator overloads. Those are one of my favorite things about c and glsl. + protected Quaternion slerp(Quaternion v0, Quaternion v1, float t) { + // Only unit quaternions are valid rotations. + // Normalize to avoid undefined behavior. + //Drillgon200: Any quaternions loaded from blender should be normalized already + //v0.normalise(); + //v1.normalise(); + + // Compute the cosine of the angle between the two vectors. + double dot = Quaternion.dot(v0, v1); + + // If the dot product is negative, slerp won't take + // the shorter path. Note that v1 and -v1 are equivalent when + // the negation is applied to all four components. Fix by + // reversing one quaternion. + if (dot < 0.0f) { + v1 = new Quaternion(-v1.x, -v1.y, -v1.z, -v1.w); + dot = -dot; + } + + final double DOT_THRESHOLD = 0.9999999; + if (dot > DOT_THRESHOLD) { + // If the inputs are too close for comfort, linearly interpolate + // and normalize the result. + Quaternion result = new Quaternion(v0.x + t*v1.x, + v0.y + t*v1.y, + v0.z + t*v1.z, + v0.w + t*v1.w); + result.normalise(); + return result; + } + + // Since dot is in range [0, DOT_THRESHOLD], acos is safe + double theta_0 = Math.acos(dot); // theta_0 = angle between input vectors + double theta = theta_0*t; // theta = angle between v0 and result + double sin_theta = Math.sin(theta); // compute this value only once + double sin_theta_0 = Math.sin(theta_0); // compute this value only once + + float s0 = (float) (Math.cos(theta) - dot * sin_theta / sin_theta_0); // == sin(theta_0 - theta) / sin(theta_0) + float s1 = (float) (sin_theta / sin_theta_0); + + return new Quaternion(s0*v0.x + s1*v1.x, + s0*v0.y + s1*v1.y, + s0*v0.z + s1*v1.z, + s0*v0.w + s1*v1.w); + } + +} \ No newline at end of file diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/math/Vec3.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/math/Vec3.java new file mode 100644 index 0000000000..655088854a --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/math/Vec3.java @@ -0,0 +1,327 @@ +package com.crowsofwar.avatar.client.render.lightning.math; + +import javax.vecmath.Matrix3f; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; + +public class Vec3 +{ + /** X coordinate of Vec3D */ + public double xCoord; + /** Y coordinate of Vec3D */ + public double yCoord; + /** Z coordinate of Vec3D */ + public double zCoord; + + /** + * Static method for creating a new Vec3D given the three x,y,z values. This is only called from the other static + * method which creates and places it in the list. + */ + public static Vec3 createVectorHelper(double p_72443_0_, double p_72443_2_, double p_72443_4_) + { + return new Vec3(p_72443_0_, p_72443_2_, p_72443_4_); + } + + public Vec3(Vec3d vec) { + this.xCoord = vec.x; + this.yCoord = vec.y; + this.zCoord = vec.z; + } + + public Vec3(double p_i1108_1_, double p_i1108_3_, double p_i1108_5_) + { + if (p_i1108_1_ == -0.0D) + { + p_i1108_1_ = 0.0D; + } + + if (p_i1108_3_ == -0.0D) + { + p_i1108_3_ = 0.0D; + } + + if (p_i1108_5_ == -0.0D) + { + p_i1108_5_ = 0.0D; + } + + this.xCoord = p_i1108_1_; + this.yCoord = p_i1108_3_; + this.zCoord = p_i1108_5_; + } + + /** + * Sets the x,y,z components of the vector as specified. + */ + public Vec3 setComponents(double p_72439_1_, double p_72439_3_, double p_72439_5_) + { + this.xCoord = p_72439_1_; + this.yCoord = p_72439_3_; + this.zCoord = p_72439_5_; + return this; + } + + public Vec3 set(Vec3 other){ + return setComponents(other.xCoord, other.yCoord, other.zCoord); + } + + /** + * Returns a new vector with the result of the specified vector minus this. + */ + public Vec3 subtract(Vec3 other) + { + /** + * Static method for creating a new Vec3D given the three x,y,z values. This is only called from the other + * static method which creates and places it in the list. + */ + return createVectorHelper(this.xCoord - other.xCoord, this.yCoord - other.yCoord, this.zCoord - other.zCoord); + } + + public Vec3 subtract(double x, double y, double z){ + return new Vec3(xCoord - x, yCoord - y, zCoord - z); + } + + /** + * Normalizes the vector to a length of 1 (except if it is the zero vector) + */ + public Vec3 normalize() + { + double d0 = (double)MathHelper.sqrt(this.xCoord * this.xCoord + this.yCoord * this.yCoord + this.zCoord * this.zCoord); + return d0 < 1.0E-4D ? createVectorHelper(0.0D, 0.0D, 0.0D) : createVectorHelper(this.xCoord / d0, this.yCoord / d0, this.zCoord / d0); + } + + public double dotProduct(Vec3 p_72430_1_) + { + return this.xCoord * p_72430_1_.xCoord + this.yCoord * p_72430_1_.yCoord + this.zCoord * p_72430_1_.zCoord; + } + + /** + * Returns a new vector with the result of this vector x the specified vector. + */ + public Vec3 crossProduct(Vec3 p_72431_1_) + { + /** + * Static method for creating a new Vec3D given the three x,y,z values. This is only called from the other + * static method which creates and places it in the list. + */ + return createVectorHelper(this.yCoord * p_72431_1_.zCoord - this.zCoord * p_72431_1_.yCoord, this.zCoord * p_72431_1_.xCoord - this.xCoord * p_72431_1_.zCoord, this.xCoord * p_72431_1_.yCoord - this.yCoord * p_72431_1_.xCoord); + } + + /** + * Adds the specified x,y,z vector components to this vector and returns the resulting vector. Does not change this + * vector. + */ + public Vec3 addVector(double p_72441_1_, double p_72441_3_, double p_72441_5_) + { + /** + * Static method for creating a new Vec3D given the three x,y,z values. This is only called from the other + * static method which creates and places it in the list. + */ + return createVectorHelper(this.xCoord + p_72441_1_, this.yCoord + p_72441_3_, this.zCoord + p_72441_5_); + } + + public Vec3 add(Vec3 other){ + return new Vec3(xCoord + other.xCoord, yCoord + other.yCoord, zCoord + other.zCoord); + } + + /** + * Euclidean distance between this and the specified vector, returned as double. + */ + public double distanceTo(Vec3 p_72438_1_) + { + double d0 = p_72438_1_.xCoord - this.xCoord; + double d1 = p_72438_1_.yCoord - this.yCoord; + double d2 = p_72438_1_.zCoord - this.zCoord; + return (double)MathHelper.sqrt(d0 * d0 + d1 * d1 + d2 * d2); + } + + /** + * The square of the Euclidean distance between this and the specified vector. + */ + public double squareDistanceTo(Vec3 p_72436_1_) + { + double d0 = p_72436_1_.xCoord - this.xCoord; + double d1 = p_72436_1_.yCoord - this.yCoord; + double d2 = p_72436_1_.zCoord - this.zCoord; + return d0 * d0 + d1 * d1 + d2 * d2; + } + + /** + * The square of the Euclidean distance between this and the vector of x,y,z components passed in. + */ + public double squareDistanceTo(double p_72445_1_, double p_72445_3_, double p_72445_5_) + { + double d3 = p_72445_1_ - this.xCoord; + double d4 = p_72445_3_ - this.yCoord; + double d5 = p_72445_5_ - this.zCoord; + return d3 * d3 + d4 * d4 + d5 * d5; + } + + /** + * Returns the length of the vector. + */ + public double lengthVector() + { + return (double)MathHelper.sqrt(this.xCoord * this.xCoord + this.yCoord * this.yCoord + this.zCoord * this.zCoord); + } + + public double lengthSquared(){ + return this.xCoord * this.xCoord + this.yCoord * this.yCoord + this.zCoord * this.zCoord; + } + + /** + * Returns a new vector with x value equal to the second parameter, along the line between this vector and the + * passed in vector, or null if not possible. + */ + public Vec3 getIntermediateWithXValue(Vec3 p_72429_1_, double p_72429_2_) + { + double d1 = p_72429_1_.xCoord - this.xCoord; + double d2 = p_72429_1_.yCoord - this.yCoord; + double d3 = p_72429_1_.zCoord - this.zCoord; + + if (d1 * d1 < 1.0000000116860974E-7D) + { + return null; + } + else + { + double d4 = (p_72429_2_ - this.xCoord) / d1; + return d4 >= 0.0D && d4 <= 1.0D ? createVectorHelper(this.xCoord + d1 * d4, this.yCoord + d2 * d4, this.zCoord + d3 * d4) : null; + } + } + + /** + * Returns a new vector with y value equal to the second parameter, along the line between this vector and the + * passed in vector, or null if not possible. + */ + public Vec3 getIntermediateWithYValue(Vec3 p_72435_1_, double p_72435_2_) + { + double d1 = p_72435_1_.xCoord - this.xCoord; + double d2 = p_72435_1_.yCoord - this.yCoord; + double d3 = p_72435_1_.zCoord - this.zCoord; + + if (d2 * d2 < 1.0000000116860974E-7D) + { + return null; + } + else + { + double d4 = (p_72435_2_ - this.yCoord) / d2; + return d4 >= 0.0D && d4 <= 1.0D ? createVectorHelper(this.xCoord + d1 * d4, this.yCoord + d2 * d4, this.zCoord + d3 * d4) : null; + } + } + + /** + * Returns a new vector with z value equal to the second parameter, along the line between this vector and the + * passed in vector, or null if not possible. + */ + public Vec3 getIntermediateWithZValue(Vec3 p_72434_1_, double p_72434_2_) + { + double d1 = p_72434_1_.xCoord - this.xCoord; + double d2 = p_72434_1_.yCoord - this.yCoord; + double d3 = p_72434_1_.zCoord - this.zCoord; + + if (d3 * d3 < 1.0000000116860974E-7D) + { + return null; + } + else + { + double d4 = (p_72434_2_ - this.zCoord) / d3; + return d4 >= 0.0D && d4 <= 1.0D ? createVectorHelper(this.xCoord + d1 * d4, this.yCoord + d2 * d4, this.zCoord + d3 * d4) : null; + } + } + + public String toString() + { + return "(" + this.xCoord + ", " + this.yCoord + ", " + this.zCoord + ")"; + } + + /** + * Rotates the vector around the x axis by the specified angle. + */ + public void rotateAroundX(float p_72440_1_) + { + float f1 = MathHelper.cos(p_72440_1_); + float f2 = MathHelper.sin(p_72440_1_); + double d0 = this.xCoord; + double d1 = this.yCoord * (double)f1 + this.zCoord * (double)f2; + double d2 = this.zCoord * (double)f1 - this.yCoord * (double)f2; + this.setComponents(d0, d1, d2); + } + + /** + * Rotates the vector around the y axis by the specified angle. + */ + public void rotateAroundY(float p_72442_1_) + { + float f1 = MathHelper.cos(p_72442_1_); + float f2 = MathHelper.sin(p_72442_1_); + double d0 = this.xCoord * (double)f1 + this.zCoord * (double)f2; + double d1 = this.yCoord; + double d2 = this.zCoord * (double)f1 - this.xCoord * (double)f2; + this.setComponents(d0, d1, d2); + } + + /** + * Rotates the vector around the z axis by the specified angle. + */ + public void rotateAroundZ(float p_72446_1_) + { + float f1 = MathHelper.cos(p_72446_1_); + float f2 = MathHelper.sin(p_72446_1_); + double d0 = this.xCoord * (double)f1 + this.yCoord * (double)f2; + double d1 = this.yCoord * (double)f1 - this.xCoord * (double)f2; + double d2 = this.zCoord; + this.setComponents(d0, d1, d2); + } + + public Vec3 interpolate(Vec3 other, double inter){ + return Vec3.createVectorHelper(this.xCoord + (other.xCoord - this.xCoord)*inter, this.yCoord + (other.yCoord - this.yCoord)*inter, this.zCoord + (other.zCoord - this.zCoord)*inter); + } + + public Vec3 mult(float mult){ + return Vec3.createVectorHelper(this.xCoord*mult, this.yCoord*mult, this.zCoord*mult); + } + + public Vec3 multd(double mult){ + return Vec3.createVectorHelper(this.xCoord*mult, this.yCoord*mult, this.zCoord*mult); + } + + public Vec3 negate(){ + return new Vec3(-xCoord, -yCoord, -zCoord); + } + + //https://en.wikipedia.org/wiki/Outer_product + public Matrix3f outerProduct(Vec3 other) { + Matrix3f mat = new Matrix3f( + (float)(xCoord*other.xCoord), (float)(xCoord*other.yCoord), (float)(xCoord*other.zCoord), + (float)(yCoord*other.xCoord), (float)(yCoord*other.yCoord), (float)(yCoord*other.zCoord), + (float)(zCoord*other.xCoord), (float)(zCoord*other.yCoord), (float)(zCoord*other.zCoord)); + return mat; + } + + public Vec3 matTransform(Matrix3f mat) { + double x,y,z; + x = mat.m00* xCoord + mat.m01*yCoord + mat.m02*zCoord; + y = mat.m10* xCoord + mat.m11*yCoord + mat.m12*zCoord; + z = mat.m20* xCoord + mat.m21*yCoord + mat.m22*zCoord; + return new Vec3(x, y, z); + } + + public Vec3 copy(){ + return new Vec3(xCoord, yCoord, zCoord); + } + + public Vec3d toVec3d(){ + return new Vec3d(xCoord, yCoord, zCoord); + } + + public Vec3 max(double d) { + return new Vec3(Math.max(xCoord, d), Math.max(yCoord, d), Math.max(zCoord, d)); + } + + public Vec3 min(double d) { + return new Vec3(Math.min(xCoord, d), Math.min(yCoord, d), Math.min(zCoord, d)); + } +} \ No newline at end of file diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/math/Vertex.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/math/Vertex.java new file mode 100644 index 0000000000..fb490645ad --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/math/Vertex.java @@ -0,0 +1,18 @@ +package com.crowsofwar.avatar.client.render.lightning.math; + +public class Vertex +{ + public float x, y, z; + + public Vertex(float x, float y) + { + this(x, y, 0F); + } + + public Vertex(float x, float y, float z) + { + this.x = x; + this.y = y; + this.z = z; + } +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/misc/AABBCollider.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/misc/AABBCollider.java new file mode 100644 index 0000000000..12c3d7cf57 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/misc/AABBCollider.java @@ -0,0 +1,57 @@ +package com.crowsofwar.avatar.client.render.lightning.misc; + +import com.crowsofwar.avatar.client.render.lightning.math.Vec3; +import net.minecraft.client.renderer.RenderGlobal; +import net.minecraft.util.math.AxisAlignedBB; + +import javax.vecmath.Matrix3f; + +public class AABBCollider extends Collider { + + public AxisAlignedBB box; + public float density = -1; + + //Only use if this is a static collider. + public AABBCollider(AxisAlignedBB box) { + this.box = box; + this.localCentroid = new Vec3(box.getCenter()); + } + + public AABBCollider(AxisAlignedBB box, float density) { + this.box = box; + float w = (float) (box.maxX-box.minX); + float h = (float) (box.maxY-box.minY); + float d = (float) (box.maxZ-box.minZ); + float vol = w*h*d; + this.mass = density*vol; + this.localCentroid = new Vec3(box.getCenter()); + //https://en.wikipedia.org/wiki/List_of_moments_of_inertia + float i_mass = mass/12F; + this.localInertiaTensor = new Matrix3f( + i_mass*(h*h+d*d), 0, 0, + 0, i_mass*(w*w+d*d), 0, + 0, 0, i_mass*(w*w+h*h)); + } + + @Override + public Vec3 support(Vec3 direction) { + return new Vec3( + direction.xCoord > 0 ? box.maxX : box.minX, + direction.yCoord > 0 ? box.maxY : box.minY, + direction.zCoord > 0 ? box.maxZ : box.minZ); + } + + @Override + public Collider copy() { + if(density == -1){ + return new AABBCollider(box); + } else { + return new AABBCollider(box, density); + } + } + + @Override + public void debugRender() { + RenderGlobal.drawSelectionBoundingBox(box, 1, 0, 0, 1); + } +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/misc/Collider.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/misc/Collider.java new file mode 100644 index 0000000000..a93497b742 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/misc/Collider.java @@ -0,0 +1,18 @@ +package com.crowsofwar.avatar.client.render.lightning.misc; + +import com.crowsofwar.avatar.client.render.lightning.math.Vec3; + +import javax.vecmath.Matrix3f; + +public abstract class Collider { + + public float mass; + public Matrix3f localInertiaTensor; + public Vec3 localCentroid; + + public abstract Vec3 support(Vec3 direction); + + public abstract Collider copy(); + + public abstract void debugRender(); +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/misc/Contact.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/misc/Contact.java new file mode 100644 index 0000000000..f2001d80ef --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/misc/Contact.java @@ -0,0 +1,143 @@ +package com.crowsofwar.avatar.client.render.lightning.misc; + +import com.crowsofwar.avatar.client.render.lightning.math.Vec3; +import net.minecraft.util.math.MathHelper; + +public class Contact { + + public RigidBody bodyA; + public RigidBody bodyB; + public Collider a; + public Collider b; + public Vec3 localA; + public Vec3 localB; + public Vec3 globalA; + public Vec3 globalB; + public Vec3 normal; + public float depth; + public Vec3 tangent; + public Vec3 bitangent; + + public Vec3 rA; + public Vec3 rB; + + public Jacobian normalContact; + public Jacobian tangentContact; + public Jacobian bitangentContact; + + public Contact(RigidBody bodyA, RigidBody bodyB, Collider a, Collider b, GJK.GJKInfo info) { + this.a = a; + this.b = b; + if(bodyA == null){ + bodyA = RigidBody.DUMMY; + } + if(bodyB == null){ + bodyB = RigidBody.DUMMY; + } + this.bodyA = bodyA; + this.bodyB = bodyB; + localA = bodyA.globalToLocalPos(info.contactPointA); + localB = bodyB.globalToLocalPos(info.contactPointB); + globalA = info.contactPointA; + globalB = info.contactPointB; + normal = info.normal; + depth = info.depth; + //https://box2d.org/posts/2014/02/computing-a-basis/ + if(Math.abs(normal.xCoord) >= 0.57735){ + tangent = new Vec3(normal.yCoord, -normal.xCoord, 0).normalize(); + } else { + tangent = new Vec3(0, normal.zCoord, -normal.yCoord).normalize(); + } + bitangent = normal.crossProduct(tangent); + + normalContact = new Jacobian(false); + tangentContact = new Jacobian(true); + bitangentContact = new Jacobian(true); + } + + public void init(float dt){ + rA = globalA.subtract(bodyA == RigidBody.DUMMY ? a.localCentroid : bodyA.globalCentroid); + rB = globalB.subtract(bodyB == RigidBody.DUMMY ? b.localCentroid : bodyB.globalCentroid); + + normalContact.init(this, normal, dt); + tangentContact.init(this, tangent, dt); + bitangentContact.init(this, bitangent, dt); + } + + public void solve(float dt){ + normalContact.solve(this, dt); + tangentContact.solve(this, dt); + bitangentContact.solve(this, dt); + } + + public static class Jacobian { + + boolean tangent; + + Vec3 j_va; + Vec3 j_wa; + Vec3 j_vb; + Vec3 j_wb; + + float bias; + double effectiveMass; + double totalLambda; + + public Jacobian(boolean tangent) { + this.tangent = tangent; + } + + public void init(Contact c, Vec3 dir, float dt){ + j_va = dir.negate(); + j_wa = c.rA.crossProduct(dir).negate(); + j_vb = dir; + j_wb = c.rB.crossProduct(dir); + + if(!tangent){ + float closingVel = (float)c.bodyA.linearVelocity.negate() + .subtract(c.bodyA.angularVelocity.crossProduct(c.rA)) + .add(c.bodyB.linearVelocity) + .add(c.bodyB.angularVelocity.crossProduct(c.rB)) + .dotProduct(c.normal); + float restitution = c.bodyA.restitution*c.bodyB.restitution; + + float beta = 0.2F; + float dslop = 0.0005F; + float rslop = 0.5F; + bias = -(beta/dt)*Math.max(c.depth-dslop, 0)+Math.max(restitution*closingVel-rslop, 0); + } + + effectiveMass = + c.bodyA.inv_mass + + j_wa.dotProduct(j_wa.matTransform(c.bodyA.inv_globalInertiaTensor)) + + c.bodyB.inv_mass + + j_wb.dotProduct(j_wb.matTransform(c.bodyB.inv_globalInertiaTensor)); + effectiveMass = 1D/effectiveMass; + + totalLambda = 0; + } + + public void solve(Contact c, float dt){ + double jv = + j_va.dotProduct(c.bodyA.linearVelocity) + + j_wa.dotProduct(c.bodyA.angularVelocity) + + j_vb.dotProduct(c.bodyB.linearVelocity) + + j_wb.dotProduct(c.bodyB.angularVelocity); + double lambda = effectiveMass * (-(jv + bias)); + double oldTotalLambda = totalLambda; + if(tangent){ + float friction = c.bodyA.friction*c.bodyB.friction; + double maxFriction = friction*c.normalContact.totalLambda; + totalLambda = MathHelper.clamp(totalLambda + lambda, -maxFriction, maxFriction); + } else { + totalLambda = Math.max(0, oldTotalLambda + lambda); + } + lambda = totalLambda - oldTotalLambda; + + c.bodyA.addLinearVelocity(j_va.multd(c.bodyA.inv_mass * lambda)); + c.bodyA.addAngularVelocity(j_wa.matTransform(c.bodyA.inv_globalInertiaTensor).multd(lambda)); + c.bodyB.addLinearVelocity(j_vb.multd(c.bodyB.inv_mass * lambda)); + c.bodyB.addAngularVelocity(j_wb.matTransform(c.bodyB.inv_globalInertiaTensor).multd(lambda)); + } + } +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/misc/ContactManifold.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/misc/ContactManifold.java new file mode 100644 index 0000000000..81971af35d --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/misc/ContactManifold.java @@ -0,0 +1,127 @@ +package com.crowsofwar.avatar.client.render.lightning.misc; + +import com.crowsofwar.avatar.client.render.lightning.math.BobMathUtil; +import com.crowsofwar.avatar.client.render.lightning.math.Vec3; + +public class ContactManifold { + + public static final float CONTACT_BREAK = 0.02F; + public static final float CONTACT_BREAK_SQ = CONTACT_BREAK*CONTACT_BREAK; + + public Contact[] contacts = new Contact[4]; + public int contactCount = 0; + + public ContactManifold() { + } + + public void update(){ + for(int i = 0; i < contactCount; i++){ + Contact c = contacts[i]; + c.globalA = c.bodyA.localToGlobalPos(c.localA); + c.globalB = c.bodyB.localToGlobalPos(c.localB); + + contacts[i].depth = (float) c.globalA.subtract(c.globalB).dotProduct(c.normal); + } + + for(int i = 0; i < contactCount; i ++){ + Contact c = contacts[i]; + //This is where contacts go to die + if(c.depth > CONTACT_BREAK){ + removeContact(i); + i --; + } else { + Vec3 proj = c.globalA.subtract(c.normal.mult(c.depth)); + double orthoDistToB = proj.subtract(c.globalB).lengthSquared(); + if(orthoDistToB > CONTACT_BREAK_SQ){ + removeContact(i); + i--; + } + } + } + } + + public void removeContact(int idx){ + contacts[idx] = null; + for(int i = idx; i < 3; i ++){ + contacts[i] = contacts[i+1]; + contacts[i+1] = null; + } + contactCount --; + } + + /** + * Adds a contact to this manifold + * @param c - the contact to try to add + * @return true if it added successfully + */ + public boolean addContact(Contact c){ + int idx = getContactIndex(c); + boolean replace = true; + if(idx < 0){ + if(contactCount < 4){ + idx = contactCount; + replace = false; + } else { + idx = getLeastRemoteIndex(c); + } + } + if(idx >= 0){ + if(replace){ + } else { + contactCount ++; + } + contacts[idx] = c; + return true; + } + return false; + } + + //Idea from bullet physics engine, the point where the quad made from the other four points has the most area is the point that matters least + //and we can remove it. We also want to keep the deepest point, so we just use a 0 area for the deepest point. + public int getLeastRemoteIndex(Contact c){ + float deepest = -Float.MAX_VALUE; + int deepIdx = -1; + for(int i = 0; i < contactCount; i ++){ + if(contacts[i].depth > deepest){ + deepest = contacts[i].depth; + deepIdx = i; + } + } + double res0 = 0F, res1 = 0F, res2 = 0F, res3 = 0F; + if(deepIdx != 0){ + Vec3 a = c.localA.subtract(contacts[1].localA); + Vec3 b = contacts[3].localA.subtract(contacts[2].localA); + res0 = a.crossProduct(b).lengthSquared(); + } + if(deepIdx != 1){ + Vec3 a = c.localA.subtract(contacts[0].localA); + Vec3 b = contacts[3].localA.subtract(contacts[2].localA); + res1 = a.crossProduct(b).lengthSquared(); + } + if(deepIdx != 2){ + Vec3 a = c.localA.subtract(contacts[0].localA); + Vec3 b = contacts[3].localA.subtract(contacts[1].localA); + res2 = a.crossProduct(b).lengthSquared(); + } + if(deepIdx != 3){ + Vec3 a = c.localA.subtract(contacts[0].localA); + Vec3 b = contacts[2].localA.subtract(contacts[1].localA); + res3 = a.crossProduct(b).lengthSquared(); + } + return BobMathUtil.absMaxIdx(res0, res1, res2, res3); + } + + public int getContactIndex(Contact c){ + int idx = -1; + double shortestDist = CONTACT_BREAK_SQ; + for(int i = 0; i < contactCount; i ++){ + double dist = contacts[i].localA.subtract(c.localA).lengthSquared(); + if(dist < shortestDist){ + shortestDist = dist; + idx = i; + } + } + return idx; + } + +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/misc/GJK.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/misc/GJK.java new file mode 100644 index 0000000000..5c263f8cea --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/misc/GJK.java @@ -0,0 +1,400 @@ +package com.crowsofwar.avatar.client.render.lightning.misc; + +import com.crowsofwar.avatar.client.render.lightning.math.Vec3; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class GJK { + + public static final int gjkMaxIterations = 64; + public static final int epaMaxIterations = 128; + public static float margin = 0; + + public static Simplex csoSimplex = new Simplex(); + + //https://www.youtube.com/watch?v=Qupqu1xe7Io + public static GJKInfo colliding(RigidBody bodyA, RigidBody bodyB, Collider a, Collider b){ + return colliding(bodyA, bodyB, a, b, true); + } + public static boolean collidesAny(RigidBody bodyA, RigidBody bodyB, Collider a, Collider b){ + return colliding(bodyA, bodyB, a, b, false) != null; + } + public static GJKInfo colliding(@Nullable RigidBody bodyA, @Nullable RigidBody bodyB, Collider a, Collider b, boolean epa){ + GJKInfo returnInfo = new GJKInfo(); + csoSimplex.reset(); + Vec3 direction = new Vec3(0, 0, 1); + Vec3 supportCSO = doCSOSupport(bodyA, bodyB, a, b, direction).v; + direction = supportCSO.negate(); + for(int iter = 0; iter < gjkMaxIterations; iter ++){ + supportCSO = doCSOSupport(bodyA, bodyB, a, b, direction).v; + if(supportCSO.dotProduct(direction) < 0){ + //We didn't find a closer point + returnInfo.result = Result.SEPARATED; + if(!epa) + return null; + return returnInfo; + } + switch(csoSimplex.size){ + case 0: + case 1: + //Should never happen since we already added 2 points. + break; + case 2: + Vec3 ab = csoSimplex.points[1].v.subtract(csoSimplex.points[0].v); + Vec3 ao = csoSimplex.points[0].v.negate(); + if(ab.dotProduct(ao) > 0){ + direction = ab.crossProduct(ao).crossProduct(ab); + } else { + csoSimplex.points[1] = null; + csoSimplex.size--; + direction = csoSimplex.points[0].v.mult(-1); + } + break; + case 3: + ab = csoSimplex.points[1].v.subtract(csoSimplex.points[0].v); + Vec3 ac = csoSimplex.points[2].v.subtract(csoSimplex.points[0].v); + Vec3 abc = ab.crossProduct(ac); + ao = csoSimplex.points[0].v.negate(); + direction = triangleCase(ab, ac, abc, ao); + break; + case 4: + ab = csoSimplex.points[1].v.subtract(csoSimplex.points[0].v); + ac = csoSimplex.points[2].v.subtract(csoSimplex.points[0].v); + Vec3 ad = csoSimplex.points[3].v.subtract(csoSimplex.points[0].v); + ao = csoSimplex.points[0].v.negate(); + Vec3 dir = tetraCase(ab, ac, ad, ao); + if(dir == null){ + if(epa) + EPA(bodyA, bodyB, a, b, returnInfo); + return returnInfo; + } else { + direction = dir; + } + break; + } + } + //Fail, most likely because the origin was exactly touching a simplex. + //I'm not sure how much of a performance impact adding checks for these would be. + //But it's worth checking out to see if it's needed or not + //TODO check + returnInfo.result = Result.GJK_FAILED; + return returnInfo; + } + + public static Vec3 triangleCase(Vec3 ab, Vec3 ac, Vec3 abc, Vec3 ao){ + if(abc.crossProduct(ac).dotProduct(ao) > 0){ + if(ac.dotProduct(ao) > 0){ + csoSimplex.points[1] = csoSimplex.points[2]; + csoSimplex.points[2] = null; + csoSimplex.size--; + return ac.crossProduct(ao).crossProduct(ac); + } else { + if(ab.dotProduct(ao) > 0){ + csoSimplex.points[2] = null; + csoSimplex.size--; + return ab.crossProduct(ao).crossProduct(ab); + } else { + csoSimplex.points[1] = null; + csoSimplex.points[2] = null; + csoSimplex.size -= 2; + return ao; + } + } + } else { + if(ab.crossProduct(abc).dotProduct(ao) > 0){ + if(ab.dotProduct(ao) > 0){ + csoSimplex.points[2] = null; + csoSimplex.size--; + return ab.crossProduct(ao).crossProduct(ab); + } else { + csoSimplex.points[1] = null; + csoSimplex.points[2] = null; + csoSimplex.size -= 2; + return ao; + } + } else { + if(abc.dotProduct(ao) > 0){ + return abc; + } else { + Mkv tmp = csoSimplex.points[2]; + csoSimplex.points[2] = csoSimplex.points[1]; + csoSimplex.points[1] = tmp; + return abc.negate(); + } + } + } + } + + public static Vec3 tetraCase(Vec3 ab, Vec3 ac, Vec3 ad, Vec3 ao){ + if(ab.crossProduct(ac).dotProduct(ao) > 0){ + csoSimplex.points[3] = null; + csoSimplex.size--; + return triangleCase(ab, ac, ab.crossProduct(ac), ao); + } else if(ac.crossProduct(ad).dotProduct(ao) > 0){ + csoSimplex.points[1] = csoSimplex.points[2]; + csoSimplex.points[2] = csoSimplex.points[3]; + csoSimplex.points[3] = null; + csoSimplex.size--; + return triangleCase(ac, ad, ac.crossProduct(ad), ao); + } else if(ad.crossProduct(ab).dotProduct(ao) > 0){ + csoSimplex.points[2] = csoSimplex.points[1]; + csoSimplex.points[1] = csoSimplex.points[3]; + csoSimplex.points[3] = null; + csoSimplex.size--; + return triangleCase(ad, ab, ad.crossProduct(ab), ao); + } else { + //Origin is contained by simplex, we're done + return null; + } + } + + //Calls csoSupport, possibly will be useful if I need to keep the support points found on a and b as well. + public static Mkv doCSOSupport(RigidBody bodyA, RigidBody bodyB, Collider a, Collider b, Vec3 direction){ + Vec3 supportCSO = new Vec3(0, 0, 0); + csoSupport(bodyA, bodyB, a, b, direction, supportCSO); + Mkv vert = new Mkv(supportCSO, direction); + csoSimplex.push_back(vert); + return vert; + } + + public static void csoSupport(RigidBody bodyA, RigidBody bodyB, Collider a, Collider b, Vec3 dir, Vec3 supportCSO){ + /*if(a.body != null){ + Vec3 vecA = a.body.globalToLocalVec(dir); + supportA.set(a.body.localToGlobalPos(a.support(vecA))); + } else { + supportA.set(a.support(dir)); + } + if(b.body != null){ + Vec3 vecB = b.body.globalToLocalVec(dir.negate()); + supportB.set(b.body.localToGlobalPos(b.support(vecB))); + } else { + supportB.set(b.support(dir.negate())); + } + supportCSO.set(supportA.subtract(supportB));*/ + supportCSO.set(localSupport(bodyA, a, dir).subtract(localSupport(bodyB, b, dir.negate()))); + } + + public static Vec3 localSupport(RigidBody body, Collider c, Vec3 worldDir){ + if(body != null){ + Vec3 localDir = body.globalToLocalVec(worldDir); + if(margin != 0){ + localDir = localDir.normalize(); + return body.localToGlobalPos(c.support(localDir).add(localDir.mult(margin))); + } + return body.localToGlobalPos(c.support(localDir)); + } else { + if(margin != 0){ + worldDir = worldDir.normalize(); + return c.support(worldDir).add(worldDir.mult(margin)); + } + return c.support(worldDir); + } + } + + /// EPA START /// + + private static List faces = new ArrayList<>(); + private static List edges = new ArrayList<>(); + private static Vec3[][] features = new Vec3[2][3]; + + public static void EPA(RigidBody bodyA, RigidBody bodyB, Collider a, Collider b, GJKInfo info){ + //Create the faces for the first tetrahedron + faces.add(buildFace(csoSimplex.points[0], csoSimplex.points[1], csoSimplex.points[2])); + faces.add(buildFace(csoSimplex.points[0], csoSimplex.points[2], csoSimplex.points[3])); + faces.add(buildFace(csoSimplex.points[0], csoSimplex.points[3], csoSimplex.points[1])); + faces.add(buildFace(csoSimplex.points[1], csoSimplex.points[2], csoSimplex.points[3])); + for(int iter = 0; iter < epaMaxIterations; iter ++){ + Mkv[] closestFace = null; + double smallestDist = Double.MAX_VALUE; + for(Mkv[] face : faces){ + double lenSq = originDistToPlaneSq(face); + if(lenSq < smallestDist){ + smallestDist = lenSq; + closestFace = face; + } + } + Mkv support = doCSOSupport(bodyA, bodyB, a, b, closestFace[3].v); + final float epsilon = 0.00001F; + if(distToPlaneSq(closestFace, support.v) < epsilon){ + info.result = Result.COLLIDING; + Vec3 separation = planeProjectOrigin(closestFace); + info.normal = separation.normalize(); + info.depth = (float) separation.lengthVector(); + for(int i = 0; i < 3; i ++){ + features[0][i] = localSupport(bodyA, a, closestFace[i].r); + features[1][i] = localSupport(bodyB, b, closestFace[i].r.negate()); + } + Vec3 bCoords = barycentricCoords(closestFace, separation); + info.contactPointA = new Vec3( + features[0][0].xCoord*bCoords.xCoord+features[0][1].xCoord*bCoords.yCoord+features[0][2].xCoord*bCoords.zCoord, + features[0][0].yCoord*bCoords.xCoord+features[0][1].yCoord*bCoords.yCoord+features[0][2].yCoord*bCoords.zCoord, + features[0][0].zCoord*bCoords.xCoord+features[0][1].zCoord*bCoords.yCoord+features[0][2].zCoord*bCoords.zCoord); + //Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleTauHit(Minecraft.getMinecraft().world, features[0][0].xCoord, features[0][0].yCoord, features[0][0].zCoord, 1F, new Vec3d(0, 0, 1))); + //Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleTauHit(Minecraft.getMinecraft().world, features[0][1].xCoord, features[0][1].yCoord, features[0][1].zCoord, 1F, new Vec3d(0, 0, 1))); + //Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleTauHit(Minecraft.getMinecraft().world, features[0][2].xCoord, features[0][2].yCoord, features[0][2].zCoord, 1F, new Vec3d(0, 0, 1))); + //Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleTauHit(Minecraft.getMinecraft().world, info.contactPointA.xCoord, info.contactPointA.yCoord, info.contactPointA.zCoord, 2F, new Vec3d(0, 0, 1))); + info.contactPointB = new Vec3( + features[1][0].xCoord*bCoords.xCoord+features[1][1].xCoord*bCoords.yCoord+features[1][2].xCoord*bCoords.zCoord, + features[1][0].yCoord*bCoords.xCoord+features[1][1].yCoord*bCoords.yCoord+features[1][2].yCoord*bCoords.zCoord, + features[1][0].zCoord*bCoords.xCoord+features[1][1].zCoord*bCoords.yCoord+features[1][2].zCoord*bCoords.zCoord); + + faces.clear(); + return; + } + //E x p a n d the polytope + Iterator itr = faces.iterator(); + while(itr.hasNext()){ + Mkv[] face = itr.next(); + if(face[3].v.dotProduct(support.v.subtract(face[0].v)) > 0){ + itr.remove(); + Mkv[] edge = new Mkv[]{face[1], face[0]}; + if(!removeEdge(edge)){ + edge[0] = face[0]; + edge[1] = face[1]; + edges.add(edge); + } + edge = new Mkv[]{face[2], face[1]}; + if(!removeEdge(edge)){ + edge[0] = face[1]; + edge[1] = face[2]; + edges.add(edge); + } + edge = new Mkv[]{face[0], face[2]}; + if(!removeEdge(edge)){ + edge[0] = face[2]; + edge[1] = face[0]; + edges.add(edge); + } + } + } + for(Mkv[] edge : edges){ + faces.add(buildFace(edge[0], edge[1], support)); + } + edges.clear(); + } + faces.clear(); + info.result = Result.EPA_FAILED; + } + + //I don't trust ArrayList's default remove to work with arrays, and I don't want to spend the time to check it. + public static boolean removeEdge(Mkv[] edge){ + Iterator itr = edges.iterator(); + while(itr.hasNext()){ + Mkv[] edge2 = itr.next(); + if(edge[0] == edge2[0] && edge[1] == edge2[1]){ + itr.remove(); + return true; + } + } + return false; + } + + public static Vec3 planeProjectOrigin(Mkv[] face){ + Vec3 point = face[0].v.negate(); + double dot = face[3].v.dotProduct(point); + return face[3].v.mult((float) dot).negate(); + } + + public static double distToPlaneSq(Mkv[] face, Vec3 point){ + double dot = face[3].v.dotProduct(point.subtract(face[0].v)); + Vec3 proj = face[3].v.mult((float) dot); + return proj.lengthSquared(); + } + + public static double originDistToPlaneSq(Mkv[] face){ + double dot = face[0].v.dotProduct(face[3].v); + Vec3 proj = face[3].v.mult((float) dot); + return proj.lengthSquared(); + } + + public static Mkv[] buildFace(Mkv a, Mkv b, Mkv c){ + Vec3 ab = b.v.subtract(a.v); + Vec3 ac = c.v.subtract(a.v); + Vec3 ao = a.v.negate(); + Vec3 normal = ab.crossProduct(ac).normalize(); + if(normal.dotProduct(ao) < 0){ + return new Mkv[]{a, b, c, new Mkv(normal, null)}; + } else { + return new Mkv[]{a, c, b, new Mkv(normal.negate(), null)}; + } + } + + public static Vec3 barycentricCoords(Mkv[] face, Vec3 point){ + //Idea is that the barycentric coordinate is the area of the opposite triangle to the vertex, so we compute that with the cross product + //and make that the weight. You also have to divide by the sum of the weights to normalize them. + //I was under the impression that the area of the triangle would be the cross product over 2, but apparently the barycentric coords don't need that. + //I'm thinking this is because the normalization deals with that for me. + double u = face[1].v.subtract(point).crossProduct(face[2].v.subtract(point)).lengthVector(); + double v = face[0].v.subtract(point).crossProduct(face[2].v.subtract(point)).lengthVector(); + double w = face[0].v.subtract(point).crossProduct(face[1].v.subtract(point)).lengthVector(); + //Normalize + double uvw = u+v+w; + return new Vec3(u, v, w).multd(1/uvw); + } + + public static class Simplex { + public int size = 0; + public Mkv[] points = new Mkv[4]; + + public void push_back(Mkv vec){ + for(int i = Math.min(size, 2); i >= 0; i --){ + points[i+1] = points[i]; + } + points[0] = vec; + size ++; + if(size > 4) + size = 4; + } + + public void reset(){ + size = 0; + for(int i = 0; i < 4; i ++){ + points[i] = null; + } + } + + public Simplex copy(){ + Simplex simp = new Simplex(); + simp.size = size; + for(int i = 0; i < 4; i ++){ + simp.points[i] = points[i].copy(); + } + return simp; + } + } + + //Minkowski vertex, a struct for both the vertex on the minkowski difference and the ray that got there for extracting the contact. + //Idea from the bullet physics engine. + public static class Mkv { + public Vec3 v; + public Vec3 r; + + public Mkv(Vec3 point, Vec3 direction) { + this.v = point; + this.r = direction; + } + + public Mkv copy(){ + Mkv vert = new Mkv(v.copy(), r.copy()); + return vert; + } + } + + public static class GJKInfo { + public Result result; + public Vec3 normal; + public float depth; + public Vec3 contactPointA; + public Vec3 contactPointB; + } + + public static enum Result { + COLLIDING, + SEPARATED, + GJK_FAILED, + EPA_FAILED; + } +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/misc/LensVisibilityHandler.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/misc/LensVisibilityHandler.java new file mode 100644 index 0000000000..67eee716b6 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/misc/LensVisibilityHandler.java @@ -0,0 +1,162 @@ +package com.crowsofwar.avatar.client.render.lightning.misc; + +import java.nio.FloatBuffer; +import java.util.HashMap; +import java.util.Map; + +import com.crowsofwar.avatar.AvatarInfo; +import com.crowsofwar.avatar.client.render.lightning.render.GLCompat; +import com.crowsofwar.avatar.network.AvatarClientProxy; +import com.crowsofwar.avatar.network.AvatarClientProxy; +import org.lwjgl.opengl.GL11; + +import net.minecraft.client.renderer.GlStateManager; +import net.minecraftforge.client.event.RenderWorldLastEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +@Mod.EventBusSubscriber(value = Side.CLIENT, modid = AvatarInfo.MOD_ID) +public class LensVisibilityHandler { + + static Map lensSpikes = new HashMap<>(); + static int currentId = 0; + public static int checkSphere = -1; + + public static int findId(){ + while(lensSpikes.containsKey(currentId)){ + currentId ++; + } + return currentId; + } + + public static int generate(FloatBuffer matrix){ + int id = findId(); + float[] mat = new float[16]; + matrix.get(mat); + matrix.rewind(); + LensSpikeInfo i = new LensSpikeInfo(mat); + lensSpikes.put(id, i); + return id; + } + + public static void delete(int id){ + LensSpikeInfo i = lensSpikes.get(id); + if(i != null){ + i.cleanup(); + lensSpikes.remove(id); + } + } + + public static float getVisibility(int id){ + LensSpikeInfo i = lensSpikes.get(id); + if(i != null){ + return i.visibility; + } + return 0.0F; + } + + public static float[] getMatrixBuf(int id){ + LensSpikeInfo i = lensSpikes.get(id); + if(i != null){ + return i.modelviewMatrix; + } + return null; + } + + public static void putMatrixBuf(int id, FloatBuffer matrix){ + LensSpikeInfo i = lensSpikes.get(id); + if(i != null){ + matrix.get(i.modelviewMatrix); + matrix.rewind(); + } + } + + @SubscribeEvent + public static void renderLast(RenderWorldLastEvent event) { + for(LensSpikeInfo i : lensSpikes.values()){ + i.updateVisibility(); + } + } + + public static class LensSpikeInfo { + public float[] modelviewMatrix; + public float visibility = 0.0F; + private int totalFragmentsQuery; + private int fragmentsPassedQuery; + + public LensSpikeInfo(float[] matrix) { + this.modelviewMatrix = matrix; + totalFragmentsQuery = GLCompat.genQueries(); + fragmentsPassedQuery = GLCompat.genQueries(); + + GlStateManager.colorMask(false, false, false, false); + GlStateManager.depthMask(false); + GlStateManager.disableCull(); + + GL11.glPushMatrix(); + AvatarClientProxy.AUX_GL_BUFFER.put(matrix); + AvatarClientProxy.AUX_GL_BUFFER.rewind(); + GL11.glLoadMatrix(AvatarClientProxy.AUX_GL_BUFFER); + GL11.glScaled(0.05, 0.05, 0.05); + GlStateManager.disableDepth(); + GLCompat.beginQuery(GLCompat.GL_SAMPLES_PASSED, totalFragmentsQuery); + GL11.glCallList(checkSphere); + GLCompat.endQuery(GLCompat.GL_SAMPLES_PASSED); + + GlStateManager.enableDepth(); + GLCompat.beginQuery(GLCompat.GL_SAMPLES_PASSED, fragmentsPassedQuery); + GL11.glCallList(checkSphere); + GLCompat.endQuery(GLCompat.GL_SAMPLES_PASSED); + GL11.glPopMatrix(); + + GlStateManager.colorMask(true, true, true, true); + GlStateManager.depthMask(true); + GlStateManager.enableCull(); + } + + public void updateVisibility(){ + int totalDone = GLCompat.getQueryObject(totalFragmentsQuery, GLCompat.GL_QUERY_RESULT_AVAILABLE); + int passedDone = GLCompat.getQueryObject(fragmentsPassedQuery, GLCompat.GL_QUERY_RESULT_AVAILABLE); + if(totalDone != 0 && passedDone != 0){ + float total = GLCompat.getQueryObject(totalFragmentsQuery, GLCompat.GL_QUERY_RESULT); + float passed = GLCompat.getQueryObject(fragmentsPassedQuery, GLCompat.GL_QUERY_RESULT); + visibility = passed/total; + + GlStateManager.colorMask(false, false, false, false); + GlStateManager.depthMask(false); + GlStateManager.disableCull(); + + GL11.glPushMatrix(); + AvatarClientProxy.AUX_GL_BUFFER.put(modelviewMatrix); + AvatarClientProxy.AUX_GL_BUFFER.rewind(); + GL11.glLoadMatrix(AvatarClientProxy.AUX_GL_BUFFER); + GL11.glScaled(0.1, 0.1, 0.1); + GlStateManager.disableDepth(); + GLCompat.beginQuery(GLCompat.GL_SAMPLES_PASSED, totalFragmentsQuery); + GL11.glCallList(checkSphere); + GLCompat.endQuery(GLCompat.GL_SAMPLES_PASSED); + + GlStateManager.enableDepth(); + GLCompat.beginQuery(GLCompat.GL_SAMPLES_PASSED, fragmentsPassedQuery); + GL11.glCallList(checkSphere); + GLCompat.endQuery(GLCompat.GL_SAMPLES_PASSED); + GL11.glPopMatrix(); + + GlStateManager.colorMask(true, true, true, true); + GlStateManager.depthMask(true); + GlStateManager.enableCull(); + } + } + + public void cleanup(){ + GLCompat.deleteQueries(totalFragmentsQuery); + GLCompat.deleteQueries(fragmentsPassedQuery); + //That modelViewMatrix not being deleted might cause a memory leak, but if it does, I don't know what to do about it in java! + } + } + + +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/misc/RigidBody.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/misc/RigidBody.java new file mode 100644 index 0000000000..b23ab751c1 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/misc/RigidBody.java @@ -0,0 +1,466 @@ +package com.crowsofwar.avatar.client.render.lightning.misc; + +import com.crowsofwar.avatar.client.render.lightning.math.BobMathUtil; +import com.crowsofwar.avatar.client.render.lightning.math.Vec3; +import com.crowsofwar.avatar.network.AvatarClientProxy; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import org.lwjgl.opengl.GL11; + +import javax.vecmath.AxisAngle4f; +import javax.vecmath.Matrix3f; +import javax.vecmath.Quat4f; +import java.nio.FloatBuffer; +import java.util.ArrayList; +import java.util.List; + +public class RigidBody { + + public static final Vec3[] cardinals = new Vec3[]{ + new Vec3(1, 0, 0), new Vec3(0, 1, 0), new Vec3(0, 0, 1), + new Vec3(-1, 0, 0), new Vec3(0, -1, 0), new Vec3(0, 0, -1)}; + + public static final RigidBody DUMMY = new RigidBody(null){ + public void solveContacts(float dt) {}; + + public void impulse(Vec3 force, Vec3 position) {}; + public void updateOrientation() {}; + public void updateGlobalCentroidFromPosition() {}; + public void updatePositionFromGlobalCentroid() {}; + public void doTimeStep(float dt) {}; + public void addColliders(Collider... collide) {}; + + public Vec3 globalToLocalPos(Vec3 pos) {return pos;}; + public Vec3 localToGlobalPos(Vec3 pos) {return pos;}; + public Vec3 globalToLocalVec(Vec3 vec) {return vec;}; + public Vec3 localToGlobalVec(Vec3 vec) {return vec;}; + + public void addLinearVelocity(Vec3 v) {}; + public void addAngularVelocity(Vec3 v) {}; + + public void addContact(Contact c) {}; + }; + + static { + DUMMY.inv_rotation = (Matrix3f) DUMMY.rotation.clone(); + DUMMY.localInertiaTensor = new Matrix3f(); + DUMMY.inv_localInertiaTensor = new Matrix3f(); + DUMMY.inv_globalInertiaTensor = new Matrix3f(); + DUMMY.localCentroid = new Vec3(0, 0, 0); + DUMMY.globalCentroid = new Vec3(0, 0, 0); + } + + public World world; + public AxisAlignedBB boundingBox; + + public List colliders = new ArrayList<>(); + public List colliderBoundingBoxes = new ArrayList<>(); + + public Vec3 position = new Vec3(0, 0, 0); + public Vec3 globalCentroid; + public Matrix3f rotation = new Matrix3f(); + public Matrix3f inv_rotation; + + public Vec3 prevPosition = new Vec3(0, 0, 0); + public Quat4f prevRotation = new Quat4f(); + + public Vec3 linearVelocity = new Vec3(0, 0, 0); + public Vec3 angularVelocity = new Vec3(0, 0, 0); + public Vec3 force = new Vec3(0, 0, 0); + public Vec3 torque = new Vec3(0, 0, 0); + + public float mass; + public float inv_mass; + public Matrix3f localInertiaTensor; + public Matrix3f inv_localInertiaTensor; + public Matrix3f inv_globalInertiaTensor; + public float friction = 0.5F; + public float restitution = 0; + + public Vec3 localCentroid; + + public ContactManifold contacts = new ContactManifold(); + + public RigidBody(World w) { + this.world = w; + rotation.setIdentity(); + } + + public RigidBody(World w, double x, double y, double z) { + this(w); + this.position = new Vec3(x, y, z); + } + + public void minecraftTimestep(){ + this.setPrevData(); + int timeStepSubDiv = 8; + float step = 0.05F/(float)timeStepSubDiv; + for(int i = 0; i < timeStepSubDiv; i ++){ + doTimeStep(step); + } + } + + public void doTimeStep(float dt){ + contacts.update(); + //Do collision detection + GJK.GJKInfo bestInfo = null; + Collider a = null; + Collider b = null; + List l = world.getCollisionBoxes(null, boundingBox); + for(AxisAlignedBB box : l){ + for(int i = 0; i < colliders.size(); i ++){ + Collider c = colliders.get(i); + if(!colliderBoundingBoxes.get(i).intersects(box)) + continue; + b = new AABBCollider(box); + GJK.GJKInfo info = GJK.colliding(this, null, c, b); + if(info.result == GJK.Result.COLLIDING /*&& (bestInfo == null || bestInfo.depth < info.depth)*/){ + //No need to find whatever is deepest. We can just add every contact and let the manifold sort itself out correctly. + //bestInfo = info; + contacts.addContact(new Contact(this, null, c, b, info)); + } + } + } + + //if(bestInfo != null){ + // contacts.addContact(new Contact(this, null, a, b, bestInfo)); + //} + + solveContacts(dt); + integrateVelocityAndPosition(dt); + } + + public void integrateVelocityAndPosition(float dt){ + //Integrate velocity + linearVelocity = linearVelocity.add(force.mult(inv_mass*dt)); + angularVelocity = angularVelocity.add(torque.mult(dt).matTransform(inv_globalInertiaTensor)); + + force.setComponents(0, 0, 0); + torque.setComponents(0, 0, 0); + + //Integrate position + globalCentroid = globalCentroid.add(linearVelocity.mult(dt)); + if(angularVelocity.lengthSquared() > 0){ + Vec3 axis = angularVelocity.normalize(); + double angle = angularVelocity.lengthVector()*dt; + Matrix3f turn = new Matrix3f(); + turn.set(new AxisAngle4f((float)axis.xCoord, (float)axis.yCoord, (float)axis.zCoord, (float)angle)); + turn.mul(rotation); + rotation = turn; + updateOrientation(); + } + updatePositionFromGlobalCentroid(); + updateAABBs(); + addLinearVelocity(new Vec3(0, -9.81*dt, 0)); + } + + public void setPrevData(){ + this.prevPosition.set(position); + setFromMat(prevRotation, rotation); + } + + public void addContact(Contact c){ + contacts.addContact(c); + } + + public void solveContacts(float dt){ + for(int j = 0; j < contacts.contactCount; j ++){ + contacts.contacts[j].init(dt); + } + int velocityIterations = 4; + for(int i = 0; i < velocityIterations; i ++){ + for(int j = 0; j < contacts.contactCount; j ++){ + contacts.contacts[j].solve(dt); + } + } + } + + /*public void solveContacts(float dt){ + for(int i = 0; i < contacts.contactCount; i ++){ + Contact c = contacts.contacts[i]; + RigidBody bodyA = c.bodyA; + RigidBody bodyB = c.bodyB; + Vec3 contactNormal = c.normal; + if(bodyA == RigidBody.DUMMY || bodyA != this){ + bodyA = c.bodyB; + bodyB = c.bodyA; + contactNormal = contactNormal.negate(); + } + Vec3 rA = c.localA.subtract(c.a.localCentroid); + Vec3 rB = c.localB.subtract(c.b.localCentroid); + Vec3[] jacobian = new Vec3[]{contactNormal.negate(), rA.crossProduct(contactNormal).negate(), contactNormal, rB.crossProduct(contactNormal)}; + double inv_effectiveMass = + bodyA.inv_mass + + jacobian[1].dotProduct(jacobian[1].matTransform(bodyA.inv_globalInertiaTensor)) + + bodyB.inv_mass + + jacobian[3].dotProduct(jacobian[3].matTransform(bodyB.inv_globalInertiaTensor)); + + double jv = + jacobian[0].dotProduct(bodyA.linearVelocity) + + jacobian[1].dotProduct(bodyA.angularVelocity) + + jacobian[2].dotProduct(bodyB.linearVelocity) + + jacobian[3].dotProduct(bodyB.angularVelocity); + + float beta = 0.2F; + float b = -(beta/dt)*c.depth; + + float lambda = (float) ((-(jv+b))/inv_effectiveMass); + //float oldTotalLambda = c.totalLambda; + //c.totalLambda = Math.max(0, c.totalLambda + lambda); + //lambda = c.totalLambda - oldTotalLambda; + + bodyA.addLinearVelocity(jacobian[0].mult(bodyA.inv_mass*lambda)); + bodyA.addAngularVelocity(jacobian[1].matTransform(bodyA.inv_globalInertiaTensor).mult(lambda)); + bodyB.addLinearVelocity(jacobian[2].mult(bodyB.inv_mass*lambda)); + bodyB.addAngularVelocity(jacobian[3].matTransform(bodyB.inv_globalInertiaTensor).mult(lambda)); + } + + }*/ + + public Vec3 localToGlobalPos(Vec3 pos){ + return pos.matTransform(rotation).add(position); + } + public Vec3 globalToLocalPos(Vec3 pos){ + return pos.subtract(position).matTransform(inv_rotation); + } + public Vec3 localToGlobalVec(Vec3 vec){ + return vec.matTransform(rotation); + } + public Vec3 globalToLocalVec(Vec3 vec){ + return vec.matTransform(inv_rotation); + } + + public void addLinearVelocity(Vec3 v){ + linearVelocity = linearVelocity.add(v); + } + public void addAngularVelocity(Vec3 v){ + angularVelocity = angularVelocity.add(v); + } + public void impulse(Vec3 force, Vec3 position){ + this.force = this.force.add(force); + this.torque = this.torque.add(position.subtract(globalCentroid).crossProduct(force)); + } + + public void impulseVelocity(Vec3 force, Vec3 position){ + linearVelocity = linearVelocity.add(force.mult(inv_mass)); + angularVelocity = angularVelocity.add(position.subtract(globalCentroid).crossProduct(force).matTransform(inv_globalInertiaTensor)); + } + + public void impulseVelocityDirect(Vec3 force, Vec3 position){ + linearVelocity = linearVelocity.add(force); + angularVelocity = angularVelocity.add(position.subtract(globalCentroid).crossProduct(force)); + } + + public void updateOrientation(){ + Quat4f quat = new Quat4f(); + float epsilon = 0.00001F; + //quat.set(rotation); + setFromMat(quat, rotation); + quat.normalize(); + BobMathUtil.matrixFromQuat(rotation, quat); + //System.out.println("1"); + inv_rotation = (Matrix3f) rotation.clone(); + inv_rotation.transpose(); + + /*Matrix3f bruh = new Matrix3f(0.44135904F, -0.0038072586F, 0.89732254F, + -0.004132689F, -0.9999893F, -0.0022101535F, + 0.8973211F, -0.002732877F, -0.44137013F); + + System.out.println(bruh.m00 + bruh.m11 + bruh.m22 + 1.0f); + quat.set(bruh); + System.out.println(quat); + quat.normalize(); + System.out.println(quat); + BobMathUtil.matrixFromQuat(bruh, quat); + System.out.println(bruh);*/ + + inv_globalInertiaTensor.set(inv_rotation); + inv_globalInertiaTensor.mul(inv_localInertiaTensor); + inv_globalInertiaTensor.mul(rotation); + } + public void updatePositionFromGlobalCentroid(){ + position = globalCentroid.add(localCentroid.mult(-1).matTransform(rotation)); + } + public void updateGlobalCentroidFromPosition(){ + globalCentroid = localCentroid.matTransform(rotation).add(position); + } + public void updateAABBs(){ + colliderBoundingBoxes.clear(); + double tMaxX, tMaxY, tMaxZ, tMinX, tMinY, tMinZ; + tMaxX = tMaxY = tMaxZ = -Double.MAX_VALUE; + tMinX = tMinY = tMinZ = Double.MAX_VALUE; + for(Collider c : colliders){ + double maxX = GJK.localSupport(this, c, cardinals[0]).xCoord; + double maxY = GJK.localSupport(this, c, cardinals[1]).yCoord; + double maxZ = GJK.localSupport(this, c, cardinals[2]).zCoord; + double minX = GJK.localSupport(this, c, cardinals[3]).xCoord; + double minY = GJK.localSupport(this, c, cardinals[4]).yCoord; + double minZ = GJK.localSupport(this, c, cardinals[5]).zCoord; + colliderBoundingBoxes.add(new AxisAlignedBB(minX, minY, minZ, maxX, maxY, maxZ)); + tMaxX = Math.max(tMaxX, maxX); + tMaxY = Math.max(tMaxY, maxY); + tMaxZ = Math.max(tMaxZ, maxZ); + tMinX = Math.min(tMinX, minX); + tMinY = Math.min(tMinY, minY); + tMinZ = Math.min(tMinZ, minZ); + } + boundingBox = new AxisAlignedBB(tMinX, tMinY, tMinZ, tMaxX, tMaxY, tMaxZ); + } + + public void addColliders(Collider... collide){ + for(Collider c : collide){ + colliders.add(c); + } + localCentroid = new Vec3(0, 0, 0); + mass = 0; + for(Collider c : colliders){ + mass += c.mass; + localCentroid = localCentroid.add(c.localCentroid.mult(c.mass)); + } + inv_mass = 1F/mass; + localCentroid = localCentroid.mult(inv_mass); + + localInertiaTensor = new Matrix3f(); + for(Collider c : colliders){ + //https://en.wikipedia.org/wiki/Parallel_axis_theorem + Vec3 colliderToLocal = localCentroid.subtract(c.localCentroid); + double lenSquared = colliderToLocal.dotProduct(colliderToLocal); + Matrix3f outerProduct = colliderToLocal.outerProduct(colliderToLocal); + + Matrix3f colliderToLocalMat = new Matrix3f(); + colliderToLocalMat.setIdentity(); + colliderToLocalMat.mul((float) lenSquared); + colliderToLocalMat.sub(outerProduct); + colliderToLocalMat.mul(c.mass); + Matrix3f cLocalIT = (Matrix3f) c.localInertiaTensor.clone(); + cLocalIT.add(colliderToLocalMat); + localInertiaTensor.add(cLocalIT); + } + inv_localInertiaTensor = new Matrix3f(); + inv_localInertiaTensor.set(localInertiaTensor); + + inv_localInertiaTensor.invert(); + inv_globalInertiaTensor = new Matrix3f(); + updateOrientation(); + updateGlobalCentroidFromPosition(); + this.prevPosition = position; + updateAABBs(); + } + + @SideOnly(Side.CLIENT) + public void doGlTransform(Vec3 playerPos, float partialTicks){ + FloatBuffer buf = AvatarClientProxy.AUX_GL_BUFFER; + Quat4f quat = new Quat4f(); + setFromMat(quat, rotation); + quat.interpolate(prevRotation, 1-partialTicks); + quat.normalize(); + Matrix3f rotation = new Matrix3f(); + BobMathUtil.matrixFromQuat(rotation, quat); + + buf.put(0, rotation.m00); + buf.put(1, rotation.m10); + buf.put(2, rotation.m20); + buf.put(3, 0); + buf.put(4, rotation.m01); + buf.put(5, rotation.m11); + buf.put(6, rotation.m21); + buf.put(7, 0); + buf.put(8, rotation.m02); + buf.put(9, rotation.m12); + buf.put(10, rotation.m22); + buf.put(11, 0); + + Vec3 pos = this.prevPosition.add(this.position.subtract(this.prevPosition).mult(partialTicks)).subtract(playerPos); + + buf.put(12, (float)pos.xCoord); + buf.put(13, (float)pos.yCoord); + buf.put(14, (float)pos.zCoord); + buf.put(15, 1); + + GL11.glMultMatrix(buf); + + buf.rewind(); + } + + //vecmath's matrix to quaternion function is garbage and lwjgl's is a chad that actually works correctly when the rotation is aligned along an axis. + public static void setFromMat(Quat4f q, Matrix3f mat){ + setFromMat(q, mat.m00, mat.m01, mat.m02, mat.m10, mat.m11, mat.m12, mat.m20, mat.m21, mat.m22); + } + + public static void setFromMat(Quat4f q, float m00, float m01, float m02, float m10, + float m11, float m12, float m20, float m21, float m22) { + + float s; + float tr = m00 + m11 + m22; + if (tr >= 0.0) { + s = (float) Math.sqrt(tr + 1.0); + q.w = s * 0.5f; + s = 0.5f / s; + q.x = (m21 - m12) * s; + q.y = (m02 - m20) * s; + q.z = (m10 - m01) * s; + } else { + float max = Math.max(Math.max(m00, m11), m22); + if (max == m00) { + s = (float) Math.sqrt(m00 - (m11 + m22) + 1.0); + q.x = s * 0.5f; + s = 0.5f / s; + q.y = (m01 + m10) * s; + q.z = (m20 + m02) * s; + q.w = (m21 - m12) * s; + } else if (max == m11) { + s = (float) Math.sqrt(m11 - (m22 + m00) + 1.0); + q.y = s * 0.5f; + s = 0.5f / s; + q.z = (m12 + m21) * s; + q.x = (m01 + m10) * s; + q.w = (m02 - m20) * s; + } else { + s = (float) Math.sqrt(m22 - (m00 + m11) + 1.0); + q.z = s * 0.5f; + s = 0.5f / s; + q.x = (m20 + m02) * s; + q.y = (m12 + m21) * s; + q.w = (m10 - m01) * s; + } + } + } + + public void renderDebugInfo(Vec3 offset, float partialTicks){ + GL11.glPushMatrix(); + BufferBuilder buf = Tessellator.getInstance().getBuffer(); + GlStateManager.disableDepth(); + for(Contact c : contacts.contacts){ + if(c != null){ + buf.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR); + Vec3 normal = c.normal.mult(0.5F); + Vec3 globalA = c.globalA.subtract(offset); + Vec3 globalB = c.globalB.subtract(offset); + buf.pos(globalA.xCoord, globalA.yCoord, globalA.zCoord).color(1, 0, 0, 1).endVertex(); + buf.pos(globalA.xCoord-normal.xCoord, globalA.yCoord-normal.yCoord, globalA.zCoord-normal.zCoord).color(1, 0, 0, 1).endVertex(); + + buf.pos(globalB.xCoord, globalB.yCoord, globalB.zCoord).color(1, 0, 0, 1).endVertex(); + buf.pos(globalB.xCoord+normal.xCoord, globalB.yCoord+normal.yCoord, globalB.zCoord+normal.zCoord).color(1, 0, 0, 1).endVertex(); + Tessellator.getInstance().draw(); + + GL11.glPointSize(16); + buf.begin(GL11.GL_POINTS, DefaultVertexFormats.POSITION_COLOR); + buf.pos(globalA.xCoord, globalA.yCoord, globalA.zCoord).color(1, 0, 0, 1).endVertex(); + buf.pos(globalB.xCoord, globalB.yCoord, globalB.zCoord).color(1, 0, 0, 1).endVertex(); + Tessellator.getInstance().draw(); + } + } + GlStateManager.enableDepth(); + doGlTransform(offset, partialTicks); + for(Collider c : colliders){ + c.debugRender(); + } + GL11.glPopMatrix(); + } +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/DisintegrationParticleHandler.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/DisintegrationParticleHandler.java new file mode 100644 index 0000000000..b7ef532fe6 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/DisintegrationParticleHandler.java @@ -0,0 +1,330 @@ +package com.crowsofwar.avatar.client.render.lightning.particle; + +import com.crowsofwar.avatar.AvatarMod; +import com.crowsofwar.avatar.client.particles.newparticles.ParticleLightningGib; +import com.crowsofwar.avatar.client.render.lightning.main.ResourceManager; +import com.crowsofwar.avatar.client.render.lightning.math.Vec3; +import com.crowsofwar.avatar.client.render.lightning.render.ModelRendererUtil; +import com.crowsofwar.avatar.network.AvatarClientProxy; +import net.minecraft.client.Minecraft; +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelBox; +import net.minecraft.client.model.ModelRenderer; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderLivingBase; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.ReflectionHelper; +import org.lwjgl.opengl.GL11; + +import java.lang.reflect.InvocationTargetException; + +public class DisintegrationParticleHandler { + + @SuppressWarnings({ "deprecation" }) + public static void spawnGluonDisintegrateParticles(EntityLivingBase e, RenderLivingBase render, float partialTicks) { + ModelBase model = render.getMainModel(); + GL11.glPushMatrix(); + GL11.glLoadIdentity(); + GlStateManager.disableCull(); + GlStateManager.enableRescaleNormal(); + //So basically we're just going to copy vanialla methods so the + model.swingProgress = e.getSwingProgress(partialTicks); + boolean shouldSit = e.isRiding() && (e.getRidingEntity() != null && e.getRidingEntity().shouldRiderSit()); + model.isRiding = shouldSit; + model.isChild = e.isChild(); + float f = interpolateRotation(e.prevRenderYawOffset, e.renderYawOffset, partialTicks); + float f1 = interpolateRotation(e.prevRotationYawHead, e.rotationYawHead, partialTicks); + float f2 = f1 - f; + if(shouldSit && e.getRidingEntity() instanceof EntityLivingBase) { + EntityLivingBase elivingbase = (EntityLivingBase) e.getRidingEntity(); + f = interpolateRotation(elivingbase.prevRenderYawOffset, elivingbase.renderYawOffset, partialTicks); + f2 = f1 - f; + float f3 = MathHelper.wrapDegrees(f2); + + if(f3 < -85.0F) { + f3 = -85.0F; + } + + if(f3 >= 85.0F) { + f3 = 85.0F; + } + + f = f1 - f3; + + if(f3 * f3 > 2500.0F) { + f += f3 * 0.2F; + } + + f2 = f1 - f; + } + + float f7 = e.prevRotationPitch + (e.rotationPitch - e.prevRotationPitch) * partialTicks; + //renderLivingAt(e, x, y, z); + float f8 = e.ticksExisted + partialTicks; + GlStateManager.rotate(180.0F - f, 0.0F, 1.0F, 0.0F); + //if(rPreRenderCallback == null){ + // rPreRenderCallback = ReflectionHelper.findMethod(RenderLivingBase.class, "preRenderCallback", "func_77041_b", EntityLivingBase.class, float.class); + //} + if(ModelRendererUtil.rPrepareScale == null){ + ModelRendererUtil.rPrepareScale = ReflectionHelper.findMethod(RenderLivingBase.class, "prepareScale", "func_188322_c", EntityLivingBase.class, float.class); + } + //float f4 = prepareScale(e, partialTicks, render); + float f4 = 0.0625F; + try { + f4 = (float) ModelRendererUtil.rPrepareScale.invoke(render, e, partialTicks); + } catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException e2) { + e2.printStackTrace(); + } + float f5 = 0.0F; + float f6 = 0.0F; + if(!e.isRiding()) { + f5 = e.prevLimbSwingAmount + (e.limbSwingAmount - e.prevLimbSwingAmount) * partialTicks; + f6 = e.limbSwing - e.limbSwingAmount * (1.0F - partialTicks); + + if(e.isChild()) { + f6 *= 3.0F; + } + + if(f5 > 1.0F) { + f5 = 1.0F; + } + f2 = f1 - f; // Forge: Fix MC-1207 + } + model.setLivingAnimations(e, f6, f5, partialTicks); + model.setRotationAngles(f6, f5, f8, f2, f7, f4, e); + + if(ModelRendererUtil.rGetEntityTexture == null){ + ModelRendererUtil.rGetEntityTexture = ReflectionHelper.findMethod(Render.class, "getEntityTexture", "func_110775_a", Entity.class); + } + ResourceLocation r = ResourceManager.turbofan_blades_tex; + try { + r = (ResourceLocation) ModelRendererUtil.rGetEntityTexture.invoke(render, e); + if(r == null) + r = ResourceManager.turbofan_blades_tex; + } catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) { + e1.printStackTrace(); + } + for(ModelRenderer renderer : model.boxList) { + spawnParticles(e.world, e, e.posX, e.posY, e.posZ, f4, renderer, r); + } + + GlStateManager.disableRescaleNormal(); + GlStateManager.enableCull(); + GL11.glPopMatrix(); + } + + public static void spawnLightningDisintegrateParticles(Entity e, Vec3 hitPos) { + Render eRenderer = Minecraft.getMinecraft().getRenderManager().getEntityRenderObject(e); + if(eRenderer instanceof RenderLivingBase && e instanceof EntityLivingBase) { + spawnLightningDisintegrateParticles((EntityLivingBase) e, ((RenderLivingBase) eRenderer), hitPos, AvatarMod.proxy.partialTicks()); + } + } + + @SuppressWarnings({ "deprecation" }) + public static void spawnLightningDisintegrateParticles(EntityLivingBase e, RenderLivingBase render, Vec3 hitPos, float partialTicks) { + ModelBase model = render.getMainModel(); + GL11.glPushMatrix(); + GL11.glLoadIdentity(); + GlStateManager.disableCull(); + GlStateManager.enableRescaleNormal(); + //So basically we're just going to copy vanialla methods so the + model.swingProgress = e.getSwingProgress(partialTicks); + boolean shouldSit = e.isRiding() && (e.getRidingEntity() != null && e.getRidingEntity().shouldRiderSit()); + model.isRiding = shouldSit; + model.isChild = e.isChild(); + float f = interpolateRotation(e.prevRenderYawOffset, e.renderYawOffset, partialTicks); + float f1 = interpolateRotation(e.prevRotationYawHead, e.rotationYawHead, partialTicks); + float f2 = f1 - f; + if(shouldSit && e.getRidingEntity() instanceof EntityLivingBase) { + EntityLivingBase elivingbase = (EntityLivingBase) e.getRidingEntity(); + f = interpolateRotation(elivingbase.prevRenderYawOffset, elivingbase.renderYawOffset, partialTicks); + f2 = f1 - f; + float f3 = MathHelper.wrapDegrees(f2); + + if(f3 < -85.0F) { + f3 = -85.0F; + } + + if(f3 >= 85.0F) { + f3 = 85.0F; + } + + f = f1 - f3; + + if(f3 * f3 > 2500.0F) { + f += f3 * 0.2F; + } + + f2 = f1 - f; + } + + float f7 = e.prevRotationPitch + (e.rotationPitch - e.prevRotationPitch) * partialTicks; + //renderLivingAt(e, x, y, z); + float f8 = e.ticksExisted + partialTicks; + GlStateManager.rotate(180.0F - f, 0.0F, 1.0F, 0.0F); + //if(rPreRenderCallback == null){ + // rPreRenderCallback = ReflectionHelper.findMethod(RenderLivingBase.class, "preRenderCallback", "func_77041_b", EntityLivingBase.class, float.class); + //} + if(ModelRendererUtil.rPrepareScale == null){ + ModelRendererUtil.rPrepareScale = ReflectionHelper.findMethod(RenderLivingBase.class, "prepareScale", "func_188322_c", EntityLivingBase.class, float.class); + } + //float f4 = prepareScale(e, partialTicks, render); + float f4 = 0.0625F; + try { + f4 = (float) ModelRendererUtil.rPrepareScale.invoke(render, e, partialTicks); + } catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException e2) { + e2.printStackTrace(); + } + float f5 = 0.0F; + float f6 = 0.0F; + if(!e.isRiding()) { + f5 = e.prevLimbSwingAmount + (e.limbSwingAmount - e.prevLimbSwingAmount) * partialTicks; + f6 = e.limbSwing - e.limbSwingAmount * (1.0F - partialTicks); + + if(e.isChild()) { + f6 *= 3.0F; + } + + if(f5 > 1.0F) { + f5 = 1.0F; + } + f2 = f1 - f; // Forge: Fix MC-1207 + } + model.setLivingAnimations(e, f6, f5, partialTicks); + model.setRotationAngles(f6, f5, f8, f2, f7, f4, e); + + if(ModelRendererUtil.rGetEntityTexture == null){ + ModelRendererUtil.rGetEntityTexture = ReflectionHelper.findMethod(Render.class, "getEntityTexture", "func_110775_a", Entity.class); + } + ResourceLocation r = ResourceManager.turbofan_blades_tex; + try { + r = (ResourceLocation) ModelRendererUtil.rGetEntityTexture.invoke(render, e); + if(r == null) + r = ResourceManager.turbofan_blades_tex; + } catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) { + e1.printStackTrace(); + } + int trailCount = 10; + for(ModelRenderer renderer : model.boxList) { + trailCount = spawnLightningParticles(e.world, e, e.posX, e.posY, e.posZ, f4, renderer, r, hitPos, trailCount); + } + + GlStateManager.disableRescaleNormal(); + GlStateManager.enableCull(); + GL11.glPopMatrix(); + } + + public static void spawnParticles(World world, EntityLivingBase ent, double x, double y, double z, float scale, ModelRenderer render, ResourceLocation tex) { + if(render.isHidden || !render.showModel) + return; + GL11.glPushMatrix(); + doTransforms(render, scale); + if(render.childModels != null) + for(ModelRenderer renderer : render.childModels) { + spawnParticles(world, ent, x, y, z, scale, renderer, tex); + } + for(ModelBox cube : render.cubeList) { + GL11.glPushMatrix(); + float cubeMidX = (cube.posX1 + (cube.posX2-cube.posX1)*0.5F)*scale; + float cubeMidY = (cube.posY1 + (cube.posY2-cube.posY1)*0.5F)*scale; + float cubeMidZ = (cube.posZ1 + (cube.posZ2-cube.posZ1)*0.5F)*scale; + GL11.glTranslated(cubeMidX, cubeMidY, cubeMidZ); + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, AvatarClientProxy.AUX_GL_BUFFER); + float[] matrix = new float[16]; + AvatarClientProxy.AUX_GL_BUFFER.get(matrix); + AvatarClientProxy.AUX_GL_BUFFER.rewind(); + GL11.glPopMatrix(); + + double pX = x + matrix[12]; + double pY = y + matrix[13]; + double pZ = z + matrix[14]; + matrix[12] = 0; + matrix[13] = 0; + matrix[14] = 0; + } + + GL11.glPopMatrix(); + } + + public static int spawnLightningParticles(World world, EntityLivingBase ent, double x, double y, double z, float scale, ModelRenderer render, ResourceLocation tex, Vec3 hitPos, int trailCount) { + if(render.isHidden || !render.showModel) + return trailCount; + GL11.glPushMatrix(); + doTransforms(render, scale); + if(render.childModels != null) { + for (ModelRenderer renderer : render.childModels) { + trailCount = spawnLightningParticles(world, ent, x, y, z, scale, renderer, tex, hitPos, trailCount); + } + } + for(ModelBox cube : render.cubeList) { + GL11.glPushMatrix(); + float cubeMidX = (cube.posX1 + (cube.posX2-cube.posX1)*0.5F)*scale; + float cubeMidY = (cube.posY1 + (cube.posY2-cube.posY1)*0.5F)*scale; + float cubeMidZ = (cube.posZ1 + (cube.posZ2-cube.posZ1)*0.5F)*scale; + GL11.glTranslated(cubeMidX, cubeMidY, cubeMidZ); + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, AvatarClientProxy.AUX_GL_BUFFER); + float[] matrix = new float[16]; + AvatarClientProxy.AUX_GL_BUFFER.get(matrix); + AvatarClientProxy.AUX_GL_BUFFER.rewind(); + GL11.glPopMatrix(); + + double pX = x + matrix[12]; + double pY = y + matrix[13]; + double pZ = z + matrix[14]; + matrix[12] = 0; + matrix[13] = 0; + matrix[14] = 0; + int numLTrails = MathHelper.clamp(trailCount, 0, 2); + ParticleLightningGib p = new ParticleLightningGib(world, pX, pY, pZ, cube, matrix, tex, cubeMidX, cubeMidY, cubeMidZ, scale, numLTrails); + trailCount -= numLTrails; + Vec3d motion = hitPos.toVec3d().normalize().add(0, 0.2, 0).scale(1.2) + .add(new Vec3d(world.rand.nextFloat()-0.5F, world.rand.nextFloat()-0.5F, world.rand.nextFloat()-0.5F).scale(0.5)); + p.motion(motion); + Minecraft.getMinecraft().effectRenderer.addEffect(p); + } + + GL11.glPopMatrix(); + return trailCount; + } + + public static void doTransforms(ModelRenderer m, float scale) { + GlStateManager.translate(m.offsetX, m.offsetY, m.offsetZ); + if(m.rotateAngleX == 0.0F && m.rotateAngleY == 0.0F && m.rotateAngleZ == 0.0F) { + if(m.rotationPointX == 0.0F && m.rotationPointY == 0.0F && m.rotationPointZ == 0.0F) { + } else { + GlStateManager.translate(m.rotationPointX * scale, m.rotationPointY * scale, m.rotationPointZ * scale); + } + } else { + GlStateManager.translate(m.rotationPointX * scale, m.rotationPointY * scale, m.rotationPointZ * scale); + if(m.rotateAngleZ != 0.0F) { + GlStateManager.rotate(m.rotateAngleZ * (180F / (float) Math.PI), 0.0F, 0.0F, 1.0F); + } + if(m.rotateAngleY != 0.0F) { + GlStateManager.rotate(m.rotateAngleY * (180F / (float) Math.PI), 0.0F, 1.0F, 0.0F); + } + if(m.rotateAngleX != 0.0F) { + GlStateManager.rotate(m.rotateAngleX * (180F / (float) Math.PI), 1.0F, 0.0F, 0.0F); + } + } + } + + protected static float interpolateRotation(float prevYawOffset, float yawOffset, float partialTicks) { + float f; + + for(f = yawOffset - prevYawOffset; f < -180.0F; f += 360.0F) { + ; + } + + while(f >= 180.0F) { + f -= 360.0F; + } + + return prevYawOffset + partialTicks * f; + } +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/ParticleBatchRenderer.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/ParticleBatchRenderer.java new file mode 100644 index 0000000000..59ce9be979 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/ParticleBatchRenderer.java @@ -0,0 +1,123 @@ +package com.crowsofwar.avatar.client.render.lightning.particle; + +import com.crowsofwar.avatar.AvatarInfo; +import com.google.common.collect.Queues; +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.renderer.ActiveRenderInfo; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.GlStateManager.DestFactor; +import net.minecraft.client.renderer.GlStateManager.SourceFactor; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.entity.Entity; +import net.minecraftforge.client.event.RenderWorldLastEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent.Phase; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import org.lwjgl.opengl.GL11; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Queue; + +//Drillgon200: Like the vanilla particle manager, but supports more gl states. +@SideOnly(Side.CLIENT) +@Mod.EventBusSubscriber(value = Side.CLIENT, modid = AvatarInfo.MOD_ID) +public class ParticleBatchRenderer { + + public static List layers = new ArrayList<>(); + + private static final Queue queue = Queues. newArrayDeque(); + + public static void registerRenderLayer(ParticleRenderLayer r){ + layers.add(r); + r.isRegistered = true; + } + + public static void addParticle(ParticleLayerBase p) { + if(p != null) + queue.add(p); + } + + public static void updateParticles() { + if(Minecraft.getMinecraft().world == null || Minecraft.getMinecraft().isGamePaused()) + return; + + for(ParticleRenderLayer layer : layers){ + Iterator itr = layer.particles.iterator(); + while(itr.hasNext()) { + ParticleLayerBase p = itr.next(); + p.onUpdate(); + if(!p.isAlive()) { + itr.remove(); + } + } + } + + if(!queue.isEmpty()) { + for(ParticleLayerBase particle = queue.poll(); particle != null; particle = queue.poll()) { + ParticleRenderLayer layer = particle.getRenderLayer(); + + if(layer == null){ + throw new RuntimeException("Particle " + particle + " does not use a custom render layer!"); + } + if(!layer.isRegistered){ + registerRenderLayer(layer); + } + if(layer.particles.size() > 16384) + layer.particles.removeFirst(); + + layer.particles.add(particle); + } + } + } + + public static void renderParticles(Entity entityIn, float partialTicks) { + float f = ActiveRenderInfo.getRotationX(); + float f1 = ActiveRenderInfo.getRotationZ(); + float f2 = ActiveRenderInfo.getRotationYZ(); + float f3 = ActiveRenderInfo.getRotationXY(); + float f4 = ActiveRenderInfo.getRotationXZ(); + Particle.interpPosX = entityIn.lastTickPosX + (entityIn.posX - entityIn.lastTickPosX) * (double) partialTicks; + Particle.interpPosY = entityIn.lastTickPosY + (entityIn.posY - entityIn.lastTickPosY) * (double) partialTicks; + Particle.interpPosZ = entityIn.lastTickPosZ + (entityIn.posZ - entityIn.lastTickPosZ) * (double) partialTicks; + Particle.cameraViewDir = entityIn.getLook(partialTicks); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); + //Note: The constant 0.003921569F is actually 1/255, so particle fragments will only be cut if they have no alpha anyway. + GlStateManager.alphaFunc(GL11.GL_GREATER, 0.003921569F); + GlStateManager.depthMask(false); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + + for(ParticleRenderLayer layer : layers) { + if(layer.particles.isEmpty()) + continue; + layer.preRender(); + for(ParticleLayerBase particle : layer.particles){ + particle.renderParticle(Tessellator.getInstance().getBuffer(), entityIn, partialTicks, f, f4, f1, f2, f3); + } + layer.postRender(); + } + + GlStateManager.depthMask(true); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); + GlStateManager.disableBlend(); + GlStateManager.alphaFunc(GL11.GL_GREATER, 0.1F); + } + + public static void renderLast(RenderWorldLastEvent event) { + renderParticles(Minecraft.getMinecraft().getRenderViewEntity(), event.getPartialTicks()); + } + + @SubscribeEvent + public static void clientTick(ClientTickEvent event) { + if(event.phase == Phase.START) { + updateParticles(); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/ParticleFakeBrightness.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/ParticleFakeBrightness.java new file mode 100644 index 0000000000..4c39386ab4 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/ParticleFakeBrightness.java @@ -0,0 +1,144 @@ +package com.crowsofwar.avatar.client.render.lightning.particle; + +import com.crowsofwar.avatar.client.render.lightning.main.ResourceManager; +import com.crowsofwar.avatar.client.render.lightning.math.BobMathUtil; +import com.crowsofwar.avatar.client.render.lightning.misc.LensVisibilityHandler; +import com.crowsofwar.avatar.network.AvatarClientProxy; +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.renderer.ActiveRenderInfo; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.GlStateManager.DestFactor; +import net.minecraft.client.renderer.GlStateManager.SourceFactor; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.ReflectionHelper; +import org.lwjgl.opengl.GL11; + +import java.nio.FloatBuffer; + +public class ParticleFakeBrightness extends Particle { + + int visibilityId = -1; + boolean local; + public float fadeInKoeff = 2; + + public ParticleFakeBrightness(World worldIn, double posXIn, double posYIn, double posZIn, float scale, int age) { + super(worldIn, posXIn, posYIn, posZIn); + this.particleScale = scale; + this.particleMaxAge = age; + } + + public ParticleFakeBrightness color(float r, float g, float b, float a){ + this.particleRed = r; + this.particleGreen = g; + this.particleBlue = b; + this.particleAlpha = a; + return this; + } + + public ParticleFakeBrightness enableLocalSpaceCorrection(){ + local = true; + return this; + } + + @Override + public void onUpdate() { + this.particleAge ++; + if(particleAge >= particleMaxAge){ + setExpired(); + LensVisibilityHandler.delete(visibilityId); + return; + } + } + + @Override + public int getFXLayer() { + return 3; + } + + @Override + public boolean shouldDisableDepth() { + return true; + } + + @Override + public void renderParticle(BufferBuilder buffer, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) { + GL11.glPushMatrix(); + GlStateManager.disableDepth(); + + if(local){ + float f5 = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks); + float f6 = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks); + float f7 = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks); + GL11.glTranslated(f5, f6, f7); + if(BobMathUtil.r_viewMat == null){ + BobMathUtil.r_viewMat = ReflectionHelper.findField(ActiveRenderInfo.class, "MODELVIEW", "field_178812_b"); + } + try { + FloatBuffer view_mat = (FloatBuffer) BobMathUtil.r_viewMat.get(null); + view_mat.rewind(); + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, AvatarClientProxy.AUX_GL_BUFFER); + for(int i = 0; i < 12; i ++){ + AvatarClientProxy.AUX_GL_BUFFER.put(i, view_mat.get(i)); + } + AvatarClientProxy.AUX_GL_BUFFER.rewind(); + GL11.glLoadMatrix(AvatarClientProxy.AUX_GL_BUFFER); + } catch(IllegalArgumentException | IllegalAccessException e) { + e.printStackTrace(); + } + } else { + double entPosX = entityIn.lastTickPosX + (entityIn.posX - entityIn.lastTickPosX)*partialTicks; + double entPosY = entityIn.lastTickPosY + (entityIn.posY - entityIn.lastTickPosY)*partialTicks; + double entPosZ = entityIn.lastTickPosZ + (entityIn.posZ - entityIn.lastTickPosZ)*partialTicks; + + interpPosX = entPosX; + interpPosY = entPosY; + interpPosZ = entPosZ; + float f5 = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks - interpPosX); + float f6 = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY); + float f7 = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks - interpPosZ); + GL11.glTranslated(f5, f6, f7); + } + if(visibilityId == -1){ + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, AvatarClientProxy.AUX_GL_BUFFER); + visibilityId = LensVisibilityHandler.generate(AvatarClientProxy.AUX_GL_BUFFER); + } + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, AvatarClientProxy.AUX_GL_BUFFER); + LensVisibilityHandler.putMatrixBuf(visibilityId, AvatarClientProxy.AUX_GL_BUFFER); + + float visibility = LensVisibilityHandler.getVisibility(visibilityId); + visibility *= visibility; + + float ageN = (float)(this.particleAge+partialTicks)/(float)this.particleMaxAge; + float scale = MathHelper.clamp(ageN*fadeInKoeff, 0, 1)* MathHelper.clamp(2-ageN*fadeInKoeff+0.1F, 0, 1); + float f4 = 0.1F * this.particleScale * visibility*scale; + + Vec3d[] avec3d = new Vec3d[] {new Vec3d((double)(-rotationX * f4 - rotationXY * f4), (double)(-rotationZ * f4), (double)(-rotationYZ * f4 - rotationXZ * f4)), new Vec3d((double)(-rotationX * f4 + rotationXY * f4), (double)(rotationZ * f4), (double)(-rotationYZ * f4 + rotationXZ * f4)), new Vec3d((double)(rotationX * f4 + rotationXY * f4), (double)(rotationZ * f4), (double)(rotationYZ * f4 + rotationXZ * f4)), new Vec3d((double)(rotationX * f4 - rotationXY * f4), (double)(-rotationZ * f4), (double)(rotationYZ * f4 - rotationXZ * f4))}; + if(!local){ + GlStateManager.enableBlend(); + GlStateManager.disableAlpha(); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE); + } + + Minecraft.getMinecraft().getTextureManager().bindTexture(ResourceManager.fresnel_ms); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP); + buffer.pos(avec3d[0].x, avec3d[0].y, avec3d[0].z).tex(1, 1).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha*visibility).lightmap(240, 240).endVertex(); + buffer.pos(avec3d[1].x, avec3d[1].y, avec3d[1].z).tex(1, 0).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha*visibility).lightmap(240, 240).endVertex(); + buffer.pos(avec3d[2].x, avec3d[2].y, avec3d[2].z).tex(0, 0).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha*visibility).lightmap(240, 240).endVertex(); + buffer.pos(avec3d[3].x, avec3d[3].y, avec3d[3].z).tex(0, 1).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha*visibility).lightmap(240, 240).endVertex(); + Tessellator.getInstance().draw(); + + if(!local){ + GlStateManager.disableBlend(); + GlStateManager.enableAlpha(); + } + GlStateManager.enableDepth(); + GL11.glPopMatrix(); + } +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/ParticleFirstPerson.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/ParticleFirstPerson.java new file mode 100644 index 0000000000..fe5c120997 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/ParticleFirstPerson.java @@ -0,0 +1,20 @@ +package com.crowsofwar.avatar.client.render.lightning.particle; + +import net.minecraft.client.particle.Particle; +import net.minecraft.world.World; + +public abstract class ParticleFirstPerson extends Particle { + + public ParticleFirstPerson(World worldIn, double posXIn, double posYIn, double posZIn) { + super(worldIn, posXIn, posYIn, posZIn); + } + + public abstract ParticleType getType(); + + public static enum ParticleType { + TAU, + GLUON, + CRUCIBLE; + } + +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/ParticleInstanced.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/ParticleInstanced.java new file mode 100644 index 0000000000..146980720e --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/ParticleInstanced.java @@ -0,0 +1,47 @@ +package com.crowsofwar.avatar.client.render.lightning.particle; + +import java.nio.ByteBuffer; + +import net.minecraft.client.particle.Particle; +import net.minecraft.world.World; + +public class ParticleInstanced extends Particle { + + protected ParticleInstanced(World worldIn, double posXIn, double posYIn, double posZIn) { + super(worldIn, posXIn, posYIn, posZIn); + } + + public void addDataToBuffer(ByteBuffer buf, float partialTicks){ + float x = (float) ((this.prevPosX + (this.posX - this.prevPosX) * (double) partialTicks - interpPosX)); + float y = (float) ((this.prevPosY + (this.posY - this.prevPosY) * (double) partialTicks - interpPosY)); + float z = (float) ((this.prevPosZ + (this.posZ - this.prevPosZ) * (double) partialTicks - interpPosZ)); + buf.putFloat(x); + buf.putFloat(y); + buf.putFloat(z); + buf.putFloat(this.particleScale); + buf.putFloat(this.particleTexture.getMinU()); + buf.putFloat(this.particleTexture.getMinV()); + buf.putFloat(this.particleTexture.getMaxU()-this.particleTexture.getMinU()); + buf.putFloat(this.particleTexture.getMaxV()-this.particleTexture.getMinV()); + byte r = (byte) (this.particleRed*255); + byte g = (byte) (this.particleGreen*255); + byte b = (byte) (this.particleBlue*255); + byte a = (byte) (this.particleAlpha*255); + buf.put(r); + buf.put(g); + buf.put(b); + buf.put(a); + int i = this.getBrightnessForRender(partialTicks); + int j = i >> 16 & 65535; + int k = i & 65535; + j = 240; + k = 240; + buf.put((byte) j); + buf.put((byte) k); + } + + public int getFaceCount(){ + return 1; + } + +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/ParticleLayerBase.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/ParticleLayerBase.java new file mode 100644 index 0000000000..600cacf9e1 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/ParticleLayerBase.java @@ -0,0 +1,13 @@ +package com.crowsofwar.avatar.client.render.lightning.particle; + +import net.minecraft.client.particle.Particle; +import net.minecraft.world.World; + +public abstract class ParticleLayerBase extends Particle { + + public ParticleLayerBase(World worldIn, double posXIn, double posYIn, double posZIn) { + super(worldIn, posXIn, posYIn, posZIn); + } + + public abstract ParticleRenderLayer getRenderLayer(); +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/ParticleRenderLayer.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/ParticleRenderLayer.java new file mode 100644 index 0000000000..105b7790b2 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/ParticleRenderLayer.java @@ -0,0 +1,51 @@ +package com.crowsofwar.avatar.client.render.lightning.particle; + +import com.crowsofwar.avatar.client.render.lightning.main.ResourceManager; +import com.google.common.collect.Queues; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.GlStateManager.DestFactor; +import net.minecraft.client.renderer.GlStateManager.SourceFactor; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import org.lwjgl.opengl.GL11; + +import java.util.ArrayDeque; + +public class ParticleRenderLayer { + + public static final ParticleRenderLayer NORMAL = new ParticleRenderLayer(); + public static final ParticleRenderLayer ADDITIVE_FRESNEL = new ParticleRenderLayer(){ + @Override + public void preRender(){ + Minecraft.getMinecraft().renderEngine.bindTexture(ResourceManager.fresnel_ms); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE); + Tessellator.getInstance().getBuffer().begin(GL11.GL_QUADS, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP); + }; + @Override + public void postRender(){ + Tessellator.getInstance().draw(); + GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); + }; + }; + + public boolean isRegistered = false; + protected ArrayDeque particles = Queues.newArrayDeque(); + + public void preRender(){ + Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); + Tessellator.getInstance().getBuffer().begin(GL11.GL_QUADS, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP); + } + + public void postRender(){ + Tessellator.getInstance().draw(); + } + + public static void register(){ + ParticleBatchRenderer.layers.add(NORMAL); + ParticleBatchRenderer.layers.add(ADDITIVE_FRESNEL); + } + +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/ParticleSlicedMob.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/ParticleSlicedMob.java new file mode 100644 index 0000000000..27a26f7e4a --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/particle/ParticleSlicedMob.java @@ -0,0 +1,124 @@ +package com.crowsofwar.avatar.client.render.lightning.particle; + +import com.crowsofwar.avatar.client.render.lightning.configs.LightningConfig; +import com.crowsofwar.avatar.client.render.lightning.handler.HbmShaderManager2; +import com.crowsofwar.avatar.client.render.lightning.math.Vec3; +import com.crowsofwar.avatar.client.render.lightning.misc.RigidBody; +import com.crowsofwar.avatar.client.render.lightning.render.RenderHelper; +import com.crowsofwar.avatar.network.AvatarClientProxy; +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.entity.Entity; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; +import org.lwjgl.opengl.GL11; + +public class ParticleSlicedMob extends Particle { + + public ResourceLocation capTex; + public ResourceLocation texture; + public float capBloom; + public int cutMob; + public int cap; + public RigidBody body; + + public ParticleSlicedMob(World worldIn, RigidBody body, int cutMob, int cap, ResourceLocation tex, ResourceLocation capTex, float capBloom) { + super(worldIn, body.globalCentroid.xCoord, body.globalCentroid.yCoord, body.globalCentroid.zCoord); + this.body = body; + this.cutMob = cutMob; + this.cap = cap; + this.capTex = capTex; + this.capBloom = capBloom; + this.texture = tex; + this.particleMaxAge = 80 + worldIn.rand.nextInt(20); + } + + @Override + public void onUpdate() { + body.minecraftTimestep(); + this.posX = body.globalCentroid.xCoord; + this.posY = body.globalCentroid.yCoord; + this.posZ = body.globalCentroid.zCoord; + this.particleAge ++; + if(particleAge >= particleMaxAge){ + setExpired(); + GL11.glDeleteLists(cutMob, 1); + GL11.glDeleteLists(cap, 1); + } + } + + @Override + public int getFXLayer() { + return 3; + } + + @Override + public void renderParticle(BufferBuilder buffer, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) { + GL11.glPushMatrix(); + GlStateManager.enableCull(); + GlStateManager.enableLighting(); + GlStateManager.enableColorMaterial(); + GlStateManager.enableRescaleNormal(); + net.minecraft.client.renderer.RenderHelper.enableStandardItemLighting(); + int i = this.getBrightnessForRender(partialTicks); + int j = i >> 16 & 65535; + int k = i & 65535; + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, k, j); + Minecraft.getMinecraft().getTextureManager().bindTexture(texture); + RenderHelper.resetParticleInterpPos(entityIn, partialTicks); + RenderHelper.resetColor(); + body.doGlTransform(new Vec3(interpPosX, interpPosY, interpPosZ), partialTicks); + GL11.glCallList(cutMob); + Minecraft.getMinecraft().getTextureManager().bindTexture(capTex); + GlStateManager.enablePolygonOffset(); + GlStateManager.doPolygonOffset(-1, -1); + float lx = OpenGlHelper.lastBrightnessX; + float ly = OpenGlHelper.lastBrightnessY; + if(capBloom > 0){ + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240); + } + GL11.glCallList(cap); + + + if(capBloom > 0 && LightningConfig.bloom){ + float[] matrix = new float[16]; + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, AvatarClientProxy.AUX_GL_BUFFER); + AvatarClientProxy.AUX_GL_BUFFER.get(matrix); + AvatarClientProxy.AUX_GL_BUFFER.rewind(); + AvatarClientProxy.deferredRenderers.add(() -> { + GL11.glPushMatrix(); + AvatarClientProxy.AUX_GL_BUFFER.put(matrix); + AvatarClientProxy.AUX_GL_BUFFER.rewind(); + GL11.glLoadMatrix(AvatarClientProxy.AUX_GL_BUFFER); + HbmShaderManager2.bloomData.bindFramebuffer(false); + + Minecraft.getMinecraft().getTextureManager().bindTexture(capTex); + GlStateManager.enablePolygonOffset(); + GlStateManager.disableLighting(); + float x = OpenGlHelper.lastBrightnessX; + float y = OpenGlHelper.lastBrightnessY; + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240); + GlStateManager.doPolygonOffset(-1, -1); + GL11.glCallList(cap); + GlStateManager.disablePolygonOffset(); + GlStateManager.enableLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, x, y); + + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + GL11.glPopMatrix(); + }); + } + + if(capBloom > 0){ + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, lx, ly); + } + GlStateManager.disablePolygonOffset(); + GlStateManager.disableRescaleNormal(); + net.minecraft.client.renderer.RenderHelper.disableStandardItemLighting(); + GL11.glPopMatrix(); + } + +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/AdvancedModelLoader.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/AdvancedModelLoader.java new file mode 100644 index 0000000000..2019c89a72 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/AdvancedModelLoader.java @@ -0,0 +1,75 @@ +package com.crowsofwar.avatar.client.render.lightning.render; + +import com.google.common.collect.Maps; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.common.FMLLog; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import java.util.Collection; +import java.util.Map; + +/** + * Common interface for advanced model loading from files, based on file suffix + * Model support can be queried through the {@link #getSupportedSuffixes()} method. + * Instances can be created by calling loadModel(String) with a class-loadable-path + * + * @author cpw + * + */ +@SideOnly(Side.CLIENT) +public class AdvancedModelLoader { + private static Map instances = Maps.newHashMap(); + + /** + * Register a new model handler + * @param modelHandler The model handler to register + */ + public static void registerModelHandler(IModelCustomLoader modelHandler) + { + for (String suffix : modelHandler.getSuffixes()) + { + instances.put(suffix, modelHandler); + } + } + + /** + * Load the model from the supplied classpath resolvable resource name + * @param resource The resource name + * @return A model + * @throws IllegalArgumentException if the resource name cannot be understood + * @throws ModelFormatException if the underlying model handler cannot parse the model format + */ + @SuppressWarnings("deprecation") + public static IModelCustom loadModel(ResourceLocation resource) throws IllegalArgumentException, ModelFormatException + { + String name = resource.getPath(); + int i = name.lastIndexOf('.'); + if (i == -1) + { + FMLLog.severe("The resource name %s is not valid", resource); + throw new IllegalArgumentException("The resource name is not valid"); + } + String suffix = name.substring(i+1); + IModelCustomLoader loader = instances.get(suffix); + if (loader == null) + { + FMLLog.severe("The resource name %s is not supported", resource); + throw new IllegalArgumentException("The resource name is not supported"); + } + + return loader.loadInstance(resource); + } + + public static Collection getSupportedSuffixes() + { + return instances.keySet(); + } + + + static + { + registerModelHandler(new ObjModelLoader()); + // registerModelHandler(new TechneModelLoader()); + } +} \ No newline at end of file diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/Face.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/Face.java new file mode 100644 index 0000000000..e30eb19a6f --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/Face.java @@ -0,0 +1,84 @@ +package com.crowsofwar.avatar.client.render.lightning.render; + +import com.crowsofwar.avatar.client.render.lightning.math.Vec3; +import com.crowsofwar.avatar.client.render.lightning.math.Vertex; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class Face +{ + public Vertex[] vertices; + public Vertex[] vertexNormals; + public Vertex faceNormal; + public TextureCoordinate[] textureCoordinates; + + @SideOnly(Side.CLIENT) + public void addFaceForRender(Tessellator tessellator) + { + addFaceForRender(tessellator, 0.0000F); + } + + @SideOnly(Side.CLIENT) + public void addFaceForRender(Tessellator tessellator, float textureOffset) + { + if (faceNormal == null) + { + faceNormal = this.calculateFaceNormal(); + } + + //tessellator.setNormal(faceNormal.x, faceNormal.y, faceNormal.z); + + float averageU = 0F; + float averageV = 0F; + + if ((textureCoordinates != null) && (textureCoordinates.length > 0)) + { + for (int i = 0; i < textureCoordinates.length; ++i) + { + averageU += textureCoordinates[i].u; + averageV += textureCoordinates[i].v; + } + + averageU = averageU / textureCoordinates.length; + averageV = averageV / textureCoordinates.length; + } + + float offsetU, offsetV; + + for (int i = 0; i < vertices.length; ++i) + { + tessellator.setNormal(vertexNormals[i].x, vertexNormals[i].y, vertexNormals[i].z); + if ((textureCoordinates != null) && (textureCoordinates.length > 0)) + { + offsetU = textureOffset; + offsetV = textureOffset; + + if (textureCoordinates[i].u > averageU) + { + offsetU = -offsetU; + } + if (textureCoordinates[i].v > averageV) + { + offsetV = -offsetV; + } + + tessellator.addVertexWithUV(vertices[i].x, vertices[i].y, vertices[i].z, textureCoordinates[i].u + offsetU, textureCoordinates[i].v + offsetV); + } + else + { + tessellator.addVertex(vertices[i].x, vertices[i].y, vertices[i].z); + } + } + } + + public Vertex calculateFaceNormal() + { + Vec3 v1 = Vec3.createVectorHelper(vertices[1].x - vertices[0].x, vertices[1].y - vertices[0].y, vertices[1].z - vertices[0].z); + Vec3 v2 = Vec3.createVectorHelper(vertices[2].x - vertices[0].x, vertices[2].y - vertices[0].y, vertices[2].z - vertices[0].z); + Vec3 normalVector = null; + + normalVector = v1.crossProduct(v2).normalize(); + + return new Vertex((float) normalVector.xCoord, (float) normalVector.yCoord, (float) normalVector.zCoord); + } +} \ No newline at end of file diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/GLCompat.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/GLCompat.java new file mode 100644 index 0000000000..0b1bc48528 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/GLCompat.java @@ -0,0 +1,696 @@ +package com.crowsofwar.avatar.client.render.lightning.render; + +import net.minecraft.client.Minecraft; +import org.lwjgl.opengl.*; + +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; + +public class GLCompat { + + public static String error = ""; + + public static int GL_ARRAY_BUFFER; + public static int GL_ELEMENT_ARRAY_BUFFER; + public static int GL_DYNAMIC_DRAW; + public static int GL_STATIC_DRAW; + + public static int GL_TEXTURE0; + + public static int GL_RENDERBUFFER; + public static int GL_FRAMEBUFFER; + public static int GL_READ_FRAMEBUFFER; + public static int GL_DRAW_FRAMEBUFFER; + public static int GL_RGBA16F; + public static int GL_DEPTH_ATTACHMENT; + public static int GL_COLOR_ATTACHMENT0; + public static int GL_DEPTH_COMPONENT24; + + public static int GL_VERTEX_SHADER; + public static int GL_FRAGMENT_SHADER; + public static int GL_COMPILE_STATUS; + public static int GL_LINK_STATUS; + public static int GL_INFO_LOG_LENGTH; + public static int GL_CURRENT_PROGRAM; + + public static int GL_FUNC_ADD; + public static int GL_MAX; + + public static int GL_SAMPLES_PASSED; + public static int GL_QUERY_RESULT_AVAILABLE; + public static int GL_QUERY_RESULT; + + public static VAOType vaoType; + public static FBOType fboType; + public static InstancingType instancingType; + public static boolean arbInstancedArrays; + public static boolean arbImaging; + public static boolean arbVbo; + public static boolean arbShaderObject; + public static boolean arbVertexProgram; + public static boolean arbVertexShader; + public static boolean arbFragmentShader; + public static boolean arbMultitexture; + public static boolean arbOcclusionQuery; + + public static int genVertexArrays(){ + switch(vaoType){ + case NORMAL: + return GL30.glGenVertexArrays(); + case ARB: + return ARBVertexArrayObject.glGenVertexArrays(); + case APPLE: + return APPLEVertexArrayObject.glGenVertexArraysAPPLE(); + } + return 0; + } + + public static void bindVertexArray(int vao){ + switch(vaoType){ + case NORMAL: + GL30.glBindVertexArray(vao); + break; + case ARB: + ARBVertexArrayObject.glBindVertexArray(vao); + break; + case APPLE: + APPLEVertexArrayObject.glBindVertexArrayAPPLE(vao); + break; + } + } + + public static int genBuffers(){ + if(arbVbo) + return ARBVertexBufferObject.glGenBuffersARB(); + else + return GL15.glGenBuffers(); + } + + public static void bindBuffer(int target, int buf){ + if(arbVbo) + ARBVertexBufferObject.glBindBufferARB(target, buf); + else + GL15.glBindBuffer(target, buf); + } + + public static void bufferData(int target, ByteBuffer data, int usage){ + if(arbVbo) + ARBVertexBufferObject.glBufferDataARB(target, data, usage); + else + GL15.glBufferData(target, data, usage); + } + + public static void vertexAttribPointer(int index, int size, int type, boolean normalized, int stride, long offset){ + if(arbVertexProgram) + ARBVertexProgram.glVertexAttribPointerARB(index, size, type, normalized, stride, offset); + else + GL20.glVertexAttribPointer(index, size, type, normalized, stride, offset); + } + + public static void enableVertexAttribArray(int index){ + if(arbVertexProgram) + ARBVertexProgram.glEnableVertexAttribArrayARB(index); + else + GL20.glEnableVertexAttribArray(index); + } + + public static void disableVertexAttribArray(int index){ + if(arbVertexProgram) + ARBVertexProgram.glDisableVertexAttribArrayARB(index); + else + GL20.glDisableVertexAttribArray(index); + } + + public static void bindAttribLocation(int program, int index, CharSequence name){ + if(arbVertexShader) + ARBVertexShader.glBindAttribLocationARB(program, index, name); + else + GL20.glBindAttribLocation(program, index, name); + } + + public static void deleteFramebuffers(int framebuffer){ + switch(fboType){ + case NORMAL: + GL30.glDeleteFramebuffers(framebuffer); + break; + case ARB: + ARBFramebufferObject.glDeleteFramebuffers(framebuffer); + break; + case EXT: + EXTFramebufferObject.glDeleteFramebuffersEXT(framebuffer); + break; + } + } + + public static void bindFramebuffer(int target, int framebuffer){ + switch(fboType){ + case NORMAL: + GL30.glBindFramebuffer(target, framebuffer); + break; + case ARB: + ARBFramebufferObject.glBindFramebuffer(target, framebuffer); + break; + case EXT: + EXTFramebufferObject.glBindFramebufferEXT(target, framebuffer); + break; + } + } + + public static void framebufferTexture2D(int target, int attachment, int textarget, int texture, int level){ + switch(fboType){ + case NORMAL: + GL30.glFramebufferTexture2D(target, attachment, textarget, texture, level); + break; + case ARB: + ARBFramebufferObject.glFramebufferTexture2D(target, attachment, textarget, texture, level); + break; + case EXT: + EXTFramebufferObject.glFramebufferTexture2DEXT(target, attachment, textarget, texture, level); + break; + } + } + + public static void bindRenderbuffer(int target, int renderbuffer){ + switch(fboType){ + case NORMAL: + GL30.glBindRenderbuffer(target, renderbuffer); + break; + case ARB: + ARBFramebufferObject.glBindRenderbuffer(target, renderbuffer); + break; + case EXT: + EXTFramebufferObject.glBindRenderbufferEXT(target, renderbuffer); + break; + } + } + + public static int genRenderbuffers(){ + switch(fboType){ + case NORMAL: + return GL30.glGenRenderbuffers(); + case ARB: + return ARBFramebufferObject.glGenRenderbuffers(); + case EXT: + return EXTFramebufferObject.glGenRenderbuffersEXT(); + } + return 0; + } + + public static void renderbufferStorage(int target, int internalformat, int width, int height){ + switch(fboType){ + case NORMAL: + GL30.glRenderbufferStorage(target, internalformat, width, height); + break; + case ARB: + ARBFramebufferObject.glRenderbufferStorage(target, internalformat, width, height); + break; + case EXT: + EXTFramebufferObject.glRenderbufferStorageEXT(target, internalformat, width, height); + break; + } + } + + public static void framebufferRenderbuffer(int target, int attachment, int renderbuffertarget, int renderbuffer){ + switch(fboType){ + case NORMAL: + GL30.glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); + break; + case ARB: + ARBFramebufferObject.glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); + break; + case EXT: + EXTFramebufferObject.glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, renderbuffer); + break; + } + } + + public static void deleteRenderbuffers(int renderbuffer){ + switch(fboType){ + case NORMAL: + GL30.glDeleteRenderbuffers(renderbuffer); + break; + case ARB: + ARBFramebufferObject.glDeleteRenderbuffers(renderbuffer); + break; + case EXT: + EXTFramebufferObject.glDeleteRenderbuffersEXT(renderbuffer); + break; + } + } + + public static int genFramebuffers(){ + switch(fboType){ + case NORMAL: + return GL30.glGenFramebuffers(); + case ARB: + return ARBFramebufferObject.glGenFramebuffers(); + case EXT: + return EXTFramebufferObject.glGenFramebuffersEXT(); + } + return 0; + } + + public static void blitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter){ + switch(fboType){ + case NORMAL: + GL30.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + break; + case ARB: + ARBFramebufferObject.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + break; + case EXT: + EXTFramebufferBlit.glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + break; + } + } + + public static void activeTexture(int tex){ + if(arbMultitexture) + ARBMultitexture.glActiveTextureARB(tex); + else + GL13.glActiveTexture(tex); + } + + public static void blendEquation(int mode){ + if(arbImaging) + ARBImaging.glBlendEquation(mode); + else + GL14.glBlendEquation(mode); + } + + public static void drawArraysInstanced(int mode, int first, int count, int primcount){ + switch(instancingType){ + case NORMAL: + GL31.glDrawArraysInstanced(mode, first, count, primcount); + break; + case ARB: + ARBDrawInstanced.glDrawArraysInstancedARB(mode, first, count, primcount); + break; + case EXT: + EXTDrawInstanced.glDrawArraysInstancedEXT(mode, first, count, primcount); + break; + } + } + + public static void vertexAttribDivisor(int index, int divisor){ + if(arbInstancedArrays) + ARBInstancedArrays.glVertexAttribDivisorARB(index, divisor); + else + GL33.glVertexAttribDivisor(index, divisor); + } + + public static int genQueries(){ + if(arbOcclusionQuery) + return ARBOcclusionQuery.glGenQueriesARB(); + else + return GL15.glGenQueries(); + } + + public static void beginQuery(int target, int id){ + if(arbOcclusionQuery) + ARBOcclusionQuery.glBeginQueryARB(target, id); + else + GL15.glBeginQuery(target, id); + } + + public static void endQuery(int target){ + if(arbOcclusionQuery) + ARBOcclusionQuery.glEndQueryARB(target); + else + GL15.glEndQuery(target); + } + + public static void deleteQueries(int id){ + if(arbOcclusionQuery) + ARBOcclusionQuery.glDeleteQueriesARB(id); + else + GL15.glDeleteQueries(id); + } + + public static int getQueryObject(int id, int pname){ + if(arbOcclusionQuery) + return ARBOcclusionQuery.glGetQueryObjectuiARB(id, pname); + else + return GL15.glGetQueryObjectui(id, pname); + } + + + + public static int getUniformLocation(int program, CharSequence name){ + if(arbShaderObject) + return ARBShaderObjects.glGetUniformLocationARB(program, name); + else + return GL20.glGetUniformLocation(program, name); + } + + public static void uniform1i(int location, int i){ + if(arbShaderObject) + ARBShaderObjects.glUniform1iARB(location, i); + else + GL20.glUniform1i(location, i); + } + + public static void uniform1f(int location, float f){ + if(arbShaderObject) + ARBShaderObjects.glUniform1fARB(location, f); + else + GL20.glUniform1f(location, f); + } + + public static void uniform2f(int location, float f1, float f2){ + if(arbShaderObject) + ARBShaderObjects.glUniform2fARB(location, f1, f2); + else + GL20.glUniform2f(location, f1, f2); + } + + public static void uniform3f(int location, float f1, float f2, float f3){ + if(arbShaderObject) + ARBShaderObjects.glUniform3fARB(location, f1, f2, f3); + else + GL20.glUniform3f(location, f1, f2, f3); + } + + public static void uniform4f(int location, float f1, float f2, float f3, float f4){ + if(arbShaderObject) + ARBShaderObjects.glUniform4fARB(location, f1, f2, f3, f4); + else + GL20.glUniform4f(location, f1, f2, f3, f4); + } + + public static void uniformMatrix3(int location, boolean transpose, FloatBuffer matrices){ + if(arbShaderObject) + ARBShaderObjects.glUniformMatrix3ARB(location, transpose, matrices); + else + GL20.glUniformMatrix3(location, transpose, matrices); + } + + public static void uniformMatrix4(int location, boolean transpose, FloatBuffer matrices){ + if(arbShaderObject) + ARBShaderObjects.glUniformMatrix4ARB(location, transpose, matrices); + else + GL20.glUniformMatrix4(location, transpose, matrices); + } + + public static int createProgram(){ + if(arbShaderObject) + return ARBShaderObjects.glCreateProgramObjectARB(); + else + return GL20.glCreateProgram(); + } + + public static int createShader(int shaderType){ + if(arbShaderObject) + return ARBShaderObjects.glCreateShaderObjectARB(shaderType); + else + return GL20.glCreateShader(shaderType); + } + + public static void shaderSource(int shader, ByteBuffer string){ + if(arbShaderObject) + ARBShaderObjects.glShaderSourceARB(shader, string); + else + GL20.glShaderSource(shader, string); + } + + public static void compileShader(int shader){ + if(arbShaderObject) + ARBShaderObjects.glCompileShaderARB(shader); + else + GL20.glCompileShader(shader); + } + + public static int getShaderi(int shader, int pname){ + if(arbShaderObject) + return ARBShaderObjects.glGetObjectParameteriARB(shader, pname); + else + return GL20.glGetShaderi(shader, pname); + } + + public static String getShaderInfoLog(int shader, int length){ + if(arbShaderObject) + return ARBShaderObjects.glGetInfoLogARB(shader, length); + else + return GL20.glGetShaderInfoLog(shader, length); + } + + public static void attachShader(int program, int shader){ + if(arbShaderObject) + ARBShaderObjects.glAttachObjectARB(program, shader); + else + GL20.glAttachShader(program, shader); + } + + public static void linkProgram(int program){ + if(arbShaderObject) + ARBShaderObjects.glLinkProgramARB(program); + else + GL20.glLinkProgram(program); + } + + public static int getProgrami(int program, int pname){ + if(arbShaderObject) + return ARBShaderObjects.glGetObjectParameteriARB(program, pname); + else + return GL20.glGetProgrami(program, pname); + } + + public static String getProgramInfoLog(int program, int length){ + if(arbShaderObject) + return ARBShaderObjects.glGetInfoLogARB(program, length); + else + return GL20.glGetProgramInfoLog(program, length); + } + + public static void deleteShader(int shader){ + if(arbShaderObject) + ARBShaderObjects.glDeleteObjectARB(shader); + else + GL20.glDeleteShader(shader); + } + + public static void useProgram(int program){ + if(arbShaderObject) + ARBShaderObjects.glUseProgramObjectARB(program); + else + GL20.glUseProgram(program); + } + + + public static String init(){ + ContextCapabilities cap = GLContext.getCapabilities(); + + if(cap.OpenGL30) + vaoType = VAOType.NORMAL; + else if(Minecraft.IS_RUNNING_ON_MAC) + vaoType = VAOType.APPLE; + else if(cap.GL_ARB_vertex_array_object) + vaoType = VAOType.ARB; + else + return "VAO not supported"; + + if(cap.OpenGL15) + arbVbo = false; + else if(cap.GL_ARB_vertex_buffer_object) + arbVbo = true; + else + return "VBO not supported"; + + if(cap.OpenGL31) + instancingType = InstancingType.NORMAL; + else if(cap.GL_ARB_draw_instanced) + instancingType = InstancingType.ARB; + else if(cap.GL_EXT_draw_instanced) + instancingType = InstancingType.EXT; + else + return "Instancing not supported"; + + if(cap.OpenGL33) + arbInstancedArrays = false; + else if(cap.GL_ARB_instanced_arrays) + arbInstancedArrays = true; + else + return "Instanced arrays not supported"; + + if(cap.OpenGL20) + arbShaderObject = false; + else if(cap.GL_ARB_shader_objects) + arbShaderObject = true; + else + return "Shaders not supported"; + + if(cap.OpenGL20) + arbVertexProgram = false; + else if(cap.GL_ARB_vertex_program) + arbVertexProgram = true; + else + return "Vertex program not supported"; + + if(cap.OpenGL20) + arbVertexShader = false; + else if(cap.GL_ARB_vertex_shader) + arbVertexShader = true; + else + return "Vertex shader not supported"; + + if(cap.OpenGL20) + arbFragmentShader = false; + else if(cap.GL_ARB_fragment_shader) + arbFragmentShader = true; + else + return "Fragment shader not supported"; + + if(cap.OpenGL30) + fboType = FBOType.NORMAL; + else if(cap.GL_ARB_framebuffer_object) + fboType = FBOType.ARB; + else if(cap.GL_EXT_framebuffer_object && cap.GL_EXT_framebuffer_blit) + fboType = FBOType.EXT; + else + return "Framebuffer objects not supported"; + + if(cap.OpenGL13) + arbMultitexture = false; + else if(cap.GL_ARB_multitexture) + arbMultitexture = true; + else + return "Multitexturing not supported"; + + if(cap.OpenGL14) + arbImaging = false; + else if(cap.GL_ARB_imaging) + arbImaging = true; + else + return "Imaging not supported"; + + if(cap.OpenGL15) + arbOcclusionQuery = false; + else if(cap.GL_ARB_occlusion_query) + arbOcclusionQuery = true; + else + return "Occlusion queries not supported"; + + if(arbVertexProgram){ + GL_ARRAY_BUFFER = ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB; + GL_ELEMENT_ARRAY_BUFFER = ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB; + GL_DYNAMIC_DRAW = ARBVertexBufferObject.GL_DYNAMIC_DRAW_ARB; + GL_STATIC_DRAW = ARBVertexBufferObject.GL_STATIC_DRAW_ARB; + } else { + GL_ARRAY_BUFFER = GL15.GL_ARRAY_BUFFER; + GL_ELEMENT_ARRAY_BUFFER = GL15.GL_ELEMENT_ARRAY_BUFFER; + GL_DYNAMIC_DRAW = GL15.GL_DYNAMIC_DRAW; + GL_STATIC_DRAW = GL15.GL_STATIC_DRAW; + } + + if(arbMultitexture){ + GL_TEXTURE0 = ARBMultitexture.GL_TEXTURE0_ARB; + } else { + GL_TEXTURE0 = GL13.GL_TEXTURE0; + } + + if(fboType == FBOType.NORMAL){ + GL_RENDERBUFFER = GL30.GL_RENDERBUFFER; + GL_FRAMEBUFFER = GL30.GL_FRAMEBUFFER; + GL_READ_FRAMEBUFFER = GL30.GL_READ_FRAMEBUFFER; + GL_DRAW_FRAMEBUFFER = GL30.GL_DRAW_FRAMEBUFFER; + GL_DEPTH_ATTACHMENT = GL30.GL_DEPTH_ATTACHMENT; + GL_COLOR_ATTACHMENT0 = GL30.GL_COLOR_ATTACHMENT0; + } else if(fboType == FBOType.ARB){ + GL_RENDERBUFFER = ARBFramebufferObject.GL_RENDERBUFFER; + GL_FRAMEBUFFER = ARBFramebufferObject.GL_FRAMEBUFFER; + GL_READ_FRAMEBUFFER = ARBFramebufferObject.GL_READ_FRAMEBUFFER; + GL_DRAW_FRAMEBUFFER = ARBFramebufferObject.GL_DRAW_FRAMEBUFFER; + GL_DEPTH_ATTACHMENT = ARBFramebufferObject.GL_DEPTH_ATTACHMENT; + GL_COLOR_ATTACHMENT0 = ARBFramebufferObject.GL_COLOR_ATTACHMENT0; + } else if(fboType == FBOType.EXT){ + GL_RENDERBUFFER = EXTFramebufferObject.GL_RENDERBUFFER_EXT; + GL_FRAMEBUFFER = EXTFramebufferObject.GL_FRAMEBUFFER_EXT; + GL_READ_FRAMEBUFFER = EXTFramebufferBlit.GL_READ_FRAMEBUFFER_EXT; + GL_DRAW_FRAMEBUFFER = EXTFramebufferBlit.GL_DRAW_FRAMEBUFFER_EXT; + GL_DEPTH_ATTACHMENT = EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT; + GL_COLOR_ATTACHMENT0 = EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT; + } + + if(cap.OpenGL30) + GL_RGBA16F = GL30.GL_RGBA16F; + else if(cap.GL_APPLE_float_pixels) + GL_RGBA16F = APPLEFloatPixels.GL_RGBA_FLOAT16_APPLE; + else if(cap.GL_ARB_texture_float) + GL_RGBA16F = ARBTextureFloat.GL_RGBA16F_ARB; + else if(cap.GL_ATI_texture_float) + GL_RGBA16F = ATITextureFloat.GL_RGBA_FLOAT16_ATI; + else + return "Floating point texture format not supported"; + + if(cap.OpenGL14) + GL_DEPTH_COMPONENT24 = GL14.GL_DEPTH_COMPONENT24; + else if(cap.GL_ARB_depth_texture) + GL_DEPTH_COMPONENT24 = ARBDepthTexture.GL_DEPTH_COMPONENT24_ARB; + else + return "24 bit depth not supported"; + + if(arbShaderObject){ + GL_COMPILE_STATUS = ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB; + GL_LINK_STATUS = ARBShaderObjects.GL_OBJECT_LINK_STATUS_ARB; + GL_INFO_LOG_LENGTH = ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB; + //Apparently the ARB thing doesn't have this, let's just hope it works + GL_CURRENT_PROGRAM = GL20.GL_CURRENT_PROGRAM; + } else { + GL_COMPILE_STATUS = GL20.GL_COMPILE_STATUS; + GL_LINK_STATUS = GL20.GL_LINK_STATUS; + GL_INFO_LOG_LENGTH = GL20.GL_INFO_LOG_LENGTH; + GL_CURRENT_PROGRAM = GL20.GL_CURRENT_PROGRAM; + } + + if(arbVertexShader){ + GL_VERTEX_SHADER = ARBVertexShader.GL_VERTEX_SHADER_ARB; + } else { + GL_VERTEX_SHADER = GL20.GL_VERTEX_SHADER; + } + + if(arbFragmentShader){ + GL_FRAGMENT_SHADER = ARBFragmentShader.GL_FRAGMENT_SHADER_ARB; + } else { + GL_FRAGMENT_SHADER = GL20.GL_FRAGMENT_SHADER; + } + + if(arbImaging){ + GL_FUNC_ADD = ARBImaging.GL_FUNC_ADD; + GL_MAX = ARBImaging.GL_MAX; + } else { + GL_FUNC_ADD = GL14.GL_FUNC_ADD; + GL_MAX = GL14.GL_MAX; + } + + if(arbOcclusionQuery){ + GL_SAMPLES_PASSED = ARBOcclusionQuery.GL_SAMPLES_PASSED_ARB; + GL_QUERY_RESULT_AVAILABLE = ARBOcclusionQuery.GL_QUERY_RESULT_AVAILABLE_ARB; + GL_QUERY_RESULT = ARBOcclusionQuery.GL_QUERY_RESULT_ARB; + } else { + GL_SAMPLES_PASSED = GL15.GL_SAMPLES_PASSED; + GL_QUERY_RESULT_AVAILABLE = GL15.GL_QUERY_RESULT_AVAILABLE; + GL_QUERY_RESULT = GL15.GL_QUERY_RESULT; + } + + return ""; + } + + public static enum VAOType { + NORMAL, + ARB, + APPLE; + } + + public static enum FBOType { + NORMAL, + ARB, + EXT; + } + + public static enum InstancingType { + NORMAL, + ARB, + EXT; + } + +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/GroupObject.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/GroupObject.java new file mode 100644 index 0000000000..fc7efbad32 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/GroupObject.java @@ -0,0 +1,54 @@ +package com.crowsofwar.avatar.client.render.lightning.render; + +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import java.util.ArrayList; + +public class GroupObject +{ + public String name; + public ArrayList faces = new ArrayList(); + public int glDrawingMode; + + public GroupObject() + { + this(""); + } + + public GroupObject(String name) + { + this(name, -1); + } + + public GroupObject(String name, int glDrawingMode) + { + this.name = name; + this.glDrawingMode = glDrawingMode; + } + + @SideOnly(Side.CLIENT) + public void render() + { + if (faces.size() > 0) + { + + Tessellator tessellator = Tessellator.instance; + tessellator.startDrawing(glDrawingMode); + render(tessellator); + tessellator.draw(); + } + } + + @SideOnly(Side.CLIENT) + public void render(Tessellator tessellator) + { + if (faces.size() > 0) + { + for (Face face : faces) + { + face.addFaceForRender(tessellator); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/IModelCustom.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/IModelCustom.java new file mode 100644 index 0000000000..3c200496cd --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/IModelCustom.java @@ -0,0 +1,18 @@ +package com.crowsofwar.avatar.client.render.lightning.render; + +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public interface IModelCustom +{ + public String getType(); + public void renderAll(); + public void renderOnly(String... groupNames); + public void renderPart(String partName); + public void renderAllExcept(String... excludedGroupNames); + public void tessellateAll(Tessellator tes); + public void tessellatePart(Tessellator tes, String name); + public void tessellateOnly(Tessellator tes, String... names); + public void tessellateAllExcept(Tessellator tes, String... excluded); +} \ No newline at end of file diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/IModelCustomLoader.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/IModelCustomLoader.java new file mode 100644 index 0000000000..63d0d6097f --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/IModelCustomLoader.java @@ -0,0 +1,23 @@ +package com.crowsofwar.avatar.client.render.lightning.render; + +import net.minecraft.util.ResourceLocation; + +public interface IModelCustomLoader { + /** + * Get the main type name for this loader + * @return the type name + */ + String getType(); + /** + * Get resource suffixes this model loader recognizes + * @return a list of suffixes + */ + String[] getSuffixes(); + /** + * Load a model instance from the supplied path + * @param resource The ResourceLocation of the model + * @return A model instance + * @throws ModelFormatException if the model format is not correct + */ + IModelCustom loadInstance(ResourceLocation resource) throws ModelFormatException; +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/ModelFormatException.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/ModelFormatException.java new file mode 100644 index 0000000000..3d749cdb25 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/ModelFormatException.java @@ -0,0 +1,27 @@ +package com.crowsofwar.avatar.client.render.lightning.render; + +public class ModelFormatException extends RuntimeException { + + private static final long serialVersionUID = 2023547503969671835L; + + public ModelFormatException() + { + super(); + } + + public ModelFormatException(String message, Throwable cause) + { + super(message, cause); + } + + public ModelFormatException(String message) + { + super(message); + } + + public ModelFormatException(Throwable cause) + { + super(cause); + } + +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/ModelRendererUtil.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/ModelRendererUtil.java new file mode 100644 index 0000000000..ca3e83a43c --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/ModelRendererUtil.java @@ -0,0 +1,299 @@ +package com.crowsofwar.avatar.client.render.lightning.render; + +import com.crowsofwar.avatar.AvatarMod; +import com.crowsofwar.avatar.client.render.lightning.main.ResourceManager; +import com.crowsofwar.avatar.client.render.lightning.math.BobMathUtil; +import com.crowsofwar.avatar.network.AvatarClientProxy; +import net.minecraft.client.Minecraft; +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelBox; +import net.minecraft.client.model.ModelRenderer; +import net.minecraft.client.model.TexturedQuad; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderLivingBase; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.ReflectionHelper; +import org.apache.commons.lang3.tuple.Pair; +import org.lwjgl.opengl.GL11; +import org.lwjgl.util.vector.Matrix4f; + +import javax.annotation.Nullable; +import javax.vecmath.Matrix3f; +import javax.vecmath.Vector3f; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.function.Consumer; + +public class ModelRendererUtil { + + //Need to call this because things like bats do extra scaling + public static Method rPrepareScale; + public static Method rGetEntityTexture; + public static Method rHandleRotationFloat; + public static Method rApplyRotations; + public static Field rQuadList; + public static Field rCompiled; + + public static ResourceLocation getEntityTexture(Entity e){ + Render eRenderer = Minecraft.getMinecraft().getRenderManager().getEntityRenderObject(e); + if(rGetEntityTexture == null){ + rGetEntityTexture = ReflectionHelper.findMethod(Render.class, "getEntityTexture", "func_110775_a", Entity.class); + } + ResourceLocation r = null; + try { + r = (ResourceLocation) rGetEntityTexture.invoke(eRenderer, e); + } catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) { + e1.printStackTrace(); + } + return r == null ? ResourceManager.turbofan_blades_tex : r; + } + + + @SuppressWarnings("deprecation") + private static List> getBoxesFromMob(EntityLivingBase e, RenderLivingBase render, float partialTicks) { + ModelBase model = render.getMainModel(); + GL11.glPushMatrix(); + GL11.glLoadIdentity(); + GlStateManager.disableCull(); + GlStateManager.enableRescaleNormal(); + //So basically we're just going to copy vanialla methods so the + model.swingProgress = e.getSwingProgress(partialTicks); + boolean shouldSit = e.isRiding() && (e.getRidingEntity() != null && e.getRidingEntity().shouldRiderSit()); + model.isRiding = shouldSit; + model.isChild = e.isChild(); + float f = interpolateRotation(e.prevRenderYawOffset, e.renderYawOffset, partialTicks); + float f1 = interpolateRotation(e.prevRotationYawHead, e.rotationYawHead, partialTicks); + float f2 = f1 - f; + if(shouldSit && e.getRidingEntity() instanceof EntityLivingBase) { + EntityLivingBase elivingbase = (EntityLivingBase) e.getRidingEntity(); + f = interpolateRotation(elivingbase.prevRenderYawOffset, elivingbase.renderYawOffset, partialTicks); + f2 = f1 - f; + float f3 = MathHelper.wrapDegrees(f2); + + if(f3 < -85.0F) { + f3 = -85.0F; + } + + if(f3 >= 85.0F) { + f3 = 85.0F; + } + + f = f1 - f3; + + if(f3 * f3 > 2500.0F) { + f += f3 * 0.2F; + } + + f2 = f1 - f; + } + + float f7 = e.prevRotationPitch + (e.rotationPitch - e.prevRotationPitch) * partialTicks; + //renderLivingAt(e, x, y, z); + //float f8 = e.ticksExisted + partialTicks; + //GlStateManager.rotate(180.0F - f, 0.0F, 1.0F, 0.0F); + //if(rPreRenderCallback == null){ + // rPreRenderCallback = ReflectionHelper.findMethod(RenderLivingBase.class, "preRenderCallback", "func_77041_b", EntityLivingBase.class, float.class); + //} + if(rPrepareScale == null){ + rPrepareScale = ReflectionHelper.findMethod(RenderLivingBase.class, "prepareScale", "func_188322_c", EntityLivingBase.class, float.class); + } + //float f4 = prepareScale(e, partialTicks, render); + if(rHandleRotationFloat == null){ + rHandleRotationFloat = ReflectionHelper.findMethod(RenderLivingBase.class, "handleRotationFloat", "func_77044_a", EntityLivingBase.class, float.class); + rApplyRotations = ReflectionHelper.findMethod(RenderLivingBase.class, "applyRotations", "func_77043_a", EntityLivingBase.class, float.class, float.class, float.class); + } + + float f8 = 0; + try { + f8 = (Float)rHandleRotationFloat.invoke(render, e, partialTicks); + rApplyRotations.invoke(render, e, f8, f, partialTicks); + } catch(Exception x){ + } + + //this.applyRotations(entity, f8, f, partialTicks); + + float f4 = 0.0625F; + try { + f4 = (float) rPrepareScale.invoke(render, e, partialTicks); + } catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException e2) { + e2.printStackTrace(); + } + float f5 = 0.0F; + float f6 = 0.0F; + if(!e.isRiding()) { + f5 = e.prevLimbSwingAmount + (e.limbSwingAmount - e.prevLimbSwingAmount) * partialTicks; + f6 = e.limbSwing - e.limbSwingAmount * (1.0F - partialTicks); + + if(e.isChild()) { + f6 *= 3.0F; + } + + if(f5 > 1.0F) { + f5 = 1.0F; + } + f2 = f1 - f; // Forge: Fix MC-1207 + } + model.setLivingAnimations(e, f6, f5, partialTicks); + model.setRotationAngles(f6, f5, f8, f2, f7, f4, e); + + if(rGetEntityTexture == null){ + rGetEntityTexture = ReflectionHelper.findMethod(Render.class, "getEntityTexture", "func_110775_a", Entity.class); + } + ResourceLocation r = ResourceManager.turbofan_blades_tex; + try { + r = (ResourceLocation) rGetEntityTexture.invoke(render, e); + if(r == null) + r = ResourceManager.turbofan_blades_tex; + } catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) { + e1.printStackTrace(); + } + if(rCompiled == null){ + rCompiled = ReflectionHelper.findField(ModelRenderer.class, "compiled", "field_78812_q"); + } + List> list = new ArrayList<>(); + for(ModelRenderer renderer : model.boxList) { + if(!isChild(renderer, model.boxList)) + generateList(e.world, e, f4, list, renderer, r); + } + + GlStateManager.disableRescaleNormal(); + GlStateManager.enableCull(); + GL11.glPopMatrix(); + return list; + } + + public static boolean isChild(ModelRenderer r, List list){ + for(ModelRenderer r2 : list){ + if(r2.childModels != null && r2.childModels.contains(r)) + return true; + } + return false; + } + + protected static void generateList(World world, EntityLivingBase ent, float scale, List> list, ModelRenderer render, ResourceLocation tex){ + boolean compiled = false; + try { + //A lot of mobs weirdly replace model renderers and end up with extra ones in the list that aren't ever rendered. + //Since they're not rendered, they should never be compiled, so this hack tries to detect that. + //Not the greatest method ever, but it appears to work. + compiled = rCompiled.getBoolean(render); + } catch(Exception x){ + } + if(render.isHidden || !render.showModel || !compiled) + return; + GL11.glPushMatrix(); + doTransforms(render, scale); + if(render.childModels != null) + for(ModelRenderer renderer : render.childModels) { + generateList(world, ent, scale, list, renderer, tex); + } + GL11.glScaled(scale, scale, scale); + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, AvatarClientProxy.AUX_GL_BUFFER); + Matrix4f mat = new Matrix4f(); + mat.load(AvatarClientProxy.AUX_GL_BUFFER); + AvatarClientProxy.AUX_GL_BUFFER.rewind(); + list.add(Pair.of(mat, render)); + GL11.glPopMatrix(); + } + + public static void doTransforms(ModelRenderer m, float scale) { + GlStateManager.translate(m.offsetX, m.offsetY, m.offsetZ); + if(m.rotateAngleX == 0.0F && m.rotateAngleY == 0.0F && m.rotateAngleZ == 0.0F) { + if(m.rotationPointX == 0.0F && m.rotationPointY == 0.0F && m.rotationPointZ == 0.0F) { + } else { + GlStateManager.translate(m.rotationPointX * scale, m.rotationPointY * scale, m.rotationPointZ * scale); + } + } else { + GlStateManager.translate(m.rotationPointX * scale, m.rotationPointY * scale, m.rotationPointZ * scale); + if(m.rotateAngleZ != 0.0F) { + GlStateManager.rotate(m.rotateAngleZ * (180F / (float) Math.PI), 0.0F, 0.0F, 1.0F); + } + if(m.rotateAngleY != 0.0F) { + GlStateManager.rotate(m.rotateAngleY * (180F / (float) Math.PI), 0.0F, 1.0F, 0.0F); + } + if(m.rotateAngleX != 0.0F) { + GlStateManager.rotate(m.rotateAngleX * (180F / (float) Math.PI), 1.0F, 0.0F, 0.0F); + } + } + } + + protected static float interpolateRotation(float prevYawOffset, float yawOffset, float partialTicks) { + float f; + + for(f = yawOffset - prevYawOffset; f < -180.0F; f += 360.0F) { + ; + } + + while(f >= 180.0F) { + f -= 360.0F; + } + + return prevYawOffset + partialTicks * f; + } + + public static class VertexData { + public Vec3d[] positions; + public int[] positionIndices; + public float[] texCoords; + + public void tessellate(BufferBuilder buf, boolean normal){ + tessellate(buf, false, normal); + } + + public void tessellate(BufferBuilder buf, boolean flip, boolean normal){ + if(positionIndices != null) + for(int i = 0; i < positionIndices.length; i += 3){ + Vec3d a = positions[positionIndices[i]]; + Vec3d b = positions[positionIndices[i+1]]; + Vec3d c = positions[positionIndices[i+2]]; + //Offset into texcoord array + int tOB = 1; + int tOC = 2; + if(flip){ + Vec3d tmp = b; + b = c; + c = tmp; + tOB = 2; + tOC = 1; + } + if(normal){ + Vec3d norm = b.subtract(a).crossProduct(c.subtract(a)).normalize(); + buf.pos(a.x, a.y, a.z).tex(texCoords[i*2+0], texCoords[i*2+1]).normal((float)norm.x, (float)norm.y, (float)norm.z).endVertex(); + buf.pos(b.x, b.y, b.z).tex(texCoords[(i+tOB)*2+0], texCoords[(i+tOB)*2+1]).normal((float)norm.x, (float)norm.y, (float)norm.z).endVertex(); + buf.pos(c.x, c.y, c.z).tex(texCoords[(i+tOC)*2+0], texCoords[(i+tOC)*2+1]).normal((float)norm.x, (float)norm.y, (float)norm.z).endVertex(); + } else { + buf.pos(a.x, a.y, a.z).tex(texCoords[i*2+0], texCoords[i*2+1]).endVertex(); + buf.pos(b.x, b.y, b.z).tex(texCoords[(i+tOB)*2+0], texCoords[(i+tOB)*2+1]).endVertex(); + buf.pos(c.x, c.y, c.z).tex(texCoords[(i+tOC)*2+0], texCoords[(i+tOC)*2+1]).endVertex(); + } + + } + } + + public float[] vertexArray() { + float[] verts = new float[positions.length*3]; + for(int i = 0; i < positions.length; i ++){ + Vec3d pos = positions[i]; + verts[i*3] = (float) pos.x; + verts[i*3+1] = (float) pos.y; + verts[i*3+2] = (float) pos.z; + } + return verts; + } + } + +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/ObjModelLoader.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/ObjModelLoader.java new file mode 100644 index 0000000000..eb1764017e --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/ObjModelLoader.java @@ -0,0 +1,26 @@ +package com.crowsofwar.avatar.client.render.lightning.render; + +import net.minecraft.util.ResourceLocation; + +public class ObjModelLoader implements IModelCustomLoader +{ + + @Override + public String getType() + { + return "OBJ model"; + } + + private static final String[] types = { "obj" }; + @Override + public String[] getSuffixes() + { + return types; + } + + @Override + public IModelCustom loadInstance(ResourceLocation resource) throws ModelFormatException + { + return new WavefrontObject(resource); + } +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/QuadComparator.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/QuadComparator.java new file mode 100644 index 0000000000..4930110ea4 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/QuadComparator.java @@ -0,0 +1,65 @@ +package com.crowsofwar.avatar.client.render.lightning.render; + +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import java.util.Comparator; + +@SideOnly(Side.CLIENT) +public class QuadComparator implements Comparator +{ + private float field_147630_a; + private float field_147628_b; + private float field_147629_c; + private int[] field_147627_d; + + public QuadComparator(int[] p_i45077_1_, float p_i45077_2_, float p_i45077_3_, float p_i45077_4_) + { + this.field_147627_d = p_i45077_1_; + this.field_147630_a = p_i45077_2_; + this.field_147628_b = p_i45077_3_; + this.field_147629_c = p_i45077_4_; + } + + public int compare(Integer p_compare_1_, Integer p_compare_2_) + { + float f = Float.intBitsToFloat(this.field_147627_d[p_compare_1_.intValue()]) - this.field_147630_a; + float f1 = Float.intBitsToFloat(this.field_147627_d[p_compare_1_.intValue() + 1]) - this.field_147628_b; + float f2 = Float.intBitsToFloat(this.field_147627_d[p_compare_1_.intValue() + 2]) - this.field_147629_c; + float f3 = Float.intBitsToFloat(this.field_147627_d[p_compare_1_.intValue() + 8]) - this.field_147630_a; + float f4 = Float.intBitsToFloat(this.field_147627_d[p_compare_1_.intValue() + 9]) - this.field_147628_b; + float f5 = Float.intBitsToFloat(this.field_147627_d[p_compare_1_.intValue() + 10]) - this.field_147629_c; + float f6 = Float.intBitsToFloat(this.field_147627_d[p_compare_1_.intValue() + 16]) - this.field_147630_a; + float f7 = Float.intBitsToFloat(this.field_147627_d[p_compare_1_.intValue() + 17]) - this.field_147628_b; + float f8 = Float.intBitsToFloat(this.field_147627_d[p_compare_1_.intValue() + 18]) - this.field_147629_c; + float f9 = Float.intBitsToFloat(this.field_147627_d[p_compare_1_.intValue() + 24]) - this.field_147630_a; + float f10 = Float.intBitsToFloat(this.field_147627_d[p_compare_1_.intValue() + 25]) - this.field_147628_b; + float f11 = Float.intBitsToFloat(this.field_147627_d[p_compare_1_.intValue() + 26]) - this.field_147629_c; + float f12 = Float.intBitsToFloat(this.field_147627_d[p_compare_2_.intValue()]) - this.field_147630_a; + float f13 = Float.intBitsToFloat(this.field_147627_d[p_compare_2_.intValue() + 1]) - this.field_147628_b; + float f14 = Float.intBitsToFloat(this.field_147627_d[p_compare_2_.intValue() + 2]) - this.field_147629_c; + float f15 = Float.intBitsToFloat(this.field_147627_d[p_compare_2_.intValue() + 8]) - this.field_147630_a; + float f16 = Float.intBitsToFloat(this.field_147627_d[p_compare_2_.intValue() + 9]) - this.field_147628_b; + float f17 = Float.intBitsToFloat(this.field_147627_d[p_compare_2_.intValue() + 10]) - this.field_147629_c; + float f18 = Float.intBitsToFloat(this.field_147627_d[p_compare_2_.intValue() + 16]) - this.field_147630_a; + float f19 = Float.intBitsToFloat(this.field_147627_d[p_compare_2_.intValue() + 17]) - this.field_147628_b; + float f20 = Float.intBitsToFloat(this.field_147627_d[p_compare_2_.intValue() + 18]) - this.field_147629_c; + float f21 = Float.intBitsToFloat(this.field_147627_d[p_compare_2_.intValue() + 24]) - this.field_147630_a; + float f22 = Float.intBitsToFloat(this.field_147627_d[p_compare_2_.intValue() + 25]) - this.field_147628_b; + float f23 = Float.intBitsToFloat(this.field_147627_d[p_compare_2_.intValue() + 26]) - this.field_147629_c; + float f24 = (f + f3 + f6 + f9) * 0.25F; + float f25 = (f1 + f4 + f7 + f10) * 0.25F; + float f26 = (f2 + f5 + f8 + f11) * 0.25F; + float f27 = (f12 + f15 + f18 + f21) * 0.25F; + float f28 = (f13 + f16 + f19 + f22) * 0.25F; + float f29 = (f14 + f17 + f20 + f23) * 0.25F; + float f30 = f24 * f24 + f25 * f25 + f26 * f26; + float f31 = f27 * f27 + f28 * f28 + f29 * f29; + return Float.compare(f31, f30); + } + + public int compare(Object p_compare_1_, Object p_compare_2_) + { + return this.compare((Integer)p_compare_1_, (Integer)p_compare_2_); + } +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/RenderHelper.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/RenderHelper.java new file mode 100644 index 0000000000..482b9ba5a9 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/RenderHelper.java @@ -0,0 +1,503 @@ +package com.crowsofwar.avatar.client.render.lightning.render; + +import com.crowsofwar.avatar.AvatarMod; +import com.crowsofwar.avatar.client.render.lightning.math.BobMathUtil; + +import com.crowsofwar.avatar.network.AvatarClientProxy; +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.IBakedModel; +import net.minecraft.client.renderer.chunk.RenderChunk; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.renderer.vertex.VertexBuffer; +import net.minecraft.client.renderer.vertex.VertexFormatElement; +import net.minecraft.entity.Entity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.fml.relauncher.ReflectionHelper; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL20; +import org.lwjgl.util.glu.Project; +import org.lwjgl.util.vector.Matrix4f; +import org.lwjgl.util.vector.Vector3f; +import org.lwjgl.util.vector.Vector4f; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +@SideOnly(Side.CLIENT) +public class RenderHelper { + + public static Field r_setTileEntities; + public static Field r_viewFrustum; + public static Method r_getRenderChunk; + + private static FloatBuffer MODELVIEW = GLAllocation.createDirectFloatBuffer(16); + private static FloatBuffer PROJECTION = GLAllocation.createDirectFloatBuffer(16); + private static IntBuffer VIEWPORT = GLAllocation.createDirectIntBuffer(16); + private static FloatBuffer POSITION = GLAllocation.createDirectFloatBuffer(4); + + public static boolean useFullPost = true; + public static boolean flashlightInit = false; + public static int shadowFbo; + public static int shadowFboTex; + + public static int height = 0; + public static int width = 0; + + public static int deferredFbo; + public static int deferredColorTex = -1; + //TODO condense into one texture? + public static int deferredPositionTex = -1; + public static int deferredProjCoordTex = -1; + //Actually it might be possible to reconstruct both position and normal data from the depth buffer, which would't require a shader at all + //TODO test this? + public static int deferredNormalTex = -1; + //Only used for full post processing + public static int deferredDepthTex = -1; + + public static float[] inv_ViewProjectionMatrix = new float[16]; + + //Flashlights should all be rendered at the end of the render world for their deferred rendering to work. + //If we're not at the end of render world, add it to a list to be rendered later. + public static boolean renderingFlashlights = false; + //If true, no flashlights should be added to the render list. This prevents entities that add flashlights from adding them more than once when we + //Render them here + private static boolean flashlightLock = false; + //List of future flashlights to render; + private static List flashlightQueue = new ArrayList<>(); + + /** + * + * @param lb + * @param rb + * @param rt + * @param lt + * @return left-bottom-right-top + */ + public static float[] getScreenAreaFromQuad(Vec3d lb, Vec3d rb, Vec3d rt, Vec3d lt){ + FloatBuffer mmatrix = GLAllocation.createDirectFloatBuffer(16); + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, mmatrix); + FloatBuffer pmatrix = GLAllocation.createDirectFloatBuffer(16); + GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, pmatrix); + IntBuffer vport = GLAllocation.createDirectIntBuffer(16); + GL11.glGetInteger(GL11.GL_VIEWPORT, vport); + + FloatBuffer[] points = new FloatBuffer[4]; + FloatBuffer buf0 = GLAllocation.createDirectFloatBuffer(3); + Project.gluProject((float)lb.x, (float)lb.y, (float)lb.z, mmatrix, pmatrix, vport, buf0); + points[0] = buf0; + FloatBuffer buf1 = GLAllocation.createDirectFloatBuffer(3); + Project.gluProject((float)rb.x, (float)rb.y, (float)rb.z, mmatrix, pmatrix, vport, buf1); + points[1] = buf1; + FloatBuffer buf2 = GLAllocation.createDirectFloatBuffer(3); + Project.gluProject((float)rt.x, (float)rt.y, (float)rt.z, mmatrix, pmatrix, vport, buf2); + points[2] = buf2; + FloatBuffer buf3 = GLAllocation.createDirectFloatBuffer(3); + Project.gluProject((float)lt.x, (float)lt.y, (float)lt.z, mmatrix, pmatrix, vport, buf3); + points[3] = buf3; + + float top = buf0.get(1); + float bottom = buf0.get(1); + float left = buf0.get(0); + float right = buf0.get(0); + + for(FloatBuffer buf : points){ + if(buf.get(0) > right){ + right = buf.get(0); + } + if(buf.get(0) < left){ + left = buf.get(0); + } + if(buf.get(1) > top){ + top = buf.get(1); + } + if(buf.get(1) < bottom){ + bottom = buf.get(1); + } + } + //System.out.println(top); + if(bottom < 0) + bottom = 0; + if(top > Minecraft.getMinecraft().displayHeight) + top = Minecraft.getMinecraft().displayHeight; + if(left < 0) + left = 0; + if(right > Minecraft.getMinecraft().displayWidth) + right = Minecraft.getMinecraft().displayWidth; + + if(right <= 0 || top <= 0 || bottom >= Minecraft.getMinecraft().displayHeight || left >= Minecraft.getMinecraft().displayWidth) + return null; + //System.out.println(right); + return new float[]{left, bottom, right, top}; + } + + + public static TextureAtlasSprite getItemTexture(Item item, int meta){ + return getItemTexture(new ItemStack(item, 1, meta)); + } + + public static TextureAtlasSprite getItemTexture(Item item){ + return getItemTexture(item, 0); + } + + public static TextureAtlasSprite getItemTexture(ItemStack item){ + return Minecraft.getMinecraft().getRenderItem().getItemModelWithOverrides(item, null, null).getParticleTexture(); + } + + public static void addVertexWithUV(double x, double y, double z, double u, double v){ + addVertexWithUV(x, y, z, u, v, Tessellator.getInstance()); + } + public static void addVertex(double x, double y, double z){ + Tessellator.getBuffer().pos(x, y, z).endVertex(); + } + + public static void addVertexWithUV(double x, double y, double z, double u, double v, Tessellator tes){ + BufferBuilder buf = tes.getBuffer(); + buf.pos(x, y, z).tex(u, v).endVertex(); + } + public static void startDrawingTexturedQuads(){ + startDrawingTexturedQuads(Tessellator.getInstance()); + } + public static void startDrawingQuads(){ + Tessellator.getBuffer().begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION); + } + public static void startDrawingTexturedQuads(Tessellator tes){ + tes.getBuffer().begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + } + public static void draw(){ + draw(Tessellator.getInstance()); + } + public static void draw(Tessellator tes){ + tes.draw(); + } + + public static void bindTexture(ResourceLocation resource){ + Minecraft.getMinecraft().renderEngine.bindTexture(resource); + } + public static void bindBlockTexture(){ + bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); + } + + //Drillgon200: using GLStateManager for this because it caches color values + public static void setColor(int color) { + + float red = (float) (color >> 16 & 255) / 255.0F; + float green = (float) (color >> 8 & 255) / 255.0F; + float blue = (float) (color & 255) / 255.0F; + GlStateManager.color(red, green, blue, 1.0F); + } + + public static void unpackColor(int color, float[] col){ + float red = (float) (color >> 16 & 255) / 255.0F; + float green = (float) (color >> 8 & 255) / 255.0F; + float blue = (float) (color & 255) / 255.0F; + col[0] = red; + col[1] = green; + col[2] = blue; + } + + public static void resetParticleInterpPos(Entity entityIn, float partialTicks){ + double entPosX = entityIn.lastTickPosX + (entityIn.posX - entityIn.lastTickPosX)*partialTicks; + double entPosY = entityIn.lastTickPosY + (entityIn.posY - entityIn.lastTickPosY)*partialTicks; + double entPosZ = entityIn.lastTickPosZ + (entityIn.posZ - entityIn.lastTickPosZ)*partialTicks; + + Particle.interpPosX = entPosX; + Particle.interpPosY = entPosY; + Particle.interpPosZ = entPosZ; + } + + public static void resetColor(){ + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + } + + public static void startDrawingColored(int i) { + Tessellator.getBuffer().begin(i, DefaultVertexFormats.POSITION_COLOR); + } + + public static void addVertexColor(double x, double y, double z, int red, int green, int blue, int alpha){ + Tessellator.getBuffer().pos(x, y, z).color(red, green, blue, alpha).endVertex();; + } + + public static void addVertexColor(double x, double y, double z, float red, float green, float blue, float alpha){ + Tessellator.getBuffer().pos(x, y, z).color(red, green, blue, alpha).endVertex();; + } + + public static void renderAll(IBakedModel boxcar) { + Tessellator tes = Tessellator.getInstance(); + BufferBuilder buf = tes.getBuffer(); + buf.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_NORMAL); + for(BakedQuad quad : boxcar.getQuads(null, null, 0)){ + buf.addVertexData(quad.getVertexData()); + } + tes.draw(); + } + + public static void renderConeMesh(Vec3d start, Vec3d normal, float height, float radius, int sides){ + float[] vertices = new float[(1+sides)*3]; + vertices[0] = 0; + vertices[1] = 0; + vertices[2] = 0; + + Vec3d vertex = new Vec3d(radius, 0, 0); + for(int i = 0; i < sides; i ++){ + vertex = vertex.rotateYaw((float) (2*Math.PI*(1F/(float)sides))); + vertices[(i+1)*3] = (float) vertex.x; + vertices[(i+1)*3+1] = (float) vertex.y-height; + vertices[(i+1)*3+2] = (float) vertex.z; + } + + GL11.glPushMatrix(); + Vec3d angles = BobMathUtil.getEulerAngles(normal); + GL11.glTranslated(start.x, start.y, start.z); + GL11.glRotated(angles.x+180, 0, 1, 0); + GL11.glRotated(angles.y+180, 1, 0, 0); + + + Tessellator tes = Tessellator.getInstance(); + BufferBuilder buf = tes.getBuffer(); + buf.begin(GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION); + for(int i = 2; i <= sides; i ++){ + buf.pos(0, 0, 0).endVertex(); + buf.pos(vertices[(i-1)*3], vertices[(i-1)*3+1], vertices[(i-1)*3+2]).endVertex(); + buf.pos(vertices[i*3], vertices[i*3+1], vertices[i*3+2]).endVertex(); + } + buf.pos(0, 0, 0).endVertex(); + buf.pos(vertices[sides*3], vertices[sides*3+1], vertices[sides*3+2]).endVertex(); + buf.pos(vertices[1*3], vertices[1*3+1], vertices[1*3+2]).endVertex(); + + for(int i = 1; i < sides-1; i ++){ + buf.pos(vertices[3], vertices[3+1], vertices[3+2]).endVertex(); + buf.pos(vertices[(i+2)*3], vertices[(i+2)*3+1], vertices[(i+2)*3+2]).endVertex(); + buf.pos(vertices[(i+1)*3], vertices[(i+1)*3+1], vertices[(i+1)*3+2]).endVertex(); + } + tes.draw(); + + GL11.glPopMatrix(); + } + + public static void enableBlockVBOs(){ + GlStateManager.glEnableClientState(32884); + OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit); + GlStateManager.glEnableClientState(32888); + OpenGlHelper.setClientActiveTexture(OpenGlHelper.lightmapTexUnit); + GlStateManager.glEnableClientState(32888); + OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit); + GlStateManager.glEnableClientState(32886); + } + + public static void disableBlockVBOs(){ + for (VertexFormatElement vertexformatelement : DefaultVertexFormats.BLOCK.getElements()) + { + VertexFormatElement.EnumUsage vertexformatelement$enumusage = vertexformatelement.getUsage(); + int k1 = vertexformatelement.getIndex(); + + switch (vertexformatelement$enumusage) + { + case POSITION: + GlStateManager.glDisableClientState(32884); + break; + case UV: + OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit + k1); + GlStateManager.glDisableClientState(32888); + OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit); + break; + case COLOR: + GlStateManager.glDisableClientState(32886); + GlStateManager.resetColor(); + } + } + } + + public static void renderChunks(Collection toRender, double posX, double posY, double posZ){ + for(RenderChunk chunk : toRender){ + GL11.glPushMatrix(); + BlockPos chunkPos = chunk.getPosition(); + GL11.glTranslated(chunkPos.getX() - posX, chunkPos.getY() - posY, chunkPos.getZ() - posZ); + chunk.multModelviewMatrix(); + for(int i = 0; i < 3; i ++){ + if(chunk.getCompiledChunk().isLayerEmpty(BlockRenderLayer.values()[i]) || chunk.getVertexBufferByLayer(i) == null) + continue; + if(i == 2){ + Minecraft.getMinecraft().getTextureManager().getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE).setBlurMipmap(false, false); + } + VertexBuffer buf = chunk.getVertexBufferByLayer(i); + buf.bindBuffer(); + GlStateManager.glVertexPointer(3, 5126, 28, 0); + GlStateManager.glColorPointer(4, 5121, 28, 12); + GlStateManager.glTexCoordPointer(2, 5126, 28, 16); + OpenGlHelper.setClientActiveTexture(OpenGlHelper.lightmapTexUnit); + GlStateManager.glTexCoordPointer(2, 5122, 28, 24); + OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit); + buf.drawArrays(GL11.GL_QUADS); + if(i == 2){ + Minecraft.getMinecraft().getTextureManager().getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE).restoreLastBlurMipmap(); + } + } + GL11.glPopMatrix(); + } + } + + @Deprecated + private static void sendFlashlightUniforms(int shader, Vec3d playerPos, Vec3d pos, Vec3d normal, float height, float degrees, ResourceLocation flashlight_tex){ + pos = pos.subtract(playerPos); + pos = BobMathUtil.viewFromLocal(new Vector4f((float)pos.x, (float)pos.y, (float)pos.z, 1))[0]; + normal = BobMathUtil.viewFromLocal(new Vector4f((float)normal.x, (float)normal.y, (float)normal.z, 0))[0]; + GL20.glUniform1f(GL20.glGetUniformLocation(shader, "angle"), (float) Math.cos(Math.toRadians(degrees))); + GL20.glUniform1f(GL20.glGetUniformLocation(shader, "height"), height); + GL20.glUniform3f(GL20.glGetUniformLocation(shader, "pos"), (float)pos.x, (float)pos.y, (float)pos.z); + GL20.glUniform3f(GL20.glGetUniformLocation(shader, "direction"), (float)normal.x, (float)normal.y, (float)normal.z); + //GL20.glUniform2f(GL20.glGetUniformLocation(shader, "screenSize"), Minecraft.getMinecraft().displayWidth, Minecraft.getMinecraft().displayHeight); + + GlStateManager.setActiveTexture(GL13.GL_TEXTURE3); + GlStateManager.bindTexture(shadowFboTex); + GL20.glUniform1i(GL20.glGetUniformLocation(shader, "shadowTex"), 3); + GlStateManager.setActiveTexture(GL13.GL_TEXTURE4); + bindTexture(flashlight_tex); + GL20.glUniform1i(GL20.glGetUniformLocation(shader, "flashlightTex"), 4); + GlStateManager.setActiveTexture(GL13.GL_TEXTURE0); + } + + @Deprecated + private static void sendFlashLightPostUniforms(int shader, Vec3d playerPos, Vec3d pos, float height, float brightness, float[] shadowView, float[] shadowProjection, ResourceLocation flashlight_tex){ + pos = pos.subtract(playerPos); + //pos = BobMathUtil.viewFromLocal(new Vector4f((float)pos.x, (float)pos.y, (float)pos.z, 1))[0]; + GL20.glUniform1f(GL20.glGetUniformLocation(shader, "height"), height); + GL20.glUniform3f(GL20.glGetUniformLocation(shader, "fs_Pos"), (float)pos.x, (float)pos.y, (float)pos.z); + GL20.glUniform2f(GL20.glGetUniformLocation(shader, "zNearFar"), 0.05F, Minecraft.getMinecraft().gameSettings.renderDistanceChunks * 16 * MathHelper.SQRT_2); + GL20.glUniform1f(GL20.glGetUniformLocation(shader, "eyeHeight"), Minecraft.getMinecraft().player.getEyeHeight()); + GL20.glUniform1f(GL20.glGetUniformLocation(shader, "brightness"), brightness); + + GlStateManager.setActiveTexture(GL13.GL_TEXTURE3); + GlStateManager.bindTexture(Minecraft.getMinecraft().getFramebuffer().framebufferTexture); + GL20.glUniform1i(GL20.glGetUniformLocation(shader, "mc_tex"), 3); + GlStateManager.setActiveTexture(GL13.GL_TEXTURE4); + GlStateManager.bindTexture(deferredDepthTex); + GL20.glUniform1i(GL20.glGetUniformLocation(shader, "depthBuffer"), 4); + GlStateManager.setActiveTexture(GL13.GL_TEXTURE5); + bindTexture(flashlight_tex); + GL20.glUniform1i(GL20.glGetUniformLocation(shader, "flashlightTex"), 5); + GlStateManager.setActiveTexture(GL13.GL_TEXTURE6); + GlStateManager.bindTexture(shadowFboTex); + GL20.glUniform1i(GL20.glGetUniformLocation(shader, "shadowTex"), 6); + GlStateManager.setActiveTexture(GL13.GL_TEXTURE0); + + Matrix4f view = new Matrix4f(); + Matrix4f proj = new Matrix4f(); + + AvatarClientProxy.AUX_GL_BUFFER.put(shadowView); + AvatarClientProxy.AUX_GL_BUFFER2.put(shadowProjection); + AvatarClientProxy.AUX_GL_BUFFER.rewind(); + AvatarClientProxy.AUX_GL_BUFFER2.rewind(); + view.load(AvatarClientProxy.AUX_GL_BUFFER); + proj.load(AvatarClientProxy.AUX_GL_BUFFER2); + AvatarClientProxy.AUX_GL_BUFFER.rewind(); + AvatarClientProxy.AUX_GL_BUFFER2.rewind(); + Matrix4f.mul(proj, view, view); + view.store(AvatarClientProxy.AUX_GL_BUFFER); + AvatarClientProxy.AUX_GL_BUFFER.rewind(); + GL20.glUniformMatrix4(GL20.glGetUniformLocation(shader, "flashlight_ViewProjectionMatrix"), false, AvatarClientProxy.AUX_GL_BUFFER); + + AvatarClientProxy.AUX_GL_BUFFER.put(inv_ViewProjectionMatrix); + AvatarClientProxy.AUX_GL_BUFFER.rewind(); + GL20.glUniformMatrix4(GL20.glGetUniformLocation(shader, "inv_ViewProjectionMatrix"), false, AvatarClientProxy.AUX_GL_BUFFER); + + } + + @SuppressWarnings("deprecation") + public static RenderChunk getRenderChunk(BlockPos pos){ + try { + if(r_viewFrustum == null) + r_viewFrustum = ReflectionHelper.findField(RenderGlobal.class, "viewFrustum", "field_175008_n"); + if(r_getRenderChunk == null) + r_getRenderChunk = ReflectionHelper.findMethod(ViewFrustum.class, "getRenderChunk", "func_178161_a", BlockPos.class); + ViewFrustum v = (ViewFrustum) r_viewFrustum.get(Minecraft.getMinecraft().renderGlobal); + RenderChunk r = (RenderChunk) r_getRenderChunk.invoke(v, pos); + return r; + } catch(IllegalArgumentException | IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + return null; + } + + public static void renderFullscreenTriangle(){ + renderFullscreenTriangle(false); + } + + public static void renderFullscreenTriangle(boolean alpha){ + GlStateManager.colorMask(true, true, true, alpha); + GlStateManager.disableDepth(); + GlStateManager.depthMask(false); + GlStateManager.enableTexture2D(); + GlStateManager.disableLighting(); + GlStateManager.disableAlpha(); + + GlStateManager.enableColorMaterial(); + + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + bufferbuilder.begin(GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION_TEX); + bufferbuilder.pos(-1, -1, 0.0D).tex(0, 0).endVertex(); + bufferbuilder.pos(3, -1, 0.0D).tex(2, 0).endVertex(); + bufferbuilder.pos(-1, 3, 0.0D).tex(0, 2).endVertex(); + tessellator.draw(); + GlStateManager.depthMask(true); + GlStateManager.enableDepth(); + GlStateManager.enableAlpha(); + GlStateManager.enableLighting(); + GlStateManager.colorMask(true, true, true, true); + } + + public static float[] project(float x, float y, float z){ + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, MODELVIEW); + GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, PROJECTION); + GL11.glGetInteger(GL11.GL_VIEWPORT, VIEWPORT); + + Project.gluProject(x, y, z, MODELVIEW, PROJECTION, VIEWPORT, POSITION); + return new float[]{POSITION.get(0), POSITION.get(1), POSITION.get(2)}; + } + + public static float[] unproject(float x, float y, float z){ + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, MODELVIEW); + GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, PROJECTION); + GL11.glGetInteger(GL11.GL_VIEWPORT, VIEWPORT); + + Project.gluUnProject(x, y, z, MODELVIEW, PROJECTION, VIEWPORT, POSITION); + return new float[]{POSITION.get(0), POSITION.get(1), POSITION.get(2)}; + } + + public static boolean intersects2DBox(float x, float y, float[] box){ + return x > box[0] && x < box[2] && y > box[1] && y < box[3]; + } + + public static boolean boxesOverlap(float[] box1, float[] box2){ + return box1[0] < box2[2] && box1[2] > box2[0] && box1[1] < box2[3] && box1[3] > box2[1]; + } + + public static boolean boxContainsOther(float[] box, float[] other){ + return box[0] <= other[0] && box[1] <= other[1] && box[2] >= other[2] && box[3] >= other[3]; + } + + public static float[] getBoxCenter(float[] box){ + return new float[]{box[0]+(box[2]-box[0])*0.5F, box[1]+(box[3]-box[1])*0.5F}; + } + +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/TesselatorVertexState.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/TesselatorVertexState.java new file mode 100644 index 0000000000..dc0f78a124 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/TesselatorVertexState.java @@ -0,0 +1,63 @@ +package com.crowsofwar.avatar.client.render.lightning.render; + +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class TesselatorVertexState +{ + private int[] rawBuffer; + private int rawBufferIndex; + private int vertexCount; + private boolean hasTexture; + private boolean hasBrightness; + private boolean hasNormals; + private boolean hasColor; + private static final String __OBFID = "CL_00000961"; + + public TesselatorVertexState(int[] p_i45079_1_, int p_i45079_2_, int p_i45079_3_, boolean p_i45079_4_, boolean p_i45079_5_, boolean p_i45079_6_, boolean p_i45079_7_) + { + this.rawBuffer = p_i45079_1_; + this.rawBufferIndex = p_i45079_2_; + this.vertexCount = p_i45079_3_; + this.hasTexture = p_i45079_4_; + this.hasBrightness = p_i45079_5_; + this.hasNormals = p_i45079_6_; + this.hasColor = p_i45079_7_; + } + + public int[] getRawBuffer() + { + return this.rawBuffer; + } + + public int getRawBufferIndex() + { + return this.rawBufferIndex; + } + + public int getVertexCount() + { + return this.vertexCount; + } + + public boolean getHasTexture() + { + return this.hasTexture; + } + + public boolean getHasBrightness() + { + return this.hasBrightness; + } + + public boolean getHasNormals() + { + return this.hasNormals; + } + + public boolean getHasColor() + { + return this.hasColor; + } +} \ No newline at end of file diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/Tessellator.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/Tessellator.java new file mode 100644 index 0000000000..4271dbf4b3 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/Tessellator.java @@ -0,0 +1,546 @@ +package com.crowsofwar.avatar.client.render.lightning.render; + +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GLAllocation; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import org.lwjgl.opengl.GL11; + +import java.nio.*; +import java.util.PriorityQueue; + +@SideOnly(Side.CLIENT) +public class Tessellator +{ + private static int nativeBufferSize = 0x200000; + private static int trivertsInBuffer = (nativeBufferSize / 48) * 6; + public static boolean renderingWorldRenderer = false; + public boolean defaultTexture = false; + private int rawBufferSize = 0; + public int textureID = 0; + + /** The byte buffer used for GL allocation. */ + private static ByteBuffer byteBuffer = GLAllocation.createDirectByteBuffer(nativeBufferSize * 4); + /** The same memory as byteBuffer, but referenced as an integer buffer. */ + private static IntBuffer intBuffer = byteBuffer.asIntBuffer(); + /** The same memory as byteBuffer, but referenced as an float buffer. */ + private static FloatBuffer floatBuffer = byteBuffer.asFloatBuffer(); + /** The same memory as byteBuffer, but referenced as an short buffer. */ + private static ShortBuffer shortBuffer = byteBuffer.asShortBuffer(); + /** Raw integer array. */ + private int[] rawBuffer; + /** The number of vertices to be drawn in the next draw call. Reset to 0 between draw calls. */ + private int vertexCount; + /** The first coordinate to be used for the texture. */ + private double textureU; + /** The second coordinate to be used for the texture. */ + private double textureV; + private int brightness; + /** The color (RGBA) value to be used for the following draw call. */ + private int color; + /** Whether the current draw object for this tessellator has color values. */ + public boolean hasColor; + /** Whether the current draw object for this tessellator has texture coordinates. */ + private boolean hasTexture; + private boolean hasBrightness; + /** Whether the current draw object for this tessellator has normal values. */ + public boolean hasNormals; + /** The index into the raw buffer to be used for the next data. */ + private int rawBufferIndex; + /** + * The number of vertices manually added to the given draw call. This differs from vertexCount because it adds extra + * vertices when converting quads to triangles. + */ + private int addedVertices; + /** Disables all color information for the following draw call. */ + private boolean isColorDisabled; + /** The draw mode currently being used by the tessellator. */ + private int drawMode; + /** An offset to be applied along the x-axis for all vertices in this draw call. */ + private double xOffset; + /** An offset to be applied along the y-axis for all vertices in this draw call. */ + private double yOffset; + /** An offset to be applied along the z-axis for all vertices in this draw call. */ + private double zOffset; + /** The normal to be applied to the face being drawn. */ + private int normal; + /** The static instance of the Tessellator. */ + public static final Tessellator instance = new Tessellator(2097152); + /** Whether this tessellator is currently in draw mode. */ + private boolean isDrawing; + /** The size of the buffers used (in integers). */ + private int bufferSize; + private static final String __OBFID = "CL_00000960"; + + private Tessellator(int p_i1250_1_) + { + } + + public Tessellator() + { + } + + static + { + instance.defaultTexture = true; + } + + public static Tessellator getInstance() { + return Tessellator.instance; + } + + public static BufferBuilder getBuffer() { + return net.minecraft.client.renderer.Tessellator.getInstance().getBuffer(); + } + + /** + * Draws the data set up in this tessellator and resets the state to prepare for new drawing. + */ + public int draw() + { + hasColor = false; + hasNormals = false; + this.xOffset = 0; + this.yOffset = 0; + this.zOffset = 0; + net.minecraft.client.renderer.Tessellator.getInstance().draw(); + return 1; + /* if (!this.isDrawing) + { + throw new IllegalStateException("Not tesselating!"); + } + else + { + this.isDrawing = false; + + int offs = 0; + while (offs < vertexCount) + { + int vtc = Math.min(vertexCount - offs, nativeBufferSize >> 5); + this.intBuffer.clear(); + this.intBuffer.put(this.rawBuffer, offs * 8, vtc * 8); + this.byteBuffer.position(0); + this.byteBuffer.limit(vtc * 32); + offs += vtc; + + if (this.hasTexture) + { + this.floatBuffer.position(3); + GL11.glTexCoordPointer(2, 32, this.floatBuffer); + GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY); + } + + if (this.hasBrightness) + { + OpenGlHelper.setClientActiveTexture(OpenGlHelper.lightmapTexUnit); + this.shortBuffer.position(14); + GL11.glTexCoordPointer(2, 32, this.shortBuffer); + GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY); + OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit); + } + + if (this.hasColor) + { + this.byteBuffer.position(20); + GL11.glColorPointer(4, true, 32, this.byteBuffer); + GL11.glEnableClientState(GL11.GL_COLOR_ARRAY); + } + + if (this.hasNormals) + { + this.byteBuffer.position(24); + GL11.glNormalPointer(32, this.byteBuffer); + GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY); + } + + this.floatBuffer.position(0); + GL11.glVertexPointer(3, 32, this.floatBuffer); + GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY); + GL11.glDrawArrays(this.drawMode, 0, vtc); + GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY); + + if (this.hasTexture) + { + GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY); + } + + if (this.hasBrightness) + { + OpenGlHelper.setClientActiveTexture(OpenGlHelper.lightmapTexUnit); + GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY); + OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit); + } + + if (this.hasColor) + { + GL11.glDisableClientState(GL11.GL_COLOR_ARRAY); + } + + if (this.hasNormals) + { + GL11.glDisableClientState(GL11.GL_NORMAL_ARRAY); + } + } + + if (rawBufferSize > 0x20000 && rawBufferIndex < (rawBufferSize << 3)) + { + rawBufferSize = 0x10000; + rawBuffer = new int[rawBufferSize]; + } + + int i = this.rawBufferIndex * 4; + this.reset(); + return i; + }*/ + } + + public TesselatorVertexState getVertexState(float p_147564_1_, float p_147564_2_, float p_147564_3_) + { + int[] aint = new int[this.rawBufferIndex]; + PriorityQueue priorityqueue = new PriorityQueue(this.rawBufferIndex, new QuadComparator(this.rawBuffer, p_147564_1_ + (float)this.xOffset, p_147564_2_ + (float)this.yOffset, p_147564_3_ + (float)this.zOffset)); + byte b0 = 32; + int i; + + for (i = 0; i < this.rawBufferIndex; i += b0) + { + priorityqueue.add(Integer.valueOf(i)); + } + + for (i = 0; !priorityqueue.isEmpty(); i += b0) + { + int j = ((Integer)priorityqueue.remove()).intValue(); + + for (int k = 0; k < b0; ++k) + { + aint[i + k] = this.rawBuffer[j + k]; + } + } + + System.arraycopy(aint, 0, this.rawBuffer, 0, aint.length); + return new TesselatorVertexState(aint, this.rawBufferIndex, this.vertexCount, this.hasTexture, this.hasBrightness, this.hasNormals, this.hasColor); + } + + public void setVertexState(TesselatorVertexState p_147565_1_) + { + while (p_147565_1_.getRawBuffer().length > rawBufferSize && rawBufferSize > 0) + { + rawBufferSize <<= 1; + } + if (rawBufferSize > rawBuffer.length) + { + rawBuffer = new int[rawBufferSize]; + } + System.arraycopy(p_147565_1_.getRawBuffer(), 0, this.rawBuffer, 0, p_147565_1_.getRawBuffer().length); + this.rawBufferIndex = p_147565_1_.getRawBufferIndex(); + this.vertexCount = p_147565_1_.getVertexCount(); + this.hasTexture = p_147565_1_.getHasTexture(); + this.hasBrightness = p_147565_1_.getHasBrightness(); + this.hasColor = p_147565_1_.getHasColor(); + this.hasNormals = p_147565_1_.getHasNormals(); + } + + /** + * Clears the tessellator state in preparation for new drawing. + */ + private void reset() + { + this.vertexCount = 0; + this.byteBuffer.clear(); + this.rawBufferIndex = 0; + this.addedVertices = 0; + } + + /** + * Sets draw mode in the tessellator to draw quads. + */ + public void startDrawingQuads() + { + this.startDrawing(7, DefaultVertexFormats.POSITION_TEX_NORMAL); + } + + public void startDrawingQuadsColor(){ + startDrawing(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR_NORMAL); + } + + public void startDrawing(int mode){ + startDrawing(mode, DefaultVertexFormats.POSITION_TEX_NORMAL); + } + + /** + * Resets tessellator state and prepares for drawing (with the specified draw mode). + */ + public void startDrawing(int glMode, VertexFormat format) + { + /* if (this.isDrawing) + { + throw new IllegalStateException("Already tesselating!"); + } + else + { + this.isDrawing = true; + this.reset(); + this.drawMode = p_78371_1_; + this.hasNormals = false; + this.hasColor = false; + this.hasTexture = false; + this.hasBrightness = false; + this.isColorDisabled = false; + }*/ + net.minecraft.client.renderer.Tessellator.getInstance().getBuffer().begin(glMode, format); + } + + /** + * Sets the texture coordinates. + */ + public void setTextureUV(double p_78385_1_, double p_78385_3_) + { + this.hasTexture = true; + this.textureU = p_78385_1_; + this.textureV = p_78385_3_; + } + + public void setBrightness(int p_78380_1_) + { + this.hasBrightness = true; + this.brightness = p_78380_1_; + } + + /** + * Sets the RGB values as specified, converting from floats between 0 and 1 to integers from 0-255. + */ + public void setColorOpaque_F(float p_78386_1_, float p_78386_2_, float p_78386_3_) + { + this.setColorOpaque((int)(p_78386_1_ * 255.0F), (int)(p_78386_2_ * 255.0F), (int)(p_78386_3_ * 255.0F)); + } + + /** + * Sets the RGBA values for the color, converting from floats between 0 and 1 to integers from 0-255. + */ + public void setColorRGBA_F(float p_78369_1_, float p_78369_2_, float p_78369_3_, float p_78369_4_) + { + this.setColorRGBA((int)(p_78369_1_ * 255.0F), (int)(p_78369_2_ * 255.0F), (int)(p_78369_3_ * 255.0F), (int)(p_78369_4_ * 255.0F)); + } + + /** + * Sets the RGB values as specified, and sets alpha to opaque. + */ + public void setColorOpaque(int p_78376_1_, int p_78376_2_, int p_78376_3_) + { + this.setColorRGBA(p_78376_1_, p_78376_2_, p_78376_3_, 255); + } + + private int r, g, b, a; + + /** + * Sets the RGBA values for the color. Also clamps them to 0-255. + */ + public void setColorRGBA(int p_78370_1_, int p_78370_2_, int p_78370_3_, int p_78370_4_) + { + if (!this.isColorDisabled) + { + if (p_78370_1_ > 255) + { + p_78370_1_ = 255; + } + + if (p_78370_2_ > 255) + { + p_78370_2_ = 255; + } + + if (p_78370_3_ > 255) + { + p_78370_3_ = 255; + } + + if (p_78370_4_ > 255) + { + p_78370_4_ = 255; + } + + if (p_78370_1_ < 0) + { + p_78370_1_ = 0; + } + + if (p_78370_2_ < 0) + { + p_78370_2_ = 0; + } + + if (p_78370_3_ < 0) + { + p_78370_3_ = 0; + } + + if (p_78370_4_ < 0) + { + p_78370_4_ = 0; + } + + this.hasColor = true; + + r = p_78370_1_; + g = p_78370_2_; + b = p_78370_3_; + a = p_78370_4_; + + if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) + { + this.color = p_78370_4_ << 24 | p_78370_3_ << 16 | p_78370_2_ << 8 | p_78370_1_; + } + else + { + this.color = p_78370_1_ << 24 | p_78370_2_ << 16 | p_78370_3_ << 8 | p_78370_4_; + } + } + } + + public void func_154352_a(byte p_154352_1_, byte p_154352_2_, byte p_154352_3_) + { + this.setColorOpaque(p_154352_1_ & 255, p_154352_2_ & 255, p_154352_3_ & 255); + } + + /** + * Adds a vertex specifying both x,y,z and the texture u,v for it. + */ + public void addVertexWithUV(double x, double y, double z, double u, double v) + { + BufferBuilder buf = net.minecraft.client.renderer.Tessellator.getInstance().getBuffer(); + buf.pos(x+xOffset, y+yOffset, z+zOffset).tex(u, v); + if(hasColor) + buf.color(r, g, b, a); + if(hasNormals) + buf.normal(normalTestX, normalTestY, normalTestZ); + buf.endVertex(); + /*this.setTextureUV(p_78374_7_, p_78374_9_); + this.addVertex(p_78374_1_, p_78374_3_, p_78374_5_);*/ + } + + /** + * Adds a vertex with the specified x,y,z to the current draw call. It will trigger a draw() if the buffer gets + * full. + */ + public void addVertex(double x, double y, double z) + { + BufferBuilder buf = net.minecraft.client.renderer.Tessellator.getInstance().getBuffer(); + buf.pos(x+xOffset, y+yOffset, z+zOffset); + if(hasColor){ + buf.color(r, g, b, a); + //System.out.println(r + " " + g + " " + b + " " + a); + } + if(hasNormals) + buf.normal(normalTestX, normalTestY, normalTestZ); + buf.endVertex(); + /* if (rawBufferIndex >= rawBufferSize - 32) + { + if (rawBufferSize == 0) + { + rawBufferSize = 0x10000; + rawBuffer = new int[rawBufferSize]; + } + else + { + rawBufferSize *= 2; + rawBuffer = Arrays.copyOf(rawBuffer, rawBufferSize); + } + } + ++this.addedVertices; + + if (this.hasTexture) + { + this.rawBuffer[this.rawBufferIndex + 3] = Float.floatToRawIntBits((float)this.textureU); + this.rawBuffer[this.rawBufferIndex + 4] = Float.floatToRawIntBits((float)this.textureV); + } + + if (this.hasBrightness) + { + this.rawBuffer[this.rawBufferIndex + 7] = this.brightness; + } + + if (this.hasColor) + { + this.rawBuffer[this.rawBufferIndex + 5] = this.color; + } + + if (this.hasNormals) + { + this.rawBuffer[this.rawBufferIndex + 6] = this.normal; + } + + this.rawBuffer[this.rawBufferIndex + 0] = Float.floatToRawIntBits((float)(p_78377_1_ + this.xOffset)); + this.rawBuffer[this.rawBufferIndex + 1] = Float.floatToRawIntBits((float)(p_78377_3_ + this.yOffset)); + this.rawBuffer[this.rawBufferIndex + 2] = Float.floatToRawIntBits((float)(p_78377_5_ + this.zOffset)); + this.rawBufferIndex += 8; + ++this.vertexCount;*/ + } + + /** + * Sets the color to the given opaque value (stored as byte values packed in an integer). + */ + public void setColorOpaque_I(int p_78378_1_) + { + int j = p_78378_1_ >> 16 & 255; + int k = p_78378_1_ >> 8 & 255; + int l = p_78378_1_ & 255; + this.setColorOpaque(j, k, l); + } + + /** + * Sets the color to the given color (packed as bytes in integer) and alpha values. + */ + public void setColorRGBA_I(int p_78384_1_, int p_78384_2_) + { + int k = p_78384_1_ >> 16 & 255; + int l = p_78384_1_ >> 8 & 255; + int i1 = p_78384_1_ & 255; + this.setColorRGBA(k, l, i1, p_78384_2_); + } + + /** + * Disables colors for the current draw call. + */ + public void disableColor() + { + this.isColorDisabled = true; + } + + private float normalTestX, normalTestY, normalTestZ; + + /** + * Sets the normal for the current draw call. + */ + public void setNormal(float x, float y, float z) + { + this.hasNormals = true; + // byte b0 = (byte)((int)(p_78375_1_ * 127.0F)); + // byte b1 = (byte)((int)(p_78375_2_ * 127.0F)); + // byte b2 = (byte)((int)(p_78375_3_ * 127.0F)); + // this.normal = b0 & 255 | (b1 & 255) << 8 | (b2 & 255) << 16; + normalTestX = x; + normalTestY = y; + normalTestZ = z; + } + + /** + * Sets the translation for all vertices in the current draw call. + */ + public void setTranslation(double p_78373_1_, double p_78373_3_, double p_78373_5_) + { + this.xOffset = p_78373_1_; + this.yOffset = p_78373_3_; + this.zOffset = p_78373_5_; + } + + /** + * Offsets the translation for all vertices in the current draw call. + */ + public void addTranslation(float p_78372_1_, float p_78372_2_, float p_78372_3_) + { + this.xOffset += (double)p_78372_1_; + this.yOffset += (double)p_78372_2_; + this.zOffset += (double)p_78372_3_; + } +} \ No newline at end of file diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/TextureCoordinate.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/TextureCoordinate.java new file mode 100644 index 0000000000..dd7227c1fd --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/TextureCoordinate.java @@ -0,0 +1,18 @@ +package com.crowsofwar.avatar.client.render.lightning.render; + +public class TextureCoordinate +{ + public float u, v, w; + + public TextureCoordinate(float u, float v) + { + this(u, v, 0F); + } + + public TextureCoordinate(float u, float v, float w) + { + this.u = u; + this.v = v; + this.w = w; + } +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/TrailRenderer2.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/TrailRenderer2.java new file mode 100644 index 0000000000..311ca6708c --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/TrailRenderer2.java @@ -0,0 +1,169 @@ +package com.crowsofwar.avatar.client.render.lightning.render; + +import java.nio.ByteBuffer; +import java.util.List; + +import javax.annotation.Nullable; + +import org.lwjgl.opengl.GL11; + +import net.minecraft.client.renderer.GLAllocation; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; + +public class TrailRenderer2 { + + public static final int BYTES_PER_VERTEX = 3*4 + 2*2 + 4; + + public static ByteBuffer aux_buf = GLAllocation.createDirectByteBuffer(512); + public static int array_buf; + public static int element_buf; + public static int vao; + public static int currentPointCount; + private static boolean init = false; + + public static float[] color = new float[]{1, 1, 1, 1}; + + public static void init(){ + array_buf = GLCompat.genBuffers(); + element_buf = GLCompat.genBuffers(); + vao = GLCompat.genVertexArrays(); + GLCompat.bindVertexArray(vao); + GLCompat.bindBuffer(GLCompat.GL_ARRAY_BUFFER, array_buf); + GLCompat.bindBuffer(GLCompat.GL_ELEMENT_ARRAY_BUFFER, element_buf); + //pos + GLCompat.vertexAttribPointer(0, 3, GL11.GL_FLOAT, false, BYTES_PER_VERTEX, 0); + GLCompat.enableVertexAttribArray(0); + //tex + GLCompat.vertexAttribPointer(1, 2, GL11.GL_UNSIGNED_SHORT, true, BYTES_PER_VERTEX, 12); + GLCompat.enableVertexAttribArray(1); + //color + GLCompat.vertexAttribPointer(2, 4, GL11.GL_UNSIGNED_BYTE, true, BYTES_PER_VERTEX, 16); + GLCompat.enableVertexAttribArray(2); + + GLCompat.bindVertexArray(0); + GLCompat.bindBuffer(GLCompat.GL_ARRAY_BUFFER, 0); + GLCompat.bindBuffer(GLCompat.GL_ELEMENT_ARRAY_BUFFER, 0); + } + + public static void draw(Vec3d playerPos, List points, float scale){ + draw(playerPos, points, scale, false, false, null); + } + + public static void draw(Vec3d playerPos, List points, float scale, boolean fadeEnd, boolean fadeEnd2, @Nullable IColorGetter c){ + generateAndBindVao(playerPos, points, scale, fadeEnd, fadeEnd2, c); + drawGeneratedVao(); + unbindVao(); + } + + public static void drawGeneratedVao(){ + GL11.glDrawElements(GL11.GL_TRIANGLES, (currentPointCount-1)*12, GL11.GL_UNSIGNED_INT, 0); + } + + public static void generateAndBindVao(Vec3d playerPos, List points, float scale, boolean fadeEnd, boolean fadeEnd2, @Nullable IColorGetter c){ + if(!init){ + init = true; + init(); + } + currentPointCount = points.size(); + int size = BYTES_PER_VERTEX * (points.size()*3+2); + if(size > aux_buf.capacity()){ + aux_buf = GLAllocation.createDirectByteBuffer(size); + } + Vec3d first = points.get(0); + Vec3d cross = points.get(1).subtract(first).crossProduct(playerPos.subtract(first)).normalize().scale(scale * (fadeEnd ? 0.1F : 1)); + if(c != null){ + color = c.color(0); + } else { + color = new float[]{1, 1, 1, 1}; + } + putVertex(first.add(cross), 0F, 1F); + putVertex(first.add(cross.scale(-1)), 0F, 0F); + for(int i = 1; i < points.size(); i ++){ + Vec3d last = points.get(i-1); + Vec3d current = points.get(i); + Vec3d next = points.get(i); + if(i < points.size()-1){ + next = points.get(i+1); + } + Vec3d toNext = points.get(i).subtract(last); + Vec3d tangent = next.subtract(last); + + float iN = (float)(i)/(float)(points.size()-1); + float bruh = 1-MathHelper.clamp((iN-0.8F)*5, 0, 1); + if(fadeEnd) + bruh *= MathHelper.clamp(iN*5, 0, 1); + if(!fadeEnd2) + bruh = 1; + cross = tangent.crossProduct(playerPos.subtract(last)).normalize().scale(scale*Math.max(bruh, 0.1)); + float uMiddle = (float)(i-0.5F)/(float)(points.size()-1); + if(c != null){ + color = c.color(uMiddle); + } + putVertex(last.add(toNext.scale(0.5)), uMiddle, 0.5F); + if(c != null){ + color = c.color(iN); + } + putVertex(current.add(cross), iN, 1F); + putVertex(current.add(cross.scale(-1)), iN, 0F); + } + GLCompat.bindVertexArray(vao); + GLCompat.bindBuffer(GLCompat.GL_ARRAY_BUFFER, array_buf); + aux_buf.rewind(); + GLCompat.bufferData(GLCompat.GL_ARRAY_BUFFER, aux_buf, GLCompat.GL_DYNAMIC_DRAW); + + for(int i = 0; i < points.size()-1; i ++){ + int offset = i*3; + aux_buf.putInt(0+offset); + aux_buf.putInt(2+offset); + aux_buf.putInt(1+offset); + + aux_buf.putInt(0+offset); + aux_buf.putInt(3+offset); + aux_buf.putInt(2+offset); + + aux_buf.putInt(2+offset); + aux_buf.putInt(3+offset); + aux_buf.putInt(4+offset); + + aux_buf.putInt(2+offset); + aux_buf.putInt(4+offset); + aux_buf.putInt(1+offset); + } + + GLCompat.bindBuffer(GLCompat.GL_ELEMENT_ARRAY_BUFFER, element_buf); + aux_buf.rewind(); + GLCompat.bufferData(GLCompat.GL_ELEMENT_ARRAY_BUFFER, aux_buf, GLCompat.GL_DYNAMIC_DRAW); + GL11.glVertexPointer(3, GL11.GL_FLOAT, BYTES_PER_VERTEX, 0); + GL11.glTexCoordPointer(2, GL11.GL_SHORT, BYTES_PER_VERTEX, 12); + GL11.glColorPointer(4, GL11.GL_UNSIGNED_BYTE, BYTES_PER_VERTEX, 16); + GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY); + GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY); + GL11.glEnableClientState(GL11.GL_COLOR_ARRAY); + } + + public static void unbindVao(){ + GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY); + GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY); + GL11.glDisableClientState(GL11.GL_COLOR_ARRAY); + GLCompat.bindVertexArray(0); + GLCompat.bindBuffer(GLCompat.GL_ARRAY_BUFFER, 0); + GLCompat.bindBuffer(GLCompat.GL_ELEMENT_ARRAY_BUFFER, 0); + } + + private static void putVertex(Vec3d pos, float texU, float texV){ + aux_buf.putFloat((float) pos.x); + aux_buf.putFloat((float) pos.y); + aux_buf.putFloat((float) pos.z); + aux_buf.putShort((short)(texU*65535)); + aux_buf.putShort((short)(texV*65535)); + aux_buf.put((byte)(color[0]*255)); + aux_buf.put((byte)(color[1]*255)); + aux_buf.put((byte)(color[2]*255)); + aux_buf.put((byte)(color[3]*255)); + } + + public static interface IColorGetter { + public float[] color(float position); + } +} \ No newline at end of file diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/Vbo.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/Vbo.java new file mode 100644 index 0000000000..5950010da7 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/Vbo.java @@ -0,0 +1,113 @@ +package com.crowsofwar.avatar.client.render.lightning.render; + +import net.minecraft.client.renderer.GLAllocation; +import org.lwjgl.opengl.GL11; + +import java.nio.ByteBuffer; + +public class Vbo { + + //Pos, tex, normal, color + public static final int BYTES_PER_VERTEX = 3*4 + 2*4 + 3 + 4; + + int drawMode; + int numVertices; + int vboId; + + public Vbo(int vboId, int drawMode, int numVertices) { + this.vboId = vboId; + this.drawMode = drawMode; + this.numVertices = numVertices; + } + + private void preDraw(){ + GL11.glVertexPointer(3, GL11.GL_FLOAT, BYTES_PER_VERTEX, 0); + GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY); + GL11.glTexCoordPointer(2, GL11.GL_FLOAT, BYTES_PER_VERTEX, 12); + GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY); + GL11.glNormalPointer(GL11.GL_BYTE, BYTES_PER_VERTEX, 20); + GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY); + GL11.glColorPointer(4, GL11.GL_UNSIGNED_BYTE, BYTES_PER_VERTEX, 23); + GL11.glEnableClientState(GL11.GL_COLOR_ARRAY); + } + + public void draw(){ + GLCompat.bindBuffer(GLCompat.GL_ARRAY_BUFFER, vboId); + preDraw(); + GL11.glDrawArrays(drawMode, 0, numVertices); + postDraw(); + GLCompat.bindBuffer(GLCompat.GL_ARRAY_BUFFER, 0); + } + + private void postDraw(){ + GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY); + GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY); + GL11.glDisableClientState(GL11.GL_NORMAL_ARRAY); + GL11.glDisableClientState(GL11.GL_COLOR_ARRAY); + } + + public static Vbo setupTestVbo(){ + Vertex bottomLeft = new Vertex(-0.5F, -0.5F, 0F, 0F, 0F, 0F, 0F, 1F, 1F, 1F, 1F, 1F); + Vertex bottomRight = new Vertex(0.5F, -0.5F, 0F, 1F, 0F, 0F, 0F, 1F, 1F, 1F, 1F, 1F); + Vertex topLeft = new Vertex(-0.5F, 0.5F, 0F, 0F, 1F, 0F, 0F, 1F, 1F, 1F, 1F, 1F); + Vertex topRight = new Vertex(0.5F, 0.5F, 0F, 1F, 1F, 0F, 0F, 1F, 1F, 1F, 1F, 1F); + Vertex[] vertices = new Vertex[]{bottomLeft, bottomRight, topRight, topLeft}; + + + int vboId = GLCompat.genBuffers(); + ByteBuffer data = GLAllocation.createDirectByteBuffer(vertices.length*BYTES_PER_VERTEX); + for(Vertex v : vertices){ + data.putFloat(v.x); + data.putFloat(v.y); + data.putFloat(v.z); + data.putFloat(v.u); + data.putFloat(v.v); + //Normals don't need as much precision as tex coords or positions + data.put((byte)((int)(v.normalX*127)&0xFF)); + data.put((byte)((int)(v.normalY*127)&0xFF)); + data.put((byte)((int)(v.normalZ*127)&0xFF)); + //Neither do colors + data.put((byte)(v.r*255)); + data.put((byte)(v.g*255)); + data.put((byte)(v.b*255)); + data.put((byte)(v.a*255)); + } + data.rewind(); + GLCompat.bindBuffer(GLCompat.GL_ARRAY_BUFFER, vboId); + GLCompat.bufferData(GLCompat.GL_ARRAY_BUFFER, data, GLCompat.GL_STATIC_DRAW); + GLCompat.bindBuffer(GLCompat.GL_ARRAY_BUFFER, 0); + + Vbo vbo = new Vbo(vboId, GL11.GL_QUADS, vertices.length); + return vbo; + } + + public static class Vertex { + public float x; + public float y; + public float z; + public float u; + public float v; + public float normalX; + public float normalY; + public float normalZ; + public float r; + public float g; + public float b; + public float a; + + public Vertex(float x, float y, float z, float u, float v, float nX, float nY, float nZ, float r, float g, float b, float a) { + this.x = x; + this.y = y; + this.z = z; + this.u = u; + this.v = v; + this.normalX = nX; + this.normalY = nY; + this.normalZ = nZ; + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + } +} diff --git a/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/WavefrontObject.java b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/WavefrontObject.java new file mode 100644 index 0000000000..3a77a601f2 --- /dev/null +++ b/src/main/java/com/crowsofwar/avatar/client/render/lightning/render/WavefrontObject.java @@ -0,0 +1,660 @@ +package com.crowsofwar.avatar.client.render.lightning.render; + +import com.crowsofwar.avatar.client.render.lightning.math.Vertex; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.IResource; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import org.lwjgl.opengl.GL11; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Wavefront Object importer + * Based heavily off of the specifications found at http://en.wikipedia.org/wiki/Wavefront_.obj_file + */ +public class WavefrontObject implements IModelCustom { + private static Pattern vertexPattern = Pattern.compile("(v( (\\-){0,1}\\d+(\\.\\d+)?){3,4} *\\n)|(v( (\\-){0,1}\\d+(\\.\\d+)?){3,4} *$)"); + private static Pattern vertexNormalPattern = Pattern.compile("(vn( (\\-){0,1}\\d+(\\.\\d+)?){3,4} *\\n)|(vn( (\\-){0,1}\\d+(\\.\\d+)?){3,4} *$)"); + private static Pattern textureCoordinatePattern = Pattern.compile("(vt( (\\-){0,1}\\d+\\.\\d+){2,3} *\\n)|(vt( (\\-){0,1}\\d+(\\.\\d+)?){2,3} *$)"); + private static Pattern face_V_VT_VN_Pattern = Pattern.compile("(f( \\d+/\\d+/\\d+){3,4} *\\n)|(f( \\d+/\\d+/\\d+){3,4} *$)"); + private static Pattern face_V_VT_Pattern = Pattern.compile("(f( \\d+/\\d+){3,4} *\\n)|(f( \\d+/\\d+){3,4} *$)"); + private static Pattern face_V_VN_Pattern = Pattern.compile("(f( \\d+//\\d+){3,4} *\\n)|(f( \\d+//\\d+){3,4} *$)"); + private static Pattern face_V_Pattern = Pattern.compile("(f( \\d+){3,4} *\\n)|(f( \\d+){3,4} *$)"); + private static Pattern groupObjectPattern = Pattern.compile("([go]( [\\w\\d\\.]+) *\\n)|([go]( [\\w\\d\\.]+) *$)"); + + private static Matcher vertexMatcher, vertexNormalMatcher, textureCoordinateMatcher; + private static Matcher face_V_VT_VN_Matcher, face_V_VT_Matcher, face_V_VN_Matcher, face_V_Matcher; + private static Matcher groupObjectMatcher; + + public ArrayList vertices = new ArrayList(); + public ArrayList vertexNormals = new ArrayList(); + public ArrayList textureCoordinates = new ArrayList(); + public ArrayList groupObjects = new ArrayList(); + private GroupObject currentGroupObject; + private String fileName; + + public WavefrontObject(ResourceLocation resource) throws ModelFormatException + { + this.fileName = resource.toString(); + + try + { + IResource res = Minecraft.getMinecraft().getResourceManager().getResource(resource); + loadObjModel(res.getInputStream()); + } + catch (IOException e) + { + throw new ModelFormatException("IO Exception reading model format", e); + } + } + + public WavefrontObject(String filename, InputStream inputStream) throws ModelFormatException + { + this.fileName = filename; + loadObjModel(inputStream); + } + + private void loadObjModel(InputStream inputStream) throws ModelFormatException + { + BufferedReader reader = null; + + String currentLine = null; + int lineCount = 0; + + try + { + reader = new BufferedReader(new InputStreamReader(inputStream)); + + while ((currentLine = reader.readLine()) != null) + { + lineCount++; + currentLine = currentLine.replaceAll("\\s+", " ").trim(); + + if (currentLine.startsWith("#") || currentLine.length() == 0) + { + continue; + } + else if (currentLine.startsWith("v ")) + { + Vertex vertex = parseVertex(currentLine, lineCount); + if (vertex != null) + { + vertices.add(vertex); + } + } + else if (currentLine.startsWith("vn ")) + { + Vertex vertex = parseVertexNormal(currentLine, lineCount); + if (vertex != null) + { + vertexNormals.add(vertex); + } + } + else if (currentLine.startsWith("vt ")) + { + TextureCoordinate textureCoordinate = parseTextureCoordinate(currentLine, lineCount); + if (textureCoordinate != null) + { + textureCoordinates.add(textureCoordinate); + } + } + else if (currentLine.startsWith("f ")) + { + + if (currentGroupObject == null) + { + currentGroupObject = new GroupObject("Default"); + } + + Face face = parseFace(currentLine, lineCount); + + if (face != null) + { + currentGroupObject.faces.add(face); + } + } + else if (currentLine.startsWith("g ") | currentLine.startsWith("o ")) + { + GroupObject group = parseGroupObject(currentLine, lineCount); + + if (group != null) + { + if (currentGroupObject != null) + { + groupObjects.add(currentGroupObject); + } + } + + currentGroupObject = group; + } + } + + groupObjects.add(currentGroupObject); + } + catch (IOException e) + { + throw new ModelFormatException("IO Exception reading model format", e); + } + finally + { + try + { + reader.close(); + } + catch (IOException e) + { + // hush + } + + try + { + inputStream.close(); + } + catch (IOException e) + { + // hush + } + } + } + + @Override + @SideOnly(Side.CLIENT) + public void renderAll() + { + Tessellator tessellator = Tessellator.instance; + + if (currentGroupObject != null) + { + tessellator.startDrawing(currentGroupObject.glDrawingMode); + } + else + { + tessellator.startDrawing(GL11.GL_TRIANGLES); + } + tessellateAll(tessellator); + + tessellator.draw(); + } + + @Override + @SideOnly(Side.CLIENT) + public void tessellateAll(Tessellator tessellator) + { + for (GroupObject groupObject : groupObjects) + { + groupObject.render(tessellator); + } + } + + @Override + @SideOnly(Side.CLIENT) + public void renderOnly(String... groupNames) + { + for (GroupObject groupObject : groupObjects) + { + for (String groupName : groupNames) + { + if (groupName.equalsIgnoreCase(groupObject.name)) + { + groupObject.render(); + } + } + } + } + + @Override + @SideOnly(Side.CLIENT) + public void tessellateOnly(Tessellator tessellator, String... groupNames) { + for (GroupObject groupObject : groupObjects) + { + for (String groupName : groupNames) + { + if (groupName.equalsIgnoreCase(groupObject.name)) + { + groupObject.render(tessellator); + } + } + } + } + + @Override + @SideOnly(Side.CLIENT) + public void renderPart(String partName) + { + for (GroupObject groupObject : groupObjects) + { + if (partName.equalsIgnoreCase(groupObject.name)) + { + groupObject.render(); + } + } + } + + @Override + @SideOnly(Side.CLIENT) + public void tessellatePart(Tessellator tessellator, String partName) { + for (GroupObject groupObject : groupObjects) + { + if (partName.equalsIgnoreCase(groupObject.name)) + { + groupObject.render(tessellator); + } + } + } + + @Override + @SideOnly(Side.CLIENT) + public void renderAllExcept(String... excludedGroupNames) + { + for (GroupObject groupObject : groupObjects) + { + boolean skipPart=false; + for (String excludedGroupName : excludedGroupNames) + { + if (excludedGroupName.equalsIgnoreCase(groupObject.name)) + { + skipPart=true; + } + } + if(!skipPart) + { + groupObject.render(); + } + } + } + + @Override + @SideOnly(Side.CLIENT) + public void tessellateAllExcept(Tessellator tessellator, String... excludedGroupNames) + { + boolean exclude; + for (GroupObject groupObject : groupObjects) + { + exclude=false; + for (String excludedGroupName : excludedGroupNames) + { + if (excludedGroupName.equalsIgnoreCase(groupObject.name)) + { + exclude=true; + } + } + if(!exclude) + { + groupObject.render(tessellator); + } + } + } + + private Vertex parseVertex(String line, int lineCount) throws ModelFormatException + { + Vertex vertex = null; + + if (isValidVertexLine(line)) + { + line = line.substring(line.indexOf(" ") + 1); + String[] tokens = line.split(" "); + + try + { + if (tokens.length == 2) + { + return new Vertex(Float.parseFloat(tokens[0]), Float.parseFloat(tokens[1])); + } + else if (tokens.length == 3) + { + return new Vertex(Float.parseFloat(tokens[0]), Float.parseFloat(tokens[1]), Float.parseFloat(tokens[2])); + } + } + catch (NumberFormatException e) + { + throw new ModelFormatException(String.format("Number formatting error at line %d",lineCount), e); + } + } + else + { + throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format"); + } + + return vertex; + } + + private Vertex parseVertexNormal(String line, int lineCount) throws ModelFormatException + { + Vertex vertexNormal = null; + + if (isValidVertexNormalLine(line)) + { + line = line.substring(line.indexOf(" ") + 1); + String[] tokens = line.split(" "); + + try + { + if (tokens.length == 3) + return new Vertex(Float.parseFloat(tokens[0]), Float.parseFloat(tokens[1]), Float.parseFloat(tokens[2])); + } + catch (NumberFormatException e) + { + throw new ModelFormatException(String.format("Number formatting error at line %d",lineCount), e); + } + } + else + { + throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format"); + } + + return vertexNormal; + } + + private TextureCoordinate parseTextureCoordinate(String line, int lineCount) throws ModelFormatException + { + TextureCoordinate textureCoordinate = null; + + if (isValidTextureCoordinateLine(line)) + { + line = line.substring(line.indexOf(" ") + 1); + String[] tokens = line.split(" "); + + try + { + if (tokens.length == 2) + return new TextureCoordinate(Float.parseFloat(tokens[0]), 1 - Float.parseFloat(tokens[1])); + else if (tokens.length == 3) + return new TextureCoordinate(Float.parseFloat(tokens[0]), 1 - Float.parseFloat(tokens[1]), Float.parseFloat(tokens[2])); + } + catch (NumberFormatException e) + { + throw new ModelFormatException(String.format("Number formatting error at line %d",lineCount), e); + } + } + else + { + throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format"); + } + + return textureCoordinate; + } + + private Face parseFace(String line, int lineCount) throws ModelFormatException + { + Face face = null; + + if (isValidFaceLine(line)) + { + face = new Face(); + + String trimmedLine = line.substring(line.indexOf(" ") + 1); + String[] tokens = trimmedLine.split(" "); + String[] subTokens = null; + + if (tokens.length == 3) + { + if (currentGroupObject.glDrawingMode == -1) + { + currentGroupObject.glDrawingMode = GL11.GL_TRIANGLES; + } + else if (currentGroupObject.glDrawingMode != GL11.GL_TRIANGLES) + { + throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Invalid number of points for face (expected 4, found " + tokens.length + ")"); + } + } + else if (tokens.length == 4) + { + if (currentGroupObject.glDrawingMode == -1) + { + currentGroupObject.glDrawingMode = GL11.GL_QUADS; + } + else if (currentGroupObject.glDrawingMode != GL11.GL_QUADS) + { + throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Invalid number of points for face (expected 3, found " + tokens.length + ")"); + } + } + + // f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 ... + if (isValidFace_V_VT_VN_Line(line)) + { + face.vertices = new Vertex[tokens.length]; + face.textureCoordinates = new TextureCoordinate[tokens.length]; + face.vertexNormals = new Vertex[tokens.length]; + + for (int i = 0; i < tokens.length; ++i) + { + subTokens = tokens[i].split("/"); + + face.vertices[i] = vertices.get(Integer.parseInt(subTokens[0]) - 1); + face.textureCoordinates[i] = textureCoordinates.get(Integer.parseInt(subTokens[1]) - 1); + face.vertexNormals[i] = vertexNormals.get(Integer.parseInt(subTokens[2]) - 1); + } + + face.faceNormal = face.calculateFaceNormal(); + } + // f v1/vt1 v2/vt2 v3/vt3 ... + else if (isValidFace_V_VT_Line(line)) + { + face.vertices = new Vertex[tokens.length]; + face.textureCoordinates = new TextureCoordinate[tokens.length]; + + for (int i = 0; i < tokens.length; ++i) + { + subTokens = tokens[i].split("/"); + + face.vertices[i] = vertices.get(Integer.parseInt(subTokens[0]) - 1); + face.textureCoordinates[i] = textureCoordinates.get(Integer.parseInt(subTokens[1]) - 1); + } + + face.faceNormal = face.calculateFaceNormal(); + } + // f v1//vn1 v2//vn2 v3//vn3 ... + else if (isValidFace_V_VN_Line(line)) + { + face.vertices = new Vertex[tokens.length]; + face.vertexNormals = new Vertex[tokens.length]; + + for (int i = 0; i < tokens.length; ++i) + { + subTokens = tokens[i].split("//"); + + face.vertices[i] = vertices.get(Integer.parseInt(subTokens[0]) - 1); + face.vertexNormals[i] = vertexNormals.get(Integer.parseInt(subTokens[1]) - 1); + } + + face.faceNormal = face.calculateFaceNormal(); + } + // f v1 v2 v3 ... + else if (isValidFace_V_Line(line)) + { + face.vertices = new Vertex[tokens.length]; + + for (int i = 0; i < tokens.length; ++i) + { + face.vertices[i] = vertices.get(Integer.parseInt(tokens[i]) - 1); + } + + face.faceNormal = face.calculateFaceNormal(); + } + else + { + throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format"); + } + } + else + { + throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format"); + } + + return face; + } + + private GroupObject parseGroupObject(String line, int lineCount) throws ModelFormatException + { + GroupObject group = null; + + if (isValidGroupObjectLine(line)) + { + String trimmedLine = line.substring(line.indexOf(" ") + 1); + + if (trimmedLine.length() > 0) + { + group = new GroupObject(trimmedLine); + } + } + else + { + throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format"); + } + + return group; + } + + /*** + * Verifies that the given line from the model file is a valid vertex + * @param line the line being validated + * @return true if the line is a valid vertex, false otherwise + */ + private static boolean isValidVertexLine(String line) + { + if (vertexMatcher != null) + { + vertexMatcher.reset(); + } + + vertexMatcher = vertexPattern.matcher(line); + return vertexMatcher.matches(); + } + + /*** + * Verifies that the given line from the model file is a valid vertex normal + * @param line the line being validated + * @return true if the line is a valid vertex normal, false otherwise + */ + private static boolean isValidVertexNormalLine(String line) + { + if (vertexNormalMatcher != null) + { + vertexNormalMatcher.reset(); + } + + vertexNormalMatcher = vertexNormalPattern.matcher(line); + return vertexNormalMatcher.matches(); + } + + /*** + * Verifies that the given line from the model file is a valid texture coordinate + * @param line the line being validated + * @return true if the line is a valid texture coordinate, false otherwise + */ + private static boolean isValidTextureCoordinateLine(String line) + { + if (textureCoordinateMatcher != null) + { + textureCoordinateMatcher.reset(); + } + + textureCoordinateMatcher = textureCoordinatePattern.matcher(line); + return textureCoordinateMatcher.matches(); + } + + /*** + * Verifies that the given line from the model file is a valid face that is described by vertices, texture coordinates, and vertex normals + * @param line the line being validated + * @return true if the line is a valid face that matches the format "f v1/vt1/vn1 ..." (with a minimum of 3 points in the face, and a maximum of 4), false otherwise + */ + private static boolean isValidFace_V_VT_VN_Line(String line) + { + if (face_V_VT_VN_Matcher != null) + { + face_V_VT_VN_Matcher.reset(); + } + + face_V_VT_VN_Matcher = face_V_VT_VN_Pattern.matcher(line); + return face_V_VT_VN_Matcher.matches(); + } + + /*** + * Verifies that the given line from the model file is a valid face that is described by vertices and texture coordinates + * @param line the line being validated + * @return true if the line is a valid face that matches the format "f v1/vt1 ..." (with a minimum of 3 points in the face, and a maximum of 4), false otherwise + */ + private static boolean isValidFace_V_VT_Line(String line) + { + if (face_V_VT_Matcher != null) + { + face_V_VT_Matcher.reset(); + } + + face_V_VT_Matcher = face_V_VT_Pattern.matcher(line); + return face_V_VT_Matcher.matches(); + } + + /*** + * Verifies that the given line from the model file is a valid face that is described by vertices and vertex normals + * @param line the line being validated + * @return true if the line is a valid face that matches the format "f v1//vn1 ..." (with a minimum of 3 points in the face, and a maximum of 4), false otherwise + */ + private static boolean isValidFace_V_VN_Line(String line) + { + if (face_V_VN_Matcher != null) + { + face_V_VN_Matcher.reset(); + } + + face_V_VN_Matcher = face_V_VN_Pattern.matcher(line); + return face_V_VN_Matcher.matches(); + } + + /*** + * Verifies that the given line from the model file is a valid face that is described by only vertices + * @param line the line being validated + * @return true if the line is a valid face that matches the format "f v1 ..." (with a minimum of 3 points in the face, and a maximum of 4), false otherwise + */ + private static boolean isValidFace_V_Line(String line) + { + if (face_V_Matcher != null) + { + face_V_Matcher.reset(); + } + + face_V_Matcher = face_V_Pattern.matcher(line); + return face_V_Matcher.matches(); + } + + /*** + * Verifies that the given line from the model file is a valid face of any of the possible face formats + * @param line the line being validated + * @return true if the line is a valid face that matches any of the valid face formats, false otherwise + */ + private static boolean isValidFaceLine(String line) + { + return isValidFace_V_VT_VN_Line(line) || isValidFace_V_VT_Line(line) || isValidFace_V_VN_Line(line) || isValidFace_V_Line(line); + } + + /*** + * Verifies that the given line from the model file is a valid group (or object) + * @param line the line being validated + * @return true if the line is a valid group (or object), false otherwise + */ + private static boolean isValidGroupObjectLine(String line) + { + if (groupObjectMatcher != null) + { + groupObjectMatcher.reset(); + } + + groupObjectMatcher = groupObjectPattern.matcher(line); + return groupObjectMatcher.matches(); + } + + @Override + public String getType() + { + return "obj"; + } +} diff --git a/src/main/java/com/crowsofwar/avatar/item/ItemOstrichEquipment.java b/src/main/java/com/crowsofwar/avatar/item/ItemOstrichEquipment.java index 86e4dca933..1f7c978e70 100644 --- a/src/main/java/com/crowsofwar/avatar/item/ItemOstrichEquipment.java +++ b/src/main/java/com/crowsofwar/avatar/item/ItemOstrichEquipment.java @@ -75,7 +75,7 @@ public enum EquipmentTier { */ @Nullable public static String getTierName(int index) { - if (!isValidIndex(index)) return null; + if (!isValidIndex(index)) return "woven"; return values()[index].name().toLowerCase(); } diff --git a/src/main/java/com/crowsofwar/avatar/network/AvatarClientProxy.java b/src/main/java/com/crowsofwar/avatar/network/AvatarClientProxy.java index 36e85cd308..b8e1a5133f 100644 --- a/src/main/java/com/crowsofwar/avatar/network/AvatarClientProxy.java +++ b/src/main/java/com/crowsofwar/avatar/network/AvatarClientProxy.java @@ -38,6 +38,11 @@ import com.crowsofwar.avatar.client.particles.oldsystem.*; import com.crowsofwar.avatar.client.render.*; import com.crowsofwar.avatar.client.render.iceprison.RenderIcePrison; +import com.crowsofwar.avatar.client.render.lightning.handler.LightningGenerator; +import com.crowsofwar.avatar.client.render.lightning.main.ResourceManager; +import com.crowsofwar.avatar.client.render.lightning.particle.ParticleFakeBrightness; +import com.crowsofwar.avatar.client.render.lightning.particle.ParticleRenderLayer; +import com.crowsofwar.avatar.client.render.lightning.render.GLCompat; import com.crowsofwar.avatar.client.renderer.LayerGlider; import com.crowsofwar.avatar.entity.*; import com.crowsofwar.avatar.entity.mob.*; @@ -52,24 +57,29 @@ import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.multiplayer.PlayerControllerMP; import net.minecraft.client.particle.ParticleManager; +import net.minecraft.client.renderer.GLAllocation; import net.minecraft.client.settings.KeyBinding; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.IThreadListener; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.client.event.GuiOpenEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.client.registry.ClientRegistry; +import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.InputEvent.KeyInputEvent; import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientConnectedToServerEvent; +import net.minecraftforge.fml.relauncher.ReflectionHelper; import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.Map; +import java.nio.FloatBuffer; +import java.util.*; import static com.crowsofwar.avatar.config.ConfigAnalytics.ANALYTICS_CONFIG; import static com.crowsofwar.avatar.config.ConfigClient.CLIENT_CONFIG; @@ -92,6 +102,23 @@ public class AvatarClientProxy implements AvatarCommonProxy { //Particles + // From Drillgon + public static Field partialTicksPaused; + public static final FloatBuffer AUX_GL_BUFFER = GLAllocation.createDirectFloatBuffer(16); + public static final FloatBuffer AUX_GL_BUFFER2 = GLAllocation.createDirectFloatBuffer(16); + //Drillgon200: Will I ever figure out how to write better code than this? + public static final List deferredRenderers = new ArrayList<>(); + + @Override + public void checkGLCaps(){ + GLCompat.error = GLCompat.init(); + if(GLCompat.error.isEmpty()){ + System.out.println("Advanced rendering fully supported"); + } else { + System.out.println("Advanced rendering not supported: " + GLCompat.error); + } + } + /** * Use {@link ParticleAvatar#registerParticle(ResourceLocation, ParticleAvatar.IAvatarParticleFactory)}, this is internal. */ @@ -259,6 +286,65 @@ public void init() { } + @Override + public void postInit(FMLPostInitializationEvent e) { + ResourceManager.loadAnimatedModels(); + ParticleRenderLayer.register(); + } + + @Override + public void effectNT(NBTTagCompound data) { + World world = Minecraft.getMinecraft().world; + EntityPlayer player = Minecraft.getMinecraft().player; + Random rand = world.rand; + String type = data.getString("type"); + double x = data.getDouble("posX"); + double y = data.getDouble("posY"); + double z = data.getDouble("posZ"); + if ("lightning".equals(type)) { + String mode = data.getString("mode"); + if ("beam".equals(mode)) { + double hitX = data.getDouble("hitX"); + double hitY = data.getDouble("hitY"); + double hitZ = data.getDouble("hitZ"); + int hitType = data.getInteger("hitType"); + double length = new Vec3d(x, y, z).subtract(new Vec3d(hitX, hitY, hitZ)).length(); + //Left/right, up/down, forward/backward + LightningGenerator.LightningGenInfo i = new LightningGenerator.LightningGenInfo(); + i.forkChance = 0; + i.randAmount = 1F; + i.randAmountSubdivMultiplier = 0.2F; + i.subdivMult = 2; + i.subdivisions = Math.max((int) (length * 0.1), 1); + i.subdivRecurse = 2; + Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleLightningFade(player.world, x, y, z, hitX, hitY, hitZ, 0.075F, i)); + if (hitType == 0 || hitType == 1) { + Vec3d normal = new Vec3d(data.getDouble("normX"), data.getDouble("normY"), data.getDouble("normZ")).scale(0.25F); + for (int j = 0; j < 3; j++) { + ParticleFakeBrightness b = new ParticleFakeBrightness(player.world, hitX + normal.x + (rand.nextFloat() - 0.5F) * 0.1F, hitY + normal.y + (rand.nextFloat() - 0.5F) * 0.1F, hitZ + normal.z + (rand.nextFloat() - 0.5F) * 0.1F, 60, 15) + .color(0.4F, 0.8F, 1, 2); + b.fadeInKoeff = 10; + Minecraft.getMinecraft().effectRenderer.addEffect(b); + } + } + } + } + } + + @Override + public float partialTicks() { + try { + if(partialTicksPaused == null){ + partialTicksPaused = ReflectionHelper.findField(Minecraft.class, "renderPartialTicksPaused", "field_193996_ah"); + } + boolean paused = Minecraft.getMinecraft().isGamePaused(); + return paused ? partialTicksPaused.getFloat(Minecraft.getMinecraft()) : Minecraft.getMinecraft().getRenderPartialTicks(); + } catch(Exception x){ + x.printStackTrace(); + } + return Minecraft.getMinecraft().getRenderPartialTicks(); + } + @Override public AvatarGui createClientGui(int id, EntityPlayer player, World world, int x, int y, int z) { diff --git a/src/main/java/com/crowsofwar/avatar/network/AvatarCommonProxy.java b/src/main/java/com/crowsofwar/avatar/network/AvatarCommonProxy.java index a1b0e183bc..635a2d366c 100644 --- a/src/main/java/com/crowsofwar/avatar/network/AvatarCommonProxy.java +++ b/src/main/java/com/crowsofwar/avatar/network/AvatarCommonProxy.java @@ -21,16 +21,21 @@ import com.crowsofwar.avatar.client.particles.newparticles.ParticleAvatar; import com.crowsofwar.avatar.client.controls.IControlsHandler; import com.crowsofwar.avatar.client.controls.KeybindingWrapper; +import com.crowsofwar.avatar.client.render.lightning.render.GLCompat; import com.crowsofwar.avatar.util.data.AvatarPlayerData; import com.crowsofwar.avatar.client.gui.AvatarGui; import com.crowsofwar.avatar.capabilities.IAdvancedGliderCapabilityHandler; import com.crowsofwar.gorecore.data.PlayerDataFetcher; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.IThreadListener; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; + +import java.util.logging.Level; /** * Allows calling of side-specific code by using a common base class and @@ -70,6 +75,8 @@ public interface AvatarCommonProxy { */ void init(); + void postInit(FMLPostInitializationEvent e); + AvatarGui createClientGui(int id, EntityPlayer player, World world, int x, int y, int z); PlayerDataFetcher getClientDataFetcher(); @@ -112,7 +119,7 @@ default void spawnTornadoParticle(World world, double x, double y, double z, dou * Looks up keybinding by name */ KeybindingWrapper createKeybindWrapper(String keybindName); - + /** * Register the item models so they can be configured to use the correct textures */ @@ -125,4 +132,11 @@ default void spawnTornadoParticle(World world, double x, double y, double z, dou World getClientWorld(); IAdvancedGliderCapabilityHandler getClientGliderCapability(); + + void checkGLCaps(); + + // TODO - Should be deleted + void effectNT(NBTTagCompound nbt); + + float partialTicks(); } diff --git a/src/main/java/com/crowsofwar/avatar/network/AvatarServerProxy.java b/src/main/java/com/crowsofwar/avatar/network/AvatarServerProxy.java index a3de2dd2e3..a7c5df9f59 100644 --- a/src/main/java/com/crowsofwar/avatar/network/AvatarServerProxy.java +++ b/src/main/java/com/crowsofwar/avatar/network/AvatarServerProxy.java @@ -19,13 +19,24 @@ import com.crowsofwar.avatar.client.controls.IControlsHandler; import com.crowsofwar.avatar.client.controls.KeybindingWrapper; +import com.crowsofwar.avatar.client.render.lightning.math.Vec3; import com.crowsofwar.avatar.util.data.AvatarPlayerData; import com.crowsofwar.avatar.client.gui.AvatarGui; import com.crowsofwar.avatar.capabilities.IAdvancedGliderCapabilityHandler; import com.crowsofwar.gorecore.data.PlayerDataFetcher; +import net.minecraft.client.renderer.block.model.IBakedModel; +import net.minecraft.client.renderer.block.model.ModelResourceLocation; +import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.IThreadListener; +import net.minecraft.util.registry.IRegistry; import net.minecraft.world.World; +import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; + +import java.io.File; public class AvatarServerProxy implements AvatarCommonProxy { @@ -56,6 +67,10 @@ public void init() { } + public File getDataDir(){ + return FMLCommonHandler.instance().getMinecraftServerInstance().getDataDirectory(); + } + @Override public AvatarGui createClientGui(int id, EntityPlayer player, World world, int x, int y, int z) { return null; @@ -105,4 +120,50 @@ public IAdvancedGliderCapabilityHandler getClientGliderCapability() { return null; //nothing on server } + // From Drillgon + public void registerRenderInfo() { } + public void registerTileEntitySpecialRenderer() { } + public void registerItemRenderer() { } + public void registerEntityRenderer() { } + public void registerBlockRenderer() { } + + public void particleControl(double x, double y, double z, int type) { } + + public void spawnParticle(double x, double y, double z, String type, float[] args) { } + + public void spawnSFX(World world, double posX, double posY, double posZ, int type, Vec3 payload) { } + + public void effectNT(NBTTagCompound data) { } + + public void registerMissileItems(IRegistry reg) { } + + public void preInit(FMLPreInitializationEvent evt) {} + + public void checkGLCaps(){}; + + public void postInit(FMLPostInitializationEvent e){ + } + + public float partialTicks(){ + return 1; + }; + + public boolean opengl33(){ + return true;//Doesn't matter for servers, and this won't print an error message. + } + + public EntityPlayer me() { + return null; + } + + public void playSound(String sound, Object data) { } + + public void displayTooltip(String msg) { } + + public void setRecoil(float rec){}; + + public boolean isVanished(Entity e) { + return false; + } + } diff --git a/src/main/resources/assets/avatarmod/models/anim/lightning_fp_anim0.dae b/src/main/resources/assets/avatarmod/models/anim/lightning_fp_anim0.dae new file mode 100644 index 0000000000..acaf20f101 --- /dev/null +++ b/src/main/resources/assets/avatarmod/models/anim/lightning_fp_anim0.dae @@ -0,0 +1,239 @@ + + + + + Blender User + Blender 2.90.1 commit date:2020-09-23, commit time:06:43, hash:3e85bb34d0d7 + + 2020-12-06T18:52:49 + 2020-12-06T18:52:49 + + Z_UP + + + + + + + ducc_st_engineer_png + + + + + ducc_st_engineer_png-surface + + + + + + 0 0 0 1 + + + + + + 1.45 + + + + + + + + + /E:/Chicken/Images/ducc_st_engineer.png + + + + + + + + + + + + -0.1263661 0.2716218 0.1667088 0.1573736 0.2716218 0.1667088 0.1573736 0.2716218 -0.1170308 -0.1263661 0.2716218 -0.1170309 -0.126366 -0.3667923 0.1667088 0.1573736 -0.3667923 0.1667088 0.1573736 -0.3667923 -0.1170309 -0.1263661 -0.3667923 -0.1170309 + + + + + + + + + + 1 0 0 0 0 1 3.5417e-7 1 0 -1 0 0 1.57551e-7 0 -1 -1.57551e-7 0 1 -1.85089e-7 1 0 -1 0 0 0 0 -1 + + + + + + + + + + 0.75 0.59375 0.6875 0.6875 0.6875 0.59375 0.6875 0.59375 0.625 0.6875 0.625 0.59375 0.6875 0.75 0.75 0.6875 0.75 0.75 0.875 0.59375 0.8125 0.6875 0.8125 0.59375 0.8125 0.59375 0.75 0.6875 0.75 0.59375 0.75 0.59375 0.75 0.6875 0.6875 0.6875 0.6875 0.59375 0.6875 0.6875 0.625 0.6875 0.6875 0.75 0.6875 0.6875 0.75 0.6875 0.875 0.59375 0.875 0.6875 0.8125 0.6875 0.8125 0.59375 0.8125 0.6875 0.75 0.6875 + + + + + + + + + + + + + + +

6 0 0 1 0 1 5 0 2 5 1 3 0 1 4 4 1 5 0 2 6 2 2 7 3 2 8 4 3 9 3 3 10 7 3 11 7 4 12 2 4 13 6 4 14 6 0 15 2 0 16 1 0 17 5 5 18 1 5 19 0 5 20 0 6 21 1 6 22 2 6 23 4 7 24 0 7 25 3 7 26 7 8 27 3 8 28 2 8 29

+
+
+
+ + + + -0.1256571 -0.60966 -0.2524322 0.156664 -0.60966 -0.2524322 0.1566638 -0.60966 0.03130751 -0.1256571 -0.60966 0.03130751 -0.1256571 0.02875447 0.03130751 0.1566638 0.02875447 0.03130751 0.1566638 0.02875441 -0.2524321 -0.1256571 0.02875441 -0.2524321 + + + + + + + + + + 0 -1 2.10068e-7 0 1.20393e-7 -1 -1 0 0 0 0 1 1 0 0 0 -1 2.10068e-7 0 0 -1 -1 0 1.85197e-7 0 0 1 1 2.10068e-7 4.11308e-7 + + + + + + + + + + 0.8125 0.75 0.75 0.6875 0.75 0.75 0.8125 0.5 0.75 0.59375 0.75 0.5 0.875 0.5 0.8125 0.59375 0.8125 0.5 0.6875 0.5 0.625 0.59375 0.625 0.5 0.6875 0.5 0.75 0.59375 0.6875 0.59375 0.8125 0.75 0.8125 0.6875 0.75 0.6875 0.8125 0.5 0.8125 0.59375 0.75 0.59375 0.875 0.5 0.875 0.59375 0.8125 0.59375 0.6875 0.5 0.6875 0.59375 0.625 0.59375 0.6875 0.5 0.75 0.5 0.75 0.59375 + + + + + + + + + + + + + + +

0 0 0 2 0 1 3 0 2 0 1 3 6 1 4 1 1 5 3 2 6 7 2 7 0 2 8 2 3 9 4 3 10 3 3 11 2 4 12 6 4 13 5 4 14 0 5 15 1 5 16 2 5 17 0 6 18 7 6 19 6 6 20 3 7 21 4 7 22 7 7 23 2 8 24 5 8 25 4 8 26 2 9 27 1 9 28 6 9 29

+
+
+
+
+ + + + + 0.04166662 0.08333331 0.125 0.1666666 0.2083333 0.25 0.2916666 0.3333333 0.375 0.4166666 0.4583333 0.5 0.5416667 0.5833333 0.625 0.6666667 0.7083333 0.75 0.7916667 0.8333333 0.875 0.9166667 0.9583333 1 1.041667 1.083333 1.125 1.166667 1.208333 1.25 1.291667 1.333333 1.375 1.416667 1.458333 1.5 1.541667 1.583333 1.625 1.666667 1.708333 1.75 1.791667 1.833333 1.875 1.916667 1.958333 2 2.041667 2.083333 2.125 2.166667 2.208333 2.25 2.291667 2.333333 2.375 2.416667 2.458333 2.5 2.541667 2.583333 2.625 2.666667 2.708333 2.75 2.791667 2.833333 2.875 2.916667 2.958333 3 3.041667 3.083333 3.125 3.166667 3.208333 3.25 3.291667 3.333333 3.375 3.416667 3.458333 3.5 3.541667 3.583333 3.625 3.666667 3.708333 3.75 3.791667 3.833333 3.875 3.916667 3.958333 4 4.041666 4.083333 4.125 4.166666 + + + + + + + + 1 2.98023e-8 -4.47035e-8 8.9407e-8 -2.98023e-8 0.9661521 -0.2579734 -0.3749997 -2.98023e-8 0.2579733 0.966152 0.1249996 0 0 0 1 0.9999999 -5.96046e-8 -2.98023e-8 8.9407e-8 -2.98023e-8 0.9660735 -0.2582668 -0.3749996 -7.45058e-9 0.2582667 0.9660736 0.1250001 0 0 0 1 0.9999999 0 -1.49012e-8 2.08616e-7 2.98023e-8 0.965841 -0.2591351 -0.3749997 -2.98023e-8 0.2591351 0.9658409 0.1249999 0 0 0 1 1 -2.98023e-8 -4.47035e-8 0 0 0.9654574 -0.2605611 -0.3749997 -3.72529e-8 0.260561 0.9654574 0.1250002 0 0 0 1 1 0 -2.98023e-8 1.19209e-7 -2.98023e-8 0.9649247 -0.2625265 -0.3749997 -2.23517e-8 0.2625266 0.9649248 0.125 0 0 0 1 1 0 -1.49012e-8 1.78814e-7 0 0.9642445 -0.2650138 -0.3749998 0 0.2650138 0.9642445 0.1250002 0 0 0 1 1 0 0 2.98023e-8 -2.98023e-8 0.9634176 -0.2680044 -0.3749998 0 0.2680044 0.9634176 0.1250001 0 0 0 1 1 2.98023e-8 -2.98023e-8 1.19209e-7 -2.98023e-8 0.9624442 -0.27148 -0.3749998 -2.23517e-8 0.2714799 0.9624441 0.125 0 0 0 1 1 2.98023e-8 -1.49012e-8 1.78814e-7 5.96046e-8 0.9613235 -0.2754218 -0.3749996 -1.49012e-8 0.2754218 0.9613235 0.1250002 0 0 0 1 1 0 -1.49012e-8 1.78814e-7 -2.98023e-8 0.960055 -0.2798113 -0.3749999 -2.23517e-8 0.2798112 0.960055 0.1249999 0 0 0 1 1 -2.98023e-8 0 0 -2.98023e-8 0.9586377 -0.2846293 -0.3749997 -1.49012e-8 0.2846293 0.9586377 0.125 0 0 0 1 1 -2.98023e-8 0 1.19209e-7 2.98023e-8 0.9570701 -0.289857 -0.3749996 -4.47035e-8 0.2898569 0.9570701 0.1249998 0 0 0 1 1 2.98023e-8 0 8.9407e-8 2.98023e-8 0.9553505 -0.2954752 -0.3749998 1.49012e-8 0.2954751 0.9553504 0.1249999 0 0 0 1 1 -2.98023e-8 -5.96046e-8 8.9407e-8 2.98023e-8 0.9534774 -0.3014643 -0.3749999 -5.96046e-8 0.3014643 0.9534775 0.125 0 0 0 1 1 0 0 0 2.98023e-8 0.9514494 -0.3078052 -0.3749996 -3.72529e-8 0.3078052 0.9514495 0.1249999 0 0 0 1 0.9999999 8.9407e-8 -2.98023e-8 2.98023e-8 5.96046e-8 0.9492646 -0.3144783 -0.3749998 -7.45058e-9 0.3144783 0.9492647 0.1250001 0 0 0 1 1 -2.98023e-8 0 0 2.98023e-8 0.9469218 -0.3214641 -0.3749997 -1.49012e-8 0.3214642 0.9469218 0.1250001 0 0 0 1 0.9999999 0 0 -1.19209e-7 2.98023e-8 0.9444194 -0.328743 -0.3749997 -2.23517e-8 0.328743 0.9444194 0.1250002 0 0 0 1 1 -2.98023e-8 -2.98023e-8 2.98023e-8 2.98023e-8 0.9417565 -0.3362954 -0.3749997 1.49012e-8 0.3362954 0.9417566 0.1250002 0 0 0 1 1 0 0 1.49012e-7 -2.98023e-8 0.9389324 -0.3441015 -0.3749998 7.45058e-9 0.3441015 0.9389323 0.1250002 0 0 0 1 1 2.98023e-8 -2.98023e-8 1.19209e-7 -2.98023e-8 0.9359466 -0.3521418 -0.3749996 5.21541e-8 0.3521418 0.9359466 0.1250001 0 0 0 1 1 8.9407e-8 -5.96046e-8 5.96046e-8 2.98023e-8 0.9327992 -0.3603966 -0.3749996 -1.49012e-8 0.3603965 0.9327991 0.1249999 0 0 0 1 0.9999999 5.96046e-8 -2.98023e-8 1.78814e-7 0 0.9294904 -0.3688462 -0.3749996 4.47035e-8 0.3688463 0.9294904 0.1250001 0 0 0 1 1 -2.98023e-8 0 5.96046e-8 2.98023e-8 0.9260213 -0.3774712 -0.3749996 -3.72529e-8 0.3774713 0.9260214 0.125 0 0 0 1 1 -2.98023e-8 -5.96046e-8 1.78814e-7 0 0.9223932 -0.3862522 -0.3749997 8.19564e-8 0.3862523 0.9223932 0.1250001 0 0 0 1 1 -2.98023e-8 -2.98023e-8 1.19209e-7 -5.96046e-8 0.9186082 -0.3951697 -0.3749996 1.49012e-8 0.3951697 0.9186081 0.1250002 0 0 0 1 1 2.98023e-8 -2.98023e-8 1.19209e-7 0 0.9146687 -0.4042045 -0.3749999 -1.49012e-8 0.4042045 0.9146686 0.1250001 0 0 0 1 1 0 2.98023e-8 -5.96046e-8 2.98023e-8 0.9105778 -0.4133377 -0.3749998 2.98023e-8 0.4133376 0.9105778 0.1249999 0 0 0 1 1 5.96046e-8 -5.96046e-8 1.19209e-7 0 0.9063395 -0.4225502 -0.3749996 7.45058e-9 0.4225502 0.9063395 0.1250001 0 0 0 1 1 -2.98023e-8 0 1.19209e-7 0 0.9019581 -0.4318236 -0.3749998 1.49012e-8 0.4318235 0.9019581 0.125 0 0 0 1 1 -2.98023e-8 -2.98023e-8 0 -5.96046e-8 0.8974388 -0.4411392 -0.3749997 2.98023e-8 0.4411391 0.8974387 0.1249999 0 0 0 1 0.9999999 -2.98023e-8 2.98023e-8 -5.96046e-8 0 0.8927871 -0.4504788 -0.3749997 -1.49012e-8 0.4504789 0.8927871 0.1249999 0 0 0 1 0.9999999 0 2.98023e-8 1.19209e-7 -5.96046e-8 0.8880097 -0.4598247 -0.3749997 -4.47035e-8 0.4598247 0.8880097 0.1249999 0 0 0 1 0.9999999 5.96046e-8 2.98023e-8 0 -2.98023e-8 0.8831135 -0.4691592 -0.3749999 7.45058e-9 0.4691592 0.8831134 0.125 0 0 0 1 1 5.96046e-8 -2.98023e-8 1.78814e-7 -2.98023e-8 0.8781067 -0.478465 -0.3749998 2.98023e-8 0.4784651 0.8781067 0.1249999 0 0 0 1 1 5.96046e-8 -5.96046e-8 5.96046e-8 0 0.8729973 -0.4877251 -0.3749997 8.9407e-8 0.4877252 0.8729972 0.1250001 0 0 0 1 1 0 2.98023e-8 0 0 0.8677947 -0.496923 -0.3749997 -7.45058e-9 0.4969231 0.8677946 0.125 0 0 0 1 1 0 0 1.19209e-7 2.98023e-8 0.8625088 -0.5060424 -0.3749997 5.96046e-8 0.5060424 0.8625088 0.1250001 0 0 0 1 1 0 -2.98023e-8 1.78814e-7 5.96046e-8 0.8571498 -0.5150673 -0.3749996 7.45058e-8 0.5150674 0.8571497 0.125 0 0 0 1 1 5.96046e-8 -5.96046e-8 1.78814e-7 2.98023e-8 0.8517289 -0.5239826 -0.3749996 5.21541e-8 0.5239826 0.8517289 0.1250002 0 0 0 1 0.9999999 2.98023e-8 2.98023e-8 1.78814e-7 -1.19209e-7 0.846258 -0.5327733 -0.3749997 2.79397e-8 0.5327733 0.846258 0.1250002 0 0 0 1 1 5.96046e-8 -2.98023e-8 2.38419e-7 -2.98023e-8 0.8407493 -0.5414246 -0.3749996 -6.70552e-8 0.5414245 0.8407493 0.1249999 0 0 0 1 1 5.96046e-8 0 1.78814e-7 2.98023e-8 0.8352157 -0.5499225 -0.3749998 -2.8871e-8 0.5499224 0.8352156 0.1250001 0 0 0 1 0.9999999 2.98023e-8 -5.96046e-8 1.78814e-7 2.98023e-8 0.8296705 -0.5582532 -0.3749998 -7.89296e-8 0.5582532 0.8296706 0.1249999 0 0 0 1 0.9999999 2.98023e-8 -1.19209e-7 5.96046e-8 0 0.824128 -0.5664036 -0.3749998 1.49012e-8 0.5664036 0.824128 0.125 0 0 0 1 1 0 -8.9407e-8 0 -2.98023e-8 0.8186023 -0.5743607 -0.3749998 1.67638e-8 0.5743605 0.8186023 0.125 0 0 0 1 1 5.96046e-8 -2.98023e-8 1.19209e-7 0 0.8131086 -0.5821121 -0.3749998 3.1665e-8 0.5821121 0.8131086 0.1250002 0 0 0 1 1 -2.98023e-8 -8.9407e-8 0 8.9407e-8 0.8076619 -0.5896461 -0.3749996 -1.49012e-8 0.5896461 0.807662 0.125 0 0 0 1 1 5.96046e-8 2.98023e-8 5.96046e-8 0 0.802278 -0.5969507 -0.3749998 -1.49012e-8 0.5969506 0.8022779 0.125 0 0 0 1 0.9999999 -5.96046e-8 -2.98023e-8 1.19209e-7 0 0.7969729 -0.604015 -0.3749996 3.35276e-8 0.6040151 0.7969729 0.1250002 0 0 0 1 1 5.96046e-8 -5.96046e-8 1.19209e-7 2.98023e-8 0.7917632 -0.6108282 -0.3749997 2.23517e-8 0.6108282 0.7917632 0.1249999 0 0 0 1 1 0 2.98023e-8 1.19209e-7 -2.98023e-8 0.7866653 -0.6173797 -0.3749998 -1.49012e-8 0.6173798 0.7866654 0.125 0 0 0 1 1 -2.98023e-8 1.19209e-7 0 -8.9407e-8 0.7816962 -0.6236595 -0.3749998 0 0.6236594 0.7816961 0.1250001 0 0 0 1 1 -2.98023e-8 -2.98023e-8 1.19209e-7 8.9407e-8 0.7768726 -0.6296577 -0.3749997 6.70552e-8 0.6296577 0.7768727 0.125 0 0 0 1 1 0 -5.96046e-8 0 2.98023e-8 0.7722122 -0.6353648 -0.3749996 -5.96046e-8 0.6353647 0.7722121 0.1249999 0 0 0 1 1 -5.96046e-8 -2.98023e-8 1.19209e-7 -2.98023e-8 0.7677317 -0.6407714 -0.3749996 -8.9407e-8 0.6407712 0.7677318 0.125 0 0 0 1 1 2.98023e-8 4.47035e-8 1.19209e-7 -2.98023e-8 0.763449 -0.6458682 -0.3749998 -7.45058e-8 0.6458682 0.763449 0.125 0 0 0 1 1 8.9407e-8 -7.45058e-8 0 0 0.7593812 -0.6506462 -0.3749995 0 0.6506463 0.7593812 0.1249999 0 0 0 1 0.9999999 0 -8.9407e-8 2.38419e-7 -2.98023e-8 0.7555452 -0.6550965 -0.3749998 1.49012e-8 0.6550965 0.7555452 0.1250002 0 0 0 1 1 5.96046e-8 -1.19209e-7 2.38419e-7 0 0.7519585 -0.6592104 -0.3749998 -2.98023e-8 0.6592103 0.7519586 0.1250001 0 0 0 1 1 0 -7.45058e-8 0 -2.98023e-8 0.7486384 -0.6629785 -0.3749996 2.98023e-8 0.6629786 0.7486385 0.125 0 0 0 1 1 2.98023e-8 -4.47035e-8 1.19209e-7 2.98023e-8 0.7456015 -0.6663921 -0.3749998 2.98023e-8 0.6663921 0.7456015 0.125 0 0 0 1 1 5.96046e-8 -5.96046e-8 1.19209e-7 0 0.7428643 -0.6694422 -0.3749996 1.49012e-8 0.6694422 0.7428642 0.1249999 0 0 0 1 1 8.9407e-8 -2.98023e-8 -1.19209e-7 2.98023e-8 0.7404432 -0.672119 -0.3749996 7.45058e-8 0.6721189 0.7404433 0.125 0 0 0 1 1 -2.98023e-8 2.23517e-8 0 -2.98023e-8 0.7383541 -0.6744131 -0.3749997 2.98023e-8 0.6744133 0.7383541 0.1250003 0 0 0 1 1 5.96046e-8 4.47035e-8 1.19209e-7 0 0.7366126 -0.6763148 -0.3749996 -5.96046e-8 0.6763148 0.7366127 0.1249999 0 0 0 1 1 -5.96046e-8 -4.47035e-8 1.19209e-7 2.98023e-8 0.735234 -0.6778135 -0.3749996 -2.98023e-8 0.6778134 0.735234 0.1250001 0 0 0 1 1 5.96046e-8 -2.23517e-8 2.38419e-7 2.98023e-8 0.7342323 -0.6788985 -0.3749998 0 0.6788985 0.7342322 0.1249999 0 0 0 1 0.9999999 -8.9407e-8 -2.04891e-8 0 1.49012e-8 0.7336216 -0.6795581 -0.3749997 5.96046e-8 0.6795582 0.7336215 0.1250001 0 0 0 1 1 2.98023e-8 1.54832e-8 1.19209e-7 -1.49012e-8 0.7334152 -0.679781 -0.3749998 0 0.679781 0.7334152 0.125 0 0 0 1 0.9999999 2.23517e-8 -2.98023e-8 1.19209e-7 -8.3819e-9 0.9920134 -0.1261329 -0.3749999 0 0.1261329 0.9920133 0.1250002 0 0 0 1 1 -4.47035e-8 -5.96046e-8 0 -1.02445e-8 0.9919803 -0.1263932 -0.3749996 2.98023e-8 0.1263932 0.9919803 0.1250001 0 0 0 1 1 7.45058e-9 -2.98023e-8 0 6.70552e-8 0.991879 -0.1271862 -0.3749996 2.98023e-8 0.1271862 0.9918789 0.1250002 0 0 0 1 1 0 5.96046e-8 1.19209e-7 1.44355e-8 0.9917056 -0.1285301 -0.3749996 5.96046e-8 0.1285301 0.9917057 0.1250001 0 0 0 1 1 2.98023e-8 2.98023e-8 1.19209e-7 2.18861e-8 0.9914559 -0.1304429 -0.3749999 2.98023e-8 0.1304429 0.9914558 0.125 0 0 0 1 0.9999999 0 -8.9407e-8 1.19209e-7 3.00352e-8 0.9911237 -0.1329425 -0.3749996 8.9407e-8 0.1329424 0.9911237 0.125 0 0 0 1 1 2.98023e-8 -5.96046e-8 0 -3.44589e-8 0.9907026 -0.1360465 -0.3749999 0 0.1360465 0.9907026 0.1250001 0 0 0 1 1 1.49012e-8 0 2.38419e-7 7.50879e-9 0.9901836 -0.1397723 -0.3749997 0 0.1397723 0.9901836 0.1250002 0 0 0 1 1 2.98023e-8 0 2.38419e-7 1.7928e-8 0.9895577 -0.1441374 -0.3749996 5.96046e-8 0.1441374 0.9895576 0.1249999 0 0 0 1 1 2.23517e-8 -5.96046e-8 1.19209e-7 9.31323e-10 0.9888134 -0.1491584 -0.3749998 2.98023e-8 0.1491584 0.9888134 0.1250001 0 0 0 1 1 5.58794e-8 2.98023e-8 1.19209e-7 1.96451e-9 0.9879377 -0.1548522 -0.3749998 2.98023e-8 0.1548522 0.9879376 0.1250001 0 0 0 1 1 1.49012e-8 -5.96046e-8 1.19209e-7 5.46352e-8 0.9869161 -0.1612349 -0.3749998 5.96046e-8 0.1612349 0.9869161 0.1250001 0 0 0 1 1 2.98023e-8 0 1.19209e-7 5.54137e-8 0.9857007 -0.1685051 -0.3749998 2.98023e-8 0.1685051 0.9857008 0.1250001 0 0 0 1 1 2.23517e-8 -8.9407e-8 2.38419e-7 1.49012e-8 0.9841045 -0.1775897 -0.3749999 8.9407e-8 0.1775897 0.9841045 0.1250001 0 0 0 1 1 5.96046e-8 0 1.19209e-7 -2.98023e-8 0.9818634 -0.1895898 -0.3749994 -2.98023e-8 0.1895897 0.9818634 0.1249999 0 0 0 1 0.9999999 1.49012e-8 2.98023e-8 1.19209e-7 3.72529e-8 0.9786381 -0.2055903 -0.3749997 -5.96046e-8 0.2055903 0.9786381 0.1249999 0 0 0 1 1 0 -1.19209e-7 0 4.47035e-8 0.9739766 -0.2266486 -0.3749998 5.96046e-8 0.2266486 0.9739766 0.1250002 0 0 0 1 1 0 -5.96046e-8 1.19209e-7 0 0.9672633 -0.2537749 -0.3749997 2.98023e-8 0.2537749 0.9672633 0.1250001 0 0 0 1 1 2.98023e-8 -2.98023e-8 1.78814e-7 -2.98023e-8 0.9578047 -0.2874196 -0.3749997 2.98023e-8 0.2874197 0.9578047 0.1250003 0 0 0 1 1 5.96046e-8 -4.47035e-8 2.38419e-7 4.47035e-8 0.9453582 -0.3260335 -0.3749996 1.49012e-8 0.3260335 0.9453582 0.125 0 0 0 1 1 0 -5.7742e-8 5.96046e-8 0 0.9299888 -0.3675878 -0.3749998 4.47035e-8 0.3675878 0.9299889 0.1250001 0 0 0 1 0.9999999 2.98023e-8 -5.21541e-8 5.96046e-8 -5.96046e-8 0.9120366 -0.4101088 -0.3749996 5.96046e-8 0.4101087 0.9120367 0.1250001 0 0 0 1 0.9999999 -5.96046e-8 -4.47035e-8 1.19209e-7 0 0.8921575 -0.4517241 -0.3749999 6.79865e-8 0.4517242 0.8921577 0.125 0 0 0 1 1 -5.96046e-8 -2.98023e-8 -2.98023e-8 0 0.8713257 -0.4907054 -0.3749996 3.72529e-8 0.4907054 0.8713257 0.125 0 0 0 1 1 0 -2.98023e-8 5.96046e-8 2.98023e-8 0.8507984 -0.5254921 -0.3749996 4.47035e-8 0.5254921 0.8507984 0.1250001 0 0 0 1 1 5.96046e-8 -8.9407e-8 4.47035e-8 2.98023e-8 0.8320549 -0.5546932 -0.3749996 2.98023e-8 0.5546933 0.8320549 0.1250001 0 0 0 1 0.9999999 2.23517e-8 -8.9407e-8 1.19209e-7 1.49012e-8 0.8167067 -0.577053 -0.3749998 2.98023e-8 0.5770531 0.8167067 0.1250001 0 0 0 1 0.9999999 -2.98023e-8 -2.98023e-8 5.96046e-8 4.47035e-8 0.8063916 -0.5913819 -0.3749998 2.98023e-8 0.591382 0.8063916 0.1250001 0 0 0 1 1 4.47035e-8 -5.96046e-8 0 -1.49012e-8 0.8026474 -0.5964538 -0.3749996 0 0.5964539 0.8026474 0.1250001 0 0 0 1 1 4.47035e-8 -5.96046e-8 0 -1.49012e-8 0.8026474 -0.5964538 -0.3749996 0 0.5964539 0.8026474 0.1250001 0 0 0 1 + + + + + + + + LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR + + + + + + + + + + + + + + + + + + 0.04166662 0.08333331 0.125 0.1666666 0.2083333 0.25 0.2916666 0.3333333 0.375 0.4166666 0.4583333 0.5 0.5416667 0.5833333 0.625 0.6666667 0.7083333 0.75 0.7916667 0.8333333 0.875 0.9166667 0.9583333 1 1.041667 1.083333 1.125 1.166667 1.208333 1.25 1.291667 1.333333 1.375 1.416667 1.458333 1.5 1.541667 1.583333 1.625 1.666667 1.708333 1.75 1.791667 1.833333 1.875 1.916667 1.958333 2 2.041667 2.083333 2.125 2.166667 2.208333 2.25 2.291667 2.333333 2.375 2.416667 2.458333 2.5 2.541667 2.583333 2.625 2.666667 2.708333 2.75 2.791667 2.833333 2.875 2.916667 2.958333 3 3.041667 3.083333 3.125 3.166667 3.208333 3.25 3.291667 3.333333 3.375 3.416667 3.458333 3.5 3.541667 3.583333 3.625 3.666667 3.708333 3.75 3.791667 3.833333 3.875 3.916667 3.958333 4 4.041666 4.083333 4.125 4.166666 + + + + + + + + -0.4416277 -0.8586183 0.5412973 -1.364339 0.8836397 -0.5416405 0.1242932 -1.019722 0.1553902 0.6398436 0.8315938 -0.4363496 0 0 0 1 -0.44194 -0.8584267 0.5412535 -1.364339 0.883464 -0.5420246 0.1243797 -0.9982048 0.1555016 0.6397756 0.8316094 -0.4206018 0 0 0 1 -0.4428615 -0.8578594 0.5411249 -1.364339 0.8829432 -0.5431627 0.1246293 -0.9776405 0.1558371 0.6395712 0.8316557 -0.403668 0 0 0 1 -0.4443707 -0.8569257 0.540915 -1.364339 0.8820853 -0.5450351 0.1250275 -0.9580029 0.1563987 0.63923 0.8317325 -0.3855913 0 0 0 1 -0.4464437 -0.8556346 0.5406272 -1.364339 0.8808974 -0.5476195 0.1255589 -0.9395242 0.1571879 0.6387504 0.8318396 -0.3663256 0 0 0 1 -0.4490571 -0.8539931 0.5402651 -1.364339 0.8793854 -0.5508944 0.1262079 -0.921344 0.158207 0.6381308 0.8319766 -0.3467852 0 0 0 1 -0.4521866 -0.8520074 0.5398319 -1.364339 0.8775538 -0.5548377 0.1269581 -0.9034225 0.1594582 0.6373684 0.8321436 -0.3270072 0 0 0 1 -0.4558066 -0.849683 0.5393314 -1.364339 0.8754072 -0.559426 0.1277927 -0.8857921 0.160944 0.6364598 0.8323404 -0.3069629 0 0 0 1 -0.4598914 -0.8470247 0.5387671 -1.364339 0.8729488 -0.5646362 0.1286937 -0.868501 0.1626673 0.6354013 0.832567 -0.2866281 0 0 0 1 -0.4644146 -0.8440368 0.5381433 -1.364339 0.8701815 -0.5704447 0.1296425 -0.8514485 0.1646316 0.6341881 0.8328232 -0.2660896 0 0 0 1 -0.4693491 -0.8407228 0.5374642 -1.364339 0.8671077 -0.5768281 0.1306198 -0.8345108 0.1668412 0.6328147 0.833109 -0.2454576 0 0 0 1 -0.4746671 -0.8370864 0.5367349 -1.364339 0.8637295 -0.5837621 0.1316052 -0.8177821 0.1693005 0.6312749 0.833424 -0.2246558 0 0 0 1 -0.4803403 -0.8331312 0.5359609 -1.364339 0.860049 -0.5912228 0.1325772 -0.8011947 0.1720151 0.6295617 0.833768 -0.20374 0 0 0 1 -0.4863393 -0.8288608 0.5351483 -1.364339 0.8560681 -0.5991856 0.1335135 -0.7847413 0.1749909 0.6276674 0.8341405 -0.1827195 0 0 0 1 -0.492635 -0.8242787 0.5343039 -1.364339 0.8517883 -0.6076266 0.1343908 -0.7684362 0.1782349 0.6255832 0.8345408 -0.1615833 0 0 0 1 -0.4991966 -0.8193894 0.5334355 -1.364339 0.8472121 -0.6165209 0.1351846 -0.7522342 0.1817545 0.6233 0.834968 -0.1403674 0 0 0 1 -0.5059937 -0.8141973 0.5325516 -1.364339 0.8423413 -0.6258444 0.1358695 -0.7361684 0.1855582 0.6208071 0.8354209 -0.119049 0 0 0 1 -0.5129942 -0.8087081 0.5316617 -1.364339 0.8371786 -0.6355718 0.136419 -0.7202204 0.1896551 0.6180936 0.835898 -0.09764165 0 0 0 1 -0.5201663 -0.8029279 0.5307763 -1.364339 0.8317272 -0.6456783 0.1368058 -0.7043647 0.1940547 0.6151473 0.8363974 -0.07616597 0 0 0 1 -0.5274773 -0.7968637 0.5299068 -1.364339 0.82599 -0.6561393 0.1370013 -0.6886541 0.1987678 0.6119552 0.8369165 -0.05458432 0 0 0 1 -0.534893 -0.7905245 0.529066 -1.364339 0.8199714 -0.6669286 0.1369762 -0.67304 0.2038053 0.6085039 0.8374524 -0.03293204 0 0 0 1 -0.5423804 -0.7839196 0.5282676 -1.364339 0.8136755 -0.6780216 0.1367002 -0.6575277 0.2091791 0.6047782 0.8380014 -0.01120716 0 0 0 1 -0.5499043 -0.7770603 0.5275262 -1.364339 0.8071077 -0.689392 0.1361422 -0.6421928 0.2149014 0.6007627 0.838559 0.01064318 0 0 0 1 -0.5574291 -0.76996 0.526858 -1.364339 0.8002742 -0.701013 0.1352702 -0.6269286 0.2209848 0.5964413 0.83912 0.0325436 0 0 0 1 -0.5649191 -0.7626334 0.5262801 -1.364339 0.7931813 -0.7128584 0.1340516 -0.6118057 0.2274426 0.5917965 0.839678 0.05454081 0 0 0 1 -0.5723377 -0.7550974 0.5258105 -1.364339 0.7858365 -0.7249006 0.132453 -0.5969327 0.2342879 0.5868108 0.8402258 0.07670909 0 0 0 1 -0.5796474 -0.7473714 0.5254686 -1.364339 0.7782482 -0.7371117 0.1304408 -0.5822468 0.2415345 0.5814655 0.8407543 0.09899968 0 0 0 1 -0.5868102 -0.7394772 0.5252743 -1.364339 0.7704256 -0.7494628 0.1279805 -0.5677153 0.2491958 0.5757419 0.8412536 0.1213907 0 0 0 1 -0.5937871 -0.7314397 0.5252488 -1.364339 0.7623788 -0.7619238 0.1250374 -0.5533879 0.2572853 0.5696209 0.8417121 0.1439145 0 0 0 1 -0.6005391 -0.7232858 0.5254136 -1.364339 0.7541185 -0.7744645 0.1215767 -0.5396714 0.2658163 0.5630827 0.8421161 0.1668134 0 0 0 1 -0.6070259 -0.7150464 0.5257909 -1.364339 0.7456565 -0.787053 0.1175632 -0.526262 0.2748019 0.5561079 0.8424504 0.1898925 0 0 0 1 -0.6132061 -0.7067559 0.5264034 -1.364339 0.7370061 -0.7996554 0.1129618 -0.513183 0.2842542 0.5486776 0.8426974 0.2131625 0 0 0 1 -0.6190385 -0.6984514 0.5272737 -1.364339 0.7281804 -0.8122377 0.1077376 -0.500632 0.2941851 0.5407729 0.8428375 0.2367207 0 0 0 1 -0.6244801 -0.6901748 0.5284242 -1.364339 0.7191942 -0.8247634 0.101856 -0.4883832 0.3046055 0.5323759 0.8428482 0.2604358 0 0 0 1 -0.6294877 -0.6819712 0.5298771 -1.364339 0.7100629 -0.8371941 0.09528251 -0.4764501 0.3155251 0.5234702 0.8427048 0.2843133 0 0 0 1 -0.6340171 -0.6738905 0.5316534 -1.364339 0.7008027 -0.8494902 0.08798365 -0.4651254 0.3269526 0.5140408 0.8423796 0.3084846 0 0 0 1 -0.6380234 -0.6659864 0.5337732 -1.364339 0.6914307 -0.8616095 0.07992642 -0.4541531 0.3388952 0.5040745 0.8418419 0.332815 0 0 0 1 -0.6414602 -0.6583177 0.5362545 -1.364339 0.6819651 -0.8735073 0.07107881 -0.4435362 0.3513582 0.4935613 0.8410581 0.3573048 0 0 0 1 -0.644281 -0.6509473 0.5391135 -1.364339 0.6724244 -0.8851367 0.06141008 -0.4336627 0.3643454 0.4824941 0.8399912 0.3821028 0 0 0 1 -0.6464379 -0.643943 0.5423633 -1.364339 0.6628284 -0.896448 0.05089072 -0.4242593 0.3778582 0.4708697 0.8386012 0.4070781 0 0 0 1 -0.6478825 -0.6373767 0.5460137 -1.364339 0.6531968 -0.9073891 0.03949287 -0.4153172 0.391896 0.4586892 0.8368448 0.4322244 0 0 0 1 -0.6485651 -0.6313254 0.5500703 -1.364339 0.643551 -0.9179041 0.02719047 -0.4073269 0.406455 0.4459597 0.8346755 0.4576885 0 0 0 1 -0.6484357 -0.6258697 0.5545343 -1.364339 0.633912 -0.9279351 0.01395954 -0.4000453 0.4215293 0.4326934 0.8320436 0.4833552 0 0 0 1 -0.6474428 -0.6210952 0.559401 -1.364339 0.6243026 -0.9374191 -2.21496e-4 -0.393425 0.4371091 0.4189105 0.828897 0.5092023 0 0 0 1 -0.6455349 -0.6170896 0.5646596 -1.364339 0.6147444 -0.9462919 -0.01537166 -0.3881383 0.4531822 0.4046381 0.8251806 0.5353553 0 0 0 1 -0.6426592 -0.6139452 0.5702921 -1.364339 0.6052614 -0.9544836 -0.03150687 -0.3841331 0.4697317 0.3899131 0.8208374 0.5617071 0 0 0 1 -0.6387627 -0.6117558 0.5762723 -1.364339 0.5958769 -0.9619217 -0.04863985 -0.3812808 0.4867373 0.3747816 0.815809 0.5882051 0 0 0 1 -0.6337914 -0.610617 0.5825656 -1.364339 0.586615 -0.9685296 -0.0667796 -0.3806781 0.5041741 0.3593008 0.8100356 0.6148604 0 0 0 1 -0.6276916 -0.6106244 0.5891275 -1.364339 0.5774996 -0.9742271 -0.08593117 -0.3817764 0.5220132 0.3435391 0.8034579 0.6414785 0 0 0 1 -0.6204091 -0.6118733 0.5959029 -1.364339 0.5685552 -0.97893 -0.1060951 -0.3841312 0.5402201 0.3275776 0.7960172 0.6680329 0 0 0 1 -0.6118891 -0.614457 0.6028259 -1.364339 0.5598074 -0.9825493 -0.127267 -0.388246 0.5587553 0.3115117 0.7876572 0.6943912 0 0 0 1 -0.6020783 -0.6184636 0.6098185 -1.364339 0.5512803 -0.9849935 -0.1494373 -0.393655 0.5775741 0.2954496 0.778325 0.7205045 0 0 0 1 -0.5909227 -0.6239768 0.6167904 -1.364339 0.5429998 -0.9861662 -0.1725902 -0.3999506 0.5966253 0.2795155 0.7679726 0.7464258 0 0 0 1 -0.5783697 -0.6310713 0.6236387 -1.364339 0.5349907 -0.9859681 -0.196704 -0.4074357 0.6158519 0.2638479 0.7565594 0.7720407 0 0 0 1 -0.5643678 -0.6398118 0.6302474 -1.364339 0.5272785 -0.9842959 -0.2217498 -0.4159031 0.6351902 0.2486009 0.7440531 0.7973433 0 0 0 1 -0.548867 -0.6502494 0.636488 -1.364339 0.5198882 -0.9810433 -0.2476913 -0.4250005 0.6545697 0.2339435 0.7304326 0.8224289 0 0 0 1 -0.5318195 -0.6624199 0.6422194 -1.364339 0.5128452 -0.9761012 -0.2744841 -0.4349128 0.6739125 0.2200598 0.7156903 0.8472112 0 0 0 1 -0.5131798 -0.6763398 0.6472889 -1.364339 0.5061747 -0.9693577 -0.302075 -0.445583 0.6931334 0.207147 0.699834 0.8716749 0 0 0 1 -0.4929061 -0.6920037 0.6515332 -1.364339 0.4999018 -0.9606996 -0.3304013 -0.4567379 0.712139 0.195415 0.6828904 0.8959211 0 0 0 1 -0.4709601 -0.7093809 0.6547804 -1.364339 0.4940512 -0.9500119 -0.3593906 -0.4685202 0.7308285 0.1850836 0.6649067 0.9198738 0 0 0 1 -0.4473083 -0.7284124 0.6568514 -1.364339 0.4886476 -0.9371793 -0.3889594 -0.4808729 0.7490921 0.1763809 0.6459541 0.9435361 0 0 0 1 -0.4219229 -0.7490075 0.6575631 -1.364339 0.4837153 -0.922087 -0.4190131 -0.4935813 0.7668121 0.1695385 0.6261299 0.9670073 0 0 0 1 -0.3947828 -0.7710408 0.6567317 -1.364339 0.4792782 -0.9046217 -0.4494445 -0.5067305 0.7838618 0.1647891 0.60556 0.9902362 0 0 0 1 -0.3658736 -0.7943507 0.6541765 -1.364339 0.47536 -0.8846726 -0.4801341 -0.5209397 0.800106 0.1623611 0.5844007 1.012822 0 0 0 1 -0.3351904 -0.818736 0.649724 -1.364339 0.4719841 -0.8621333 -0.5109488 -0.5359951 0.815401 0.162473 0.5628409 1.034829 0 0 0 1 -0.3027376 -0.8439559 0.6432136 -1.364339 0.4691737 -0.836902 -0.5417413 -0.5521109 0.829594 0.1653282 0.5411029 1.056094 0 0 0 1 -0.2685311 -0.8697279 0.6345035 -1.364339 0.4669505 -0.8088858 -0.5723503 -0.5700495 0.8425251 0.1711055 0.5194423 1.07583 0 0 0 1 -0.2325995 -0.8957297 0.6234763 -1.364339 0.4653365 -0.7780004 -0.6025988 -0.5889773 0.8540256 0.1799545 0.4981484 1.094588 0 0 0 1 -0.1949852 -0.9216006 0.6100457 -1.364339 0.4643532 -0.7441729 -0.6322953 -0.6089641 0.8639196 0.1919861 0.4775424 1.112268 0 0 0 1 -0.1557467 -0.9469448 0.5941646 -1.364339 0.464021 -0.7073451 -0.6612322 -0.6305025 0.8720251 0.2072641 0.457974 1.128012 0 0 0 1 -0.03528593 -1.199135 0.01399405 -1.364339 0.585228 -0.03841425 -0.8102367 -0.6528898 0.8101009 -0.02448029 0.5859356 1.142872 0 0 0 1 -0.02965669 -1.199429 0.008488774 -1.364337 0.581816 -0.02900073 -0.8129613 -0.6763113 0.8127797 -0.023005 0.5822557 1.156832 0 0 0 1 -0.02516357 -1.19961 0.00414568 -1.364334 0.5724078 -0.02136977 -0.8197756 -0.6774498 0.819583 -0.02190655 0.5726697 1.156641 0 0 0 1 -0.02162443 -1.199719 7.61964e-4 -1.36433 0.5582099 -0.01524728 -0.8296024 -0.6788771 0.8294181 -0.02101721 0.5583539 1.156401 0 0 0 1 -0.01889786 -1.199784 -0.001814027 -1.364325 0.54043 -0.01042598 -0.8413441 -0.6804967 0.8411769 -0.02025595 0.5404967 1.156129 0 0 0 1 -0.01686832 -1.199821 -0.003701178 -1.364321 0.5203239 -0.006740642 -0.8539505 -0.6822126 0.8538025 -0.01959662 0.520341 1.155841 0 0 0 1 -0.01543436 -1.199842 -0.005001295 -1.364316 0.4992203 -0.004046549 -0.8664685 -0.6839284 0.8663378 -0.01904417 0.4992065 1.155553 0 0 0 1 -0.01449888 -1.199854 -0.005810737 -1.364311 0.4785308 -0.002203386 -0.8780688 -0.6855481 0.8779512 -0.01861395 0.478499 1.155281 0 0 0 1 -0.0139632 -1.19986 -0.006229728 -1.364308 0.4597397 -0.001064651 -0.8880532 -0.6869753 0.887944 -0.01831694 0.4596983 1.155041 0 0 0 1 -0.01372271 -1.199863 -0.006369149 -1.364305 0.4443867 -4.71033e-4 -0.895835 -0.6881139 0.8957301 -0.01814838 0.4443411 1.15485 0 0 0 1 -0.01366567 -1.199864 -0.006352232 -1.364303 0.434037 -2.50484e-4 -0.900895 -0.6888676 0.9007915 -0.01808213 0.4339905 1.154723 0 0 0 1 -0.01367396 -1.199864 -0.006315139 -1.364302 0.4302482 -2.18964e-4 -0.9027106 -0.6891402 0.9026072 -0.01807284 0.4302018 1.154677 0 0 0 1 -0.02458125 -1.199635 0.002094031 -1.364303 0.4554134 -0.01567521 -0.8901842 -0.6886651 0.8899409 -0.02511382 0.4555958 1.15468 0 0 0 1 -0.05461616 -1.197863 0.02400327 -1.364306 0.5210327 -0.05879755 -0.8521292 -0.6873917 0.8517877 -0.04084023 0.5227806 1.154703 0 0 0 1 -0.09709799 -1.192702 0.05193732 -1.364311 0.6107177 -0.1208453 -0.7854186 -0.6855481 0.7858728 -0.05345223 0.6167819 1.154763 0 0 0 1 -0.1423523 -1.184034 0.07854471 -1.364317 0.7075907 -0.1883167 -0.6889762 -0.6833624 0.6921354 -0.05099983 0.7205153 1.154881 0 0 0 1 -0.1799016 -1.17426 0.1003711 -1.364324 0.7967725 -0.2457554 -0.5685176 -0.6810627 0.5768789 -0.02676516 0.8165251 1.155076 0 0 0 1 -0.2024367 -1.166369 0.1195215 -1.36433 0.8679457 -0.2815206 -0.4377591 -0.6788771 0.4535305 0.01814359 0.8911125 1.155367 0 0 0 1 -0.2100926 -1.160781 0.1419795 -1.364335 0.9167861 -0.2944429 -0.315115 -0.6770335 0.3396537 0.07675376 0.9383731 1.155772 0 0 0 1 -0.2129795 -1.153808 0.1736214 -1.364338 0.944208 -0.2978796 -0.2164528 -0.6757601 0.2512194 0.1414016 0.9607308 1.156312 0 0 0 1 -0.2306205 -1.138241 0.21702 -1.364339 0.9530793 -0.3181757 -0.1460733 -0.6752849 0.1960976 0.2077797 0.965176 1.157005 0 0 0 1 -0.2683923 -1.110351 0.2679534 -1.344004 0.9503456 -0.3597744 -0.08340454 -0.7132585 0.1575093 0.2787158 0.9598148 1.164521 0 0 0 1 -0.3128774 -1.073862 0.3182574 -1.290392 0.9427776 -0.3999182 -0.01024473 -0.8133705 0.115232 0.3562087 0.9479489 1.18305 0 0 0 1 -0.3586688 -1.032336 0.3623194 -1.214597 0.9311924 -0.4281744 0.07460649 -0.9549081 0.06509745 0.4369776 0.9290632 1.208887 0 0 0 1 -0.3996181 -0.9915308 0.3969558 -1.127709 0.9166504 -0.436543 0.1655663 -1.117159 0.007603468 0.5160394 0.9027811 1.23833 0 0 0 1 -0.4311328 -0.9570465 0.4219673 -1.040821 0.9007813 -0.4241083 0.2523589 -1.279409 -0.05213279 0.5866805 0.8707803 1.267677 0 0 0 1 -0.4516917 -0.9321005 0.4389003 -0.9650252 0.885872 -0.3985287 0.3239379 -1.420947 -0.1058569 0.6421553 0.8381113 1.293224 0 0 0 1 -0.4626345 -0.9172819 0.4490651 -0.9114135 0.8747361 -0.373397 0.371502 -1.521059 -0.1442438 0.6776196 0.8126048 1.311267 0 0 0 1 -0.466106 -0.912252 0.452577 -0.891078 0.8703857 -0.3627285 0.3886637 -1.559032 -0.1586639 0.69009 0.8025674 1.318104 0 0 0 1 -0.466106 -0.912252 0.452577 -0.891078 0.8703857 -0.3627285 0.3886637 -1.559032 -0.1586639 0.69009 0.8025674 1.318104 0 0 0 1 + + + + + + + + LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR + + + + + + + + + + + + + + + + + + + -0.466106 -0.912252 0.452577 -0.891078 0.8703857 -0.3627285 0.3886637 -1.559032 -0.1586639 0.69009 0.8025674 1.318104 0 0 0 1 + + + + + + + + + + + 1 4.47035e-8 -5.96046e-8 0 -1.49012e-8 0.8026474 -0.5964538 -0.3749996 0 0.5964539 0.8026474 0.1250001 0 0 0 1 + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/models/error.obj b/src/main/resources/assets/avatarmod/models/error.obj new file mode 100644 index 0000000000..e948f3e606 --- /dev/null +++ b/src/main/resources/assets/avatarmod/models/error.obj @@ -0,0 +1,2909 @@ +# Blender v2.76 (sub 0) OBJ File: 'error.blend' +# www.blender.org +o Text_Mesh +v -0.125000 -0.000000 -0.643408 +v -0.125000 -0.000000 -0.745792 +v -0.125000 0.234222 -0.745792 +v -0.125000 0.247672 -0.751697 +v -0.125000 0.259659 -0.758142 +v -0.125000 0.270238 -0.765055 +v -0.125000 0.279466 -0.772362 +v -0.125000 0.287399 -0.779991 +v -0.125000 0.294092 -0.787868 +v -0.125000 0.299602 -0.795920 +v -0.125000 0.303984 -0.804075 +v -0.125000 0.307295 -0.812259 +v -0.125000 0.309591 -0.820399 +v -0.125000 0.310927 -0.828422 +v -0.125000 0.311360 -0.836255 +v -0.125000 0.311317 -0.840189 +v -0.125000 0.311185 -0.843943 +v -0.125000 0.310966 -0.847541 +v -0.125000 0.310659 -0.851008 +v -0.125000 0.310265 -0.854367 +v -0.125000 0.309783 -0.857644 +v -0.125000 0.309213 -0.860862 +v -0.125000 0.308555 -0.864046 +v -0.125000 0.307810 -0.867220 +v -0.125000 0.306978 -0.870409 +v -0.125000 0.306057 -0.873637 +v -0.125000 0.305049 -0.876928 +v -0.125000 0.394109 -0.895161 +v -0.125000 0.395306 -0.892161 +v -0.125000 0.396437 -0.889103 +v -0.125000 0.397495 -0.885957 +v -0.125000 0.398473 -0.882694 +v -0.125000 0.399363 -0.879286 +v -0.125000 0.400158 -0.875701 +v -0.125000 0.400850 -0.871913 +v -0.125000 0.401434 -0.867890 +v -0.125000 0.401900 -0.863605 +v -0.125000 0.402242 -0.859027 +v -0.125000 0.402453 -0.854128 +v -0.125000 0.402524 -0.848878 +v -0.125000 0.401943 -0.838689 +v -0.125000 0.400210 -0.828493 +v -0.125000 0.397342 -0.818340 +v -0.125000 0.393356 -0.808283 +v -0.125000 0.388270 -0.798371 +v -0.125000 0.382100 -0.788657 +v -0.125000 0.374864 -0.779191 +v -0.125000 0.366578 -0.770025 +v -0.125000 0.357260 -0.761209 +v -0.125000 0.346927 -0.752795 +v -0.125000 0.335595 -0.744834 +v -0.125000 0.323282 -0.737377 +v -0.125000 0.323282 -0.734572 +v -0.125000 0.392707 -0.727560 +v -0.125000 0.392707 -0.643408 +v -0.125000 -0.009818 -0.368513 +v -0.125000 -0.008252 -0.392849 +v -0.125000 -0.003607 -0.416576 +v -0.125000 0.004043 -0.439407 +v -0.125000 0.014623 -0.461054 +v -0.125000 0.028056 -0.481231 +v -0.125000 0.044267 -0.499649 +v -0.125000 0.063181 -0.516023 +v -0.125000 0.084723 -0.530063 +v -0.125000 0.108816 -0.541484 +v -0.125000 0.135386 -0.549997 +v -0.125000 0.164356 -0.555316 +v -0.125000 0.195652 -0.557153 +v -0.125000 0.227270 -0.555316 +v -0.125000 0.256509 -0.549997 +v -0.125000 0.283299 -0.541484 +v -0.125000 0.307568 -0.530063 +v -0.125000 0.329247 -0.516023 +v -0.125000 0.348264 -0.499649 +v -0.125000 0.364550 -0.481231 +v -0.125000 0.378032 -0.461054 +v -0.125000 0.388642 -0.439407 +v -0.125000 0.396307 -0.416576 +v -0.125000 0.400958 -0.392849 +v -0.125000 0.402525 -0.368513 +v -0.125000 0.400958 -0.344178 +v -0.125000 0.396307 -0.320451 +v -0.125000 0.388642 -0.297620 +v -0.125000 0.378032 -0.275973 +v -0.125000 0.364550 -0.255796 +v -0.125000 0.348264 -0.237377 +v -0.125000 0.329247 -0.221004 +v -0.125000 0.307568 -0.206963 +v -0.125000 0.283299 -0.195543 +v -0.125000 0.256509 -0.187029 +v -0.125000 0.227270 -0.181710 +v -0.125000 0.195652 -0.179874 +v -0.125000 0.164356 -0.181710 +v -0.125000 0.135386 -0.187029 +v -0.125000 0.108816 -0.195543 +v -0.125000 0.084723 -0.206963 +v -0.125000 0.063181 -0.221004 +v -0.125000 0.044267 -0.237377 +v -0.125000 0.028056 -0.255796 +v -0.125000 0.014623 -0.275973 +v -0.125000 0.004043 -0.297620 +v -0.125000 -0.003607 -0.320451 +v -0.125000 -0.008252 -0.344178 +v -0.125000 0.074334 -0.368513 +v -0.125000 0.075315 -0.355675 +v -0.125000 0.078207 -0.343826 +v -0.125000 0.082935 -0.332990 +v -0.125000 0.089424 -0.323191 +v -0.125000 0.097598 -0.314454 +v -0.125000 0.107381 -0.306802 +v -0.125000 0.118698 -0.300261 +v -0.125000 0.131474 -0.294855 +v -0.125000 0.145632 -0.290607 +v -0.125000 0.161099 -0.287543 +v -0.125000 0.177797 -0.285687 +v -0.125000 0.195652 -0.285063 +v -0.125000 0.213682 -0.285687 +v -0.125000 0.230553 -0.287543 +v -0.125000 0.246187 -0.290607 +v -0.125000 0.260506 -0.294855 +v -0.125000 0.273432 -0.300261 +v -0.125000 0.284888 -0.306802 +v -0.125000 0.294795 -0.314454 +v -0.125000 0.303075 -0.323191 +v -0.125000 0.309651 -0.332990 +v -0.125000 0.314445 -0.343826 +v -0.125000 0.317378 -0.355675 +v -0.125000 0.318373 -0.368513 +v -0.125000 0.317378 -0.381351 +v -0.125000 0.314445 -0.393200 +v -0.125000 0.309651 -0.404037 +v -0.125000 0.303075 -0.413836 +v -0.125000 0.294795 -0.422573 +v -0.125000 0.284888 -0.430224 +v -0.125000 0.273432 -0.436765 +v -0.125000 0.260506 -0.442172 +v -0.125000 0.246187 -0.446419 +v -0.125000 0.230553 -0.449483 +v -0.125000 0.213682 -0.451339 +v -0.125000 0.195652 -0.451963 +v -0.125000 0.177797 -0.451339 +v -0.125000 0.161099 -0.449483 +v -0.125000 0.145632 -0.446419 +v -0.125000 0.131474 -0.442172 +v -0.125000 0.118698 -0.436765 +v -0.125000 0.107381 -0.430224 +v -0.125000 0.097598 -0.422573 +v -0.125000 0.089424 -0.413836 +v -0.125000 0.082935 -0.404037 +v -0.125000 0.078207 -0.393200 +v -0.125000 0.075315 -0.381351 +v -0.125000 0.000000 0.101332 +v -0.125000 -0.000000 -0.001052 +v -0.125000 0.234222 -0.001052 +v -0.125000 0.247672 -0.006957 +v -0.125000 0.259659 -0.013402 +v -0.125000 0.270238 -0.020315 +v -0.125000 0.279466 -0.027622 +v -0.125000 0.287399 -0.035251 +v -0.125000 0.294092 -0.043128 +v -0.125000 0.299602 -0.051180 +v -0.125000 0.303984 -0.059335 +v -0.125000 0.307295 -0.067518 +v -0.125000 0.309591 -0.075658 +v -0.125000 0.310927 -0.083682 +v -0.125000 0.311360 -0.091515 +v -0.125000 0.311317 -0.095449 +v -0.125000 0.311185 -0.099203 +v -0.125000 0.310966 -0.102801 +v -0.125000 0.310659 -0.106267 +v -0.125000 0.310265 -0.109627 +v -0.125000 0.309783 -0.112903 +v -0.125000 0.309213 -0.116121 +v -0.125000 0.308555 -0.119305 +v -0.125000 0.307810 -0.122480 +v -0.125000 0.306978 -0.125669 +v -0.125000 0.306057 -0.128897 +v -0.125000 0.305049 -0.132188 +v -0.125000 0.394109 -0.150421 +v -0.125000 0.395306 -0.147421 +v -0.125000 0.396437 -0.144363 +v -0.125000 0.397495 -0.141217 +v -0.125000 0.398473 -0.137954 +v -0.125000 0.399363 -0.134545 +v -0.125000 0.400158 -0.130961 +v -0.125000 0.400851 -0.127172 +v -0.125000 0.401434 -0.123149 +v -0.125000 0.401900 -0.118864 +v -0.125000 0.402242 -0.114286 +v -0.125000 0.402453 -0.109387 +v -0.125000 0.402525 -0.104137 +v -0.125000 0.401943 -0.093948 +v -0.125000 0.400210 -0.083752 +v -0.125000 0.397342 -0.073600 +v -0.125000 0.393356 -0.063542 +v -0.125000 0.388270 -0.053631 +v -0.125000 0.382100 -0.043917 +v -0.125000 0.374864 -0.034451 +v -0.125000 0.366578 -0.025284 +v -0.125000 0.357260 -0.016469 +v -0.125000 0.346927 -0.008055 +v -0.125000 0.335595 -0.000094 +v -0.125000 0.323282 0.007363 +v -0.125000 0.323282 0.010168 +v -0.125000 0.392707 0.017181 +v -0.125000 0.392707 0.101332 +v -0.125000 0.000000 0.407083 +v -0.125000 0.000000 0.304698 +v -0.125000 0.234222 0.304698 +v -0.125000 0.247672 0.298794 +v -0.125000 0.259659 0.292348 +v -0.125000 0.270238 0.285436 +v -0.125000 0.279466 0.278128 +v -0.125000 0.287399 0.270500 +v -0.125000 0.294092 0.262623 +v -0.125000 0.299602 0.254570 +v -0.125000 0.303984 0.246416 +v -0.125000 0.307295 0.238232 +v -0.125000 0.309591 0.230092 +v -0.125000 0.310927 0.222069 +v -0.125000 0.311360 0.214236 +v -0.125000 0.311317 0.210302 +v -0.125000 0.311185 0.206548 +v -0.125000 0.310966 0.202950 +v -0.125000 0.310659 0.199483 +v -0.125000 0.310265 0.196124 +v -0.125000 0.309783 0.192847 +v -0.125000 0.309213 0.189629 +v -0.125000 0.308555 0.186445 +v -0.125000 0.307810 0.183270 +v -0.125000 0.306978 0.180082 +v -0.125000 0.306057 0.176854 +v -0.125000 0.305049 0.173562 +v -0.125000 0.394109 0.155330 +v -0.125000 0.395306 0.158329 +v -0.125000 0.396437 0.161388 +v -0.125000 0.397495 0.164534 +v -0.125000 0.398473 0.167796 +v -0.125000 0.399363 0.171205 +v -0.125000 0.400158 0.174790 +v -0.125000 0.400851 0.178578 +v -0.125000 0.401434 0.182601 +v -0.125000 0.401900 0.186886 +v -0.125000 0.402242 0.191464 +v -0.125000 0.402453 0.196363 +v -0.125000 0.402525 0.201613 +v -0.125000 0.401943 0.211802 +v -0.125000 0.400210 0.221998 +v -0.125000 0.397342 0.232151 +v -0.125000 0.393356 0.242208 +v -0.125000 0.388270 0.252120 +v -0.125000 0.382100 0.261834 +v -0.125000 0.374864 0.271300 +v -0.125000 0.366578 0.280466 +v -0.125000 0.357260 0.289282 +v -0.125000 0.346927 0.297696 +v -0.125000 0.335595 0.305657 +v -0.125000 0.323282 0.313114 +v -0.125000 0.323282 0.315919 +v -0.125000 0.392707 0.322931 +v -0.125000 0.392707 0.407083 +v -0.125000 0.000000 0.829944 +v -0.125000 0.000000 0.503857 +v -0.125000 0.086957 0.503857 +v -0.125000 0.086957 0.726157 +v -0.125000 0.225807 0.726157 +v -0.125000 0.225806 0.543829 +v -0.125000 0.312763 0.543829 +v -0.125000 0.312763 0.726157 +v -0.125000 0.432679 0.726157 +v -0.125000 0.432679 0.511571 +v -0.125000 0.518934 0.511571 +v -0.125000 0.518934 0.829944 +v 0.125000 0.364550 -0.255796 +v 0.125000 0.348264 -0.237377 +v 0.125000 0.311185 -0.099203 +v 0.125000 0.310966 -0.102801 +v 0.125000 0.014623 -0.461054 +v 0.125000 0.014623 -0.275973 +v 0.125000 0.000000 0.503857 +v 0.125000 0.086957 0.503857 +v 0.125000 0.398473 0.167797 +v 0.125000 0.397342 0.232151 +v 0.125000 0.401900 -0.118864 +v 0.125000 0.400210 -0.083752 +v 0.125000 0.164356 -0.181710 +v 0.125000 0.135386 -0.187029 +v 0.125000 0.294092 -0.043128 +v 0.125000 0.299602 -0.051180 +v 0.125000 0.074334 -0.368513 +v 0.125000 0.075315 -0.381351 +v 0.125000 0.063181 -0.221004 +v 0.125000 0.388642 -0.439407 +v 0.125000 0.396307 -0.416576 +v 0.125000 0.305049 -0.876928 +v 0.125000 0.374864 -0.779191 +v 0.125000 0.305049 0.173562 +v 0.125000 0.357260 0.289282 +v 0.125000 0.306978 -0.125669 +v 0.125000 0.306057 -0.128897 +v 0.125000 0.227270 -0.555316 +v 0.125000 0.256509 -0.549997 +v 0.125000 0.000000 0.407083 +v 0.125000 0.392707 0.407083 +v 0.125000 0.399363 -0.134545 +v 0.125000 0.400158 -0.130961 +v 0.125000 0.401434 -0.867890 +v 0.125000 0.400210 -0.828493 +v 0.125000 0.309783 -0.112903 +v 0.125000 0.335595 -0.000094 +v 0.125000 0.082935 -0.332990 +v 0.125000 0.089424 -0.323191 +v 0.125000 0.131474 -0.442172 +v 0.125000 0.118698 -0.436765 +v 0.125000 0.329247 -0.516023 +v 0.125000 0.329247 -0.221004 +v 0.125000 -0.000000 0.101332 +v 0.125000 -0.000000 -0.001052 +v 0.125000 0.028056 -0.255796 +v 0.125000 0.318373 -0.368513 +v 0.125000 0.260506 -0.442172 +v 0.125000 0.246187 -0.446419 +v 0.125000 0.177797 -0.285687 +v 0.125000 0.195652 -0.285063 +v 0.125000 0.378032 -0.461054 +v 0.125000 0.294795 -0.314454 +v 0.125000 0.303075 -0.323191 +v 0.125000 0.108816 -0.541484 +v 0.125000 0.366578 -0.770025 +v 0.125000 0.310927 0.222069 +v 0.125000 0.311360 0.214236 +v 0.125000 0.305049 -0.132188 +v 0.125000 0.382100 -0.043917 +v 0.125000 0.394109 -0.150421 +v 0.125000 0.393356 -0.063542 +v 0.125000 0.402453 -0.854128 +v 0.125000 0.402524 -0.848878 +v 0.125000 0.270238 0.285436 +v 0.125000 0.279466 0.278128 +v 0.125000 0.323282 0.010168 +v 0.125000 0.392707 0.017181 +v 0.125000 0.084723 -0.530063 +v 0.125000 0.089424 -0.413836 +v 0.125000 0.063181 -0.516023 +v 0.125000 0.084723 -0.206963 +v 0.125000 0.107381 -0.306802 +v 0.125000 0.309783 -0.857644 +v 0.125000 0.335595 -0.744834 +v 0.125000 0.396437 0.161388 +v 0.125000 0.397495 0.164534 +v 0.125000 0.401943 -0.093948 +v 0.125000 0.161099 -0.287543 +v 0.125000 0.388270 -0.053631 +v 0.125000 0.311185 -0.843943 +v 0.125000 0.310966 -0.847541 +v 0.125000 0.311185 0.206548 +v 0.125000 0.323282 0.313114 +v 0.125000 0.306978 -0.870409 +v 0.125000 0.306057 -0.873637 +v 0.125000 0.307568 -0.206963 +v 0.125000 0.314445 -0.343826 +v 0.125000 0.225807 0.726157 +v 0.125000 0.225806 0.543829 +v 0.125000 0.283299 -0.541484 +v 0.125000 0.294795 -0.422573 +v 0.125000 0.309591 -0.820399 +v 0.125000 0.323282 -0.737377 +v 0.125000 0.294092 -0.787868 +v 0.125000 0.299602 -0.795920 +v 0.125000 0.309591 0.230092 +v 0.125000 0.309213 0.189629 +v 0.125000 0.308555 0.186445 +v 0.125000 0.382100 0.261834 +v 0.125000 0.374864 0.271300 +v 0.125000 0.402453 0.196363 +v 0.125000 0.401943 0.211802 +v 0.125000 0.311317 -0.095449 +v 0.125000 0.323282 0.007363 +v 0.125000 0.402242 0.191464 +v 0.125000 -0.000000 -0.643408 +v 0.125000 -0.000000 -0.745792 +v 0.125000 0.294092 0.262623 +v 0.125000 0.309213 -0.116121 +v 0.125000 0.308555 -0.119305 +v 0.125000 0.378032 -0.275973 +v 0.125000 0.323282 0.315919 +v 0.125000 -0.003607 -0.416576 +v 0.125000 -0.008252 -0.344178 +v 0.125000 0.306057 0.176854 +v 0.125000 0.346927 0.297696 +v 0.125000 0.259659 -0.758142 +v 0.125000 0.259659 0.292348 +v 0.125000 0.307295 -0.067518 +v 0.125000 0.346927 -0.008055 +v 0.125000 0.195652 -0.179874 +v 0.125000 0.400958 -0.344178 +v 0.125000 0.287399 -0.035251 +v 0.125000 0.400158 0.174790 +v 0.125000 0.400210 0.221998 +v 0.125000 0.310927 -0.083682 +v 0.125000 0.311360 -0.091515 +v 0.125000 0.402242 -0.114286 +v 0.125000 0.402453 -0.109387 +v 0.125000 0.195652 -0.557153 +v 0.125000 0.366578 0.280466 +v 0.125000 0.396437 -0.144363 +v 0.125000 0.397495 -0.141217 +v 0.125000 0.395306 -0.892161 +v 0.125000 0.393356 -0.808283 +v 0.125000 0.395306 0.158329 +v 0.125000 0.393356 0.242208 +v 0.125000 0.396307 -0.320451 +v 0.125000 0.097598 -0.314454 +v 0.125000 0.399363 -0.879286 +v 0.125000 0.397342 -0.818340 +v 0.125000 0.004043 -0.297620 +v 0.125000 0.145632 -0.446419 +v 0.125000 0.213682 -0.285687 +v 0.125000 0.247672 -0.006957 +v 0.125000 0.273432 -0.436765 +v 0.125000 0.309651 -0.332990 +v 0.125000 0.398473 -0.137954 +v 0.125000 0.397342 -0.073600 +v 0.125000 0.357260 -0.761209 +v 0.125000 0.000000 0.304698 +v 0.125000 0.401943 -0.838689 +v 0.125000 0.299602 0.254570 +v 0.125000 0.097598 -0.422573 +v 0.125000 -0.009818 -0.368513 +v 0.125000 -0.008252 -0.392849 +v 0.125000 0.082935 -0.404037 +v 0.125000 0.366578 -0.025284 +v 0.125000 0.357260 -0.016469 +v 0.125000 0.164356 -0.555316 +v 0.125000 0.177797 -0.451339 +v 0.125000 0.432679 0.726157 +v 0.125000 0.518934 0.511571 +v 0.125000 0.307810 -0.867220 +v 0.125000 0.346927 -0.752795 +v 0.125000 0.312763 0.726157 +v 0.125000 0.398473 -0.882694 +v 0.125000 0.310966 0.202950 +v 0.125000 0.309783 0.192847 +v 0.125000 0.335595 0.305657 +v 0.125000 0.317378 -0.355675 +v 0.125000 0.307810 0.183271 +v 0.125000 0.311317 -0.840189 +v 0.125000 0.287399 -0.779991 +v 0.125000 0.234222 -0.745792 +v 0.125000 0.000000 0.829944 +v 0.125000 0.402525 0.201613 +v 0.125000 -0.003607 -0.320451 +v 0.125000 0.310659 -0.106267 +v 0.125000 0.310265 -0.109627 +v 0.125000 0.401434 -0.123149 +v 0.125000 0.108816 -0.195543 +v 0.125000 0.399363 0.171205 +v 0.125000 0.303984 -0.059335 +v 0.125000 0.400958 -0.392849 +v 0.125000 0.402525 -0.368513 +v 0.125000 0.392707 0.101332 +v 0.125000 0.307568 -0.530063 +v 0.125000 0.323282 -0.734572 +v 0.125000 0.400851 -0.127172 +v 0.125000 0.396437 -0.889103 +v 0.125000 0.400850 -0.871913 +v 0.125000 0.107381 -0.430224 +v 0.125000 0.234222 -0.001052 +v 0.125000 0.230553 -0.287543 +v 0.125000 0.230553 -0.449483 +v 0.125000 0.213682 -0.451339 +v 0.125000 0.314445 -0.393200 +v 0.125000 0.309651 -0.404037 +v 0.125000 0.234222 0.304698 +v 0.125000 0.388270 -0.798371 +v 0.125000 0.382100 -0.788657 +v 0.125000 0.307295 0.238232 +v 0.125000 0.401900 -0.863605 +v 0.125000 0.402242 -0.859027 +v 0.125000 0.518934 0.829944 +v 0.125000 0.247672 0.298794 +v 0.125000 0.392707 -0.727560 +v 0.125000 0.028056 -0.481231 +v 0.125000 0.044267 -0.499649 +v 0.125000 0.394109 0.155330 +v 0.125000 0.309213 -0.860862 +v 0.125000 0.308555 -0.864046 +v 0.125000 0.310927 -0.828422 +v 0.125000 0.397495 -0.885957 +v 0.125000 0.312763 0.543829 +v 0.125000 0.310265 0.196124 +v 0.125000 0.311360 -0.836255 +v 0.125000 0.388270 0.252120 +v 0.125000 0.279466 -0.772362 +v 0.125000 0.401434 0.182601 +v 0.125000 0.401900 0.186886 +v 0.125000 0.086957 0.726157 +v 0.125000 0.392707 0.322931 +v 0.125000 0.270238 -0.765055 +v 0.125000 0.388642 -0.297620 +v 0.125000 0.306978 0.180082 +v 0.125000 0.256509 -0.187029 +v 0.125000 0.227270 -0.181710 +v 0.125000 0.309591 -0.075658 +v 0.125000 0.348264 -0.499649 +v 0.125000 0.364550 -0.481231 +v 0.125000 0.395306 -0.147421 +v 0.125000 0.078207 -0.393200 +v 0.125000 0.135386 -0.549997 +v 0.125000 0.078207 -0.343826 +v 0.125000 0.317378 -0.381351 +v 0.125000 0.400158 -0.875701 +v 0.125000 0.270238 -0.020315 +v 0.125000 0.279466 -0.027622 +v 0.125000 0.044267 -0.237377 +v 0.125000 0.161099 -0.449483 +v 0.125000 0.284888 -0.430224 +v 0.125000 0.284888 -0.306802 +v 0.125000 0.118698 -0.300261 +v 0.125000 0.303984 0.246416 +v 0.125000 0.004043 -0.439407 +v 0.125000 0.246187 -0.290607 +v 0.125000 0.310659 -0.851008 +v 0.125000 0.303984 -0.804075 +v 0.125000 0.283299 -0.195543 +v 0.125000 0.392707 -0.643408 +v 0.125000 0.131474 -0.294855 +v 0.125000 0.259659 -0.013402 +v 0.125000 0.195652 -0.451963 +v 0.125000 0.260506 -0.294855 +v 0.125000 0.303075 -0.413836 +v 0.125000 0.432679 0.511571 +v 0.125000 0.310659 0.199483 +v 0.125000 0.400851 0.178578 +v 0.125000 0.075315 -0.355675 +v 0.125000 0.145632 -0.290607 +v 0.125000 0.273432 -0.300261 +v 0.125000 0.310265 -0.854367 +v 0.125000 0.394109 -0.895161 +v 0.125000 0.307295 -0.812259 +v 0.125000 0.247672 -0.751697 +v 0.125000 0.307810 -0.122480 +v 0.125000 0.402525 -0.104137 +v 0.125000 0.287399 0.270500 +v 0.125000 0.374864 -0.034451 +v 0.125000 0.311317 0.210302 +vt 0.426575 0.688748 +vt 0.421208 0.689051 +vt 0.418443 0.689014 +vt 0.415862 0.688904 +vt 0.413450 0.688726 +vt 0.431947 0.687846 +vt 0.411193 0.688483 +vt 0.409074 0.688180 +vt 0.407078 0.687819 +vt 0.437295 0.686354 +vt 0.405190 0.687406 +vt 0.403394 0.686942 +vt 0.401675 0.686434 +vt 0.400018 0.685883 +vt 0.442593 0.684280 +vt 0.398407 0.685294 +vt 0.396827 0.684672 +vt 0.406431 0.638321 +vt 0.447814 0.681632 +vt 0.529446 0.479562 +vt 0.529446 0.683942 +vt 0.485117 0.683942 +vt 0.481422 0.647810 +vt 0.452931 0.678421 +vt 0.457918 0.674655 +vt 0.462747 0.670343 +vt 0.467391 0.665494 +vt 0.471823 0.660116 +vt 0.476017 0.654218 +vt 0.413218 0.640146 +vt 0.411546 0.639758 +vt 0.409866 0.639325 +vt 0.408165 0.638846 +vt 0.479945 0.647810 +vt 0.420086 0.641241 +vt 0.418316 0.641036 +vt 0.416590 0.640785 +vt 0.414895 0.640488 +vt 0.475512 0.601460 +vt 0.472401 0.608460 +vt 0.469006 0.614698 +vt 0.465365 0.620204 +vt 0.461515 0.625007 +vt 0.457497 0.629135 +vt 0.453347 0.632619 +vt 0.449105 0.635486 +vt 0.444809 0.637767 +vt 0.440498 0.639490 +vt 0.436210 0.640685 +vt 0.431984 0.641380 +vt 0.427857 0.641606 +vt 0.425785 0.641583 +vt 0.423808 0.641515 +vt 0.421912 0.641401 +vt 0.475512 0.479562 +vt 0.105673 0.484231 +vt 0.092827 0.484303 +vt 0.080077 0.482747 +vt 0.067743 0.479607 +vt 0.118294 0.482538 +vt 0.055974 0.474928 +vt 0.130536 0.479252 +vt 0.044917 0.468756 +vt 0.142248 0.474400 +vt 0.153274 0.468010 +vt 0.034723 0.461136 +vt 0.163463 0.460111 +vt 0.025540 0.452114 +vt 0.172660 0.450730 +vt 0.017516 0.441734 +vt 0.180713 0.439895 +vt 0.095424 0.440582 +vt 0.010802 0.430043 +vt 0.102206 0.440457 +vt 0.088703 0.439674 +vt 0.108528 0.439294 +vt 0.082563 0.437789 +vt 0.114374 0.437134 +vt 0.077012 0.434968 +vt 0.119730 0.434017 +vt 0.072062 0.431253 +vt 0.187468 0.427634 +vt 0.005545 0.417086 +vt 0.124581 0.429981 +vt 0.067723 0.426684 +vt 0.128910 0.425067 +vt 0.064005 0.421304 +vt 0.132703 0.419315 +vt 0.060919 0.415153 +vt 0.192772 0.413976 +vt 0.001895 0.402908 +vt 0.135945 0.412764 +vt 0.058474 0.408272 +vt 0.138621 0.405454 +vt 0.056683 0.400703 +vt 0.196472 0.398947 +vt 0.000000 0.387554 +vt 0.140715 0.397425 +vt 0.055554 0.392487 +vt 0.142212 0.388717 +vt 0.055099 0.383665 +vt 0.198413 0.382576 +vt 0.000010 0.371071 +vt 0.143096 0.379368 +vt 0.055327 0.374279 +vt 0.198413 0.366260 +vt 0.143319 0.370073 +vt 0.056206 0.365022 +vt 0.001942 0.354868 +vt 0.142859 0.361341 +vt 0.057698 0.356403 +vt 0.196511 0.351047 +vt 0.005633 0.339979 +vt 0.141725 0.353212 +vt 0.059786 0.348461 +vt 0.139928 0.345726 +vt 0.062457 0.341234 +vt 0.192854 0.336983 +vt 0.010930 0.326434 +vt 0.137479 0.338924 +vt 0.065694 0.334761 +vt 0.134389 0.332844 +vt 0.069484 0.329081 +vt 0.187591 0.324117 +vt 0.017680 0.314265 +vt 0.130667 0.327528 +vt 0.073809 0.324232 +vt 0.126324 0.323015 +vt 0.078656 0.320251 +vt 0.121372 0.319345 +vt 0.084010 0.317179 +vt 0.180872 0.312497 +vt 0.025728 0.303501 +vt 0.115819 0.316558 +vt 0.089854 0.315053 +vt 0.109677 0.314694 +vt 0.096175 0.313912 +vt 0.102956 0.313793 +vt 0.172846 0.302171 +vt 0.034922 0.294174 +vt 0.163660 0.293187 +vt 0.045109 0.286313 +vt 0.153464 0.285593 +vt 0.056134 0.279949 +vt 0.142407 0.279436 +vt 0.067844 0.275113 +vt 0.130637 0.274765 +vt 0.080087 0.271834 +vt 0.118303 0.271628 +vt 0.092707 0.270144 +vt 0.105553 0.270073 +vt 0.578122 0.000303 +vt 0.583490 0.000000 +vt 0.586255 0.000037 +vt 0.588836 0.000147 +vt 0.591247 0.000325 +vt 0.572751 0.001205 +vt 0.593505 0.000568 +vt 0.595624 0.000871 +vt 0.597620 0.001232 +vt 0.567403 0.002697 +vt 0.599508 0.001645 +vt 0.601304 0.002109 +vt 0.603022 0.002617 +vt 0.604680 0.003168 +vt 0.562105 0.004772 +vt 0.606291 0.003757 +vt 0.607871 0.004380 +vt 0.598266 0.050730 +vt 0.556884 0.007419 +vt 0.475251 0.209489 +vt 0.475251 0.005109 +vt 0.519581 0.005109 +vt 0.523275 0.041241 +vt 0.551766 0.010630 +vt 0.546780 0.014396 +vt 0.541951 0.018708 +vt 0.537307 0.023557 +vt 0.532875 0.028935 +vt 0.528681 0.034833 +vt 0.591480 0.048905 +vt 0.593152 0.049293 +vt 0.594832 0.049726 +vt 0.596532 0.050205 +vt 0.524753 0.041241 +vt 0.584612 0.047810 +vt 0.586381 0.048016 +vt 0.588107 0.048266 +vt 0.589803 0.048563 +vt 0.529186 0.087591 +vt 0.532296 0.080591 +vt 0.535692 0.074353 +vt 0.539333 0.068847 +vt 0.543182 0.064044 +vt 0.547201 0.059916 +vt 0.551351 0.056432 +vt 0.555592 0.053565 +vt 0.559888 0.051284 +vt 0.564199 0.049561 +vt 0.568487 0.048366 +vt 0.572714 0.047671 +vt 0.576840 0.047445 +vt 0.578913 0.047468 +vt 0.580890 0.047536 +vt 0.582785 0.047651 +vt 0.529186 0.209489 +vt 0.426575 0.479259 +vt 0.421208 0.479562 +vt 0.418443 0.479525 +vt 0.415862 0.479415 +vt 0.413450 0.479237 +vt 0.431947 0.478357 +vt 0.411193 0.478994 +vt 0.409074 0.478691 +vt 0.407078 0.478330 +vt 0.437295 0.476865 +vt 0.405190 0.477917 +vt 0.403394 0.477453 +vt 0.401675 0.476945 +vt 0.400018 0.476394 +vt 0.442593 0.474790 +vt 0.398407 0.475805 +vt 0.396827 0.475182 +vt 0.406431 0.428832 +vt 0.447814 0.472143 +vt 0.529446 0.270073 +vt 0.529446 0.474453 +vt 0.485117 0.474453 +vt 0.481422 0.438321 +vt 0.452931 0.468932 +vt 0.457918 0.465166 +vt 0.462747 0.460854 +vt 0.467391 0.456005 +vt 0.471823 0.450627 +vt 0.476017 0.444729 +vt 0.413218 0.430657 +vt 0.411546 0.430269 +vt 0.409866 0.429836 +vt 0.408165 0.429357 +vt 0.479945 0.438321 +vt 0.420086 0.431752 +vt 0.418316 0.431547 +vt 0.416590 0.431296 +vt 0.414895 0.430999 +vt 0.475512 0.391971 +vt 0.472401 0.398971 +vt 0.469006 0.405209 +vt 0.465365 0.410715 +vt 0.461515 0.415518 +vt 0.457496 0.419646 +vt 0.453347 0.423130 +vt 0.449105 0.425997 +vt 0.444809 0.428278 +vt 0.440498 0.430001 +vt 0.436210 0.431196 +vt 0.431984 0.431891 +vt 0.427857 0.432117 +vt 0.425785 0.432094 +vt 0.423808 0.432026 +vt 0.421912 0.431911 +vt 0.475512 0.270073 +vt 0.000000 0.270073 +vt 0.000000 0.000000 +vt 0.054673 0.044891 +vt 0.167714 0.000000 +vt 0.167714 0.044891 +vt 0.054673 0.107299 +vt 0.054673 0.152555 +vt 0.150721 0.107299 +vt 0.150721 0.152555 +vt 0.054673 0.224818 +vt 0.171778 0.224817 +vt 0.171778 0.270073 +vt 0.559195 0.479865 +vt 0.551062 0.479599 +vt 0.553828 0.479562 +vt 0.548481 0.479709 +vt 0.546070 0.479887 +vt 0.564566 0.480767 +vt 0.543812 0.480130 +vt 0.541693 0.480433 +vt 0.539698 0.480794 +vt 0.569915 0.482259 +vt 0.537809 0.481208 +vt 0.536014 0.481671 +vt 0.534295 0.482179 +vt 0.532638 0.482730 +vt 0.575213 0.484334 +vt 0.531027 0.483319 +vt 0.529446 0.483942 +vt 0.539051 0.530292 +vt 0.580434 0.486981 +vt 0.662066 0.689051 +vt 0.617736 0.484672 +vt 0.662066 0.484672 +vt 0.614042 0.520803 +vt 0.585551 0.490192 +vt 0.590538 0.493958 +vt 0.595366 0.498270 +vt 0.600010 0.503119 +vt 0.604443 0.508497 +vt 0.608636 0.514395 +vt 0.545837 0.528467 +vt 0.544165 0.528855 +vt 0.542485 0.529288 +vt 0.540785 0.529767 +vt 0.612565 0.520803 +vt 0.552706 0.527372 +vt 0.550936 0.527578 +vt 0.549210 0.527828 +vt 0.547515 0.528125 +vt 0.608132 0.567153 +vt 0.605021 0.560153 +vt 0.601626 0.553915 +vt 0.597984 0.548409 +vt 0.594135 0.543606 +vt 0.590116 0.539478 +vt 0.585967 0.535995 +vt 0.581725 0.533127 +vt 0.577429 0.530846 +vt 0.573118 0.529123 +vt 0.568830 0.527928 +vt 0.564604 0.527233 +vt 0.560477 0.527007 +vt 0.558405 0.527030 +vt 0.556427 0.527099 +vt 0.554532 0.527213 +vt 0.608132 0.689051 +vt 0.304086 0.270145 +vt 0.278491 0.271629 +vt 0.291240 0.270073 +vt 0.266157 0.274769 +vt 0.316707 0.271838 +vt 0.254387 0.279447 +vt 0.328950 0.275124 +vt 0.243331 0.285620 +vt 0.340661 0.279976 +vt 0.351688 0.286366 +vt 0.233136 0.293240 +vt 0.361877 0.294265 +vt 0.223953 0.302262 +vt 0.371074 0.303646 +vt 0.215930 0.312642 +vt 0.379127 0.314481 +vt 0.293837 0.313793 +vt 0.209215 0.324333 +vt 0.300619 0.313919 +vt 0.287117 0.314702 +vt 0.306941 0.315082 +vt 0.280976 0.316587 +vt 0.312788 0.317242 +vt 0.275426 0.319408 +vt 0.318144 0.320359 +vt 0.270475 0.323123 +vt 0.385882 0.326742 +vt 0.203958 0.337290 +vt 0.322994 0.324395 +vt 0.266136 0.327692 +vt 0.327323 0.329309 +vt 0.262418 0.333072 +vt 0.331117 0.335061 +vt 0.259332 0.339223 +vt 0.391185 0.340400 +vt 0.200308 0.351468 +vt 0.334359 0.341612 +vt 0.256888 0.346104 +vt 0.337034 0.348922 +vt 0.255096 0.353673 +vt 0.394885 0.355429 +vt 0.198413 0.366821 +vt 0.339128 0.356951 +vt 0.253967 0.361889 +vt 0.340625 0.365659 +vt 0.253512 0.370710 +vt 0.396827 0.371800 +vt 0.198423 0.383304 +vt 0.341510 0.375008 +vt 0.253740 0.380097 +vt 0.396827 0.388116 +vt 0.341733 0.384303 +vt 0.254620 0.389354 +vt 0.200355 0.399508 +vt 0.341272 0.393035 +vt 0.256111 0.397973 +vt 0.394924 0.403330 +vt 0.204046 0.414397 +vt 0.340138 0.401164 +vt 0.258200 0.405915 +vt 0.338341 0.408650 +vt 0.260870 0.413142 +vt 0.391267 0.417393 +vt 0.209343 0.427942 +vt 0.335892 0.415452 +vt 0.264108 0.419614 +vt 0.332802 0.421531 +vt 0.267897 0.425295 +vt 0.386005 0.430259 +vt 0.216093 0.440111 +vt 0.329080 0.426848 +vt 0.272222 0.430144 +vt 0.324738 0.431361 +vt 0.277069 0.434124 +vt 0.319785 0.435031 +vt 0.282423 0.437197 +vt 0.379286 0.441879 +vt 0.224141 0.450874 +vt 0.314232 0.437817 +vt 0.288267 0.439323 +vt 0.308090 0.439681 +vt 0.294588 0.440464 +vt 0.301369 0.440582 +vt 0.371259 0.452205 +vt 0.233335 0.460202 +vt 0.362073 0.461189 +vt 0.243522 0.468063 +vt 0.351877 0.468783 +vt 0.254547 0.474427 +vt 0.340820 0.474940 +vt 0.266257 0.479263 +vt 0.329050 0.479611 +vt 0.278500 0.482542 +vt 0.316716 0.482748 +vt 0.291121 0.484232 +vt 0.303967 0.484303 +vt 0.559195 0.270376 +vt 0.551062 0.270110 +vt 0.553828 0.270073 +vt 0.548481 0.270220 +vt 0.546070 0.270398 +vt 0.564566 0.271278 +vt 0.543813 0.270641 +vt 0.541694 0.270944 +vt 0.539698 0.271305 +vt 0.569915 0.272770 +vt 0.537810 0.271719 +vt 0.536014 0.272182 +vt 0.534295 0.272690 +vt 0.532638 0.273241 +vt 0.575213 0.274845 +vt 0.531027 0.273830 +vt 0.529446 0.274453 +vt 0.539051 0.320803 +vt 0.580434 0.277492 +vt 0.662066 0.479562 +vt 0.617736 0.275182 +vt 0.662066 0.275182 +vt 0.614042 0.311314 +vt 0.585551 0.280703 +vt 0.590538 0.284469 +vt 0.595366 0.288781 +vt 0.600010 0.293630 +vt 0.604443 0.299008 +vt 0.608636 0.304906 +vt 0.545837 0.318978 +vt 0.544165 0.319366 +vt 0.542485 0.319799 +vt 0.540785 0.320278 +vt 0.612565 0.311314 +vt 0.552706 0.317883 +vt 0.550936 0.318089 +vt 0.549210 0.318339 +vt 0.547515 0.318636 +vt 0.608132 0.357664 +vt 0.605021 0.350664 +vt 0.601626 0.344426 +vt 0.597984 0.338920 +vt 0.594135 0.334117 +vt 0.590116 0.329989 +vt 0.585967 0.326505 +vt 0.581725 0.323638 +vt 0.577429 0.321357 +vt 0.573118 0.319634 +vt 0.568830 0.318439 +vt 0.564604 0.317744 +vt 0.560477 0.317518 +vt 0.558405 0.317541 +vt 0.556427 0.317609 +vt 0.554532 0.317724 +vt 0.608132 0.479562 +vt 0.029749 0.484606 +vt 0.021616 0.484340 +vt 0.024381 0.484303 +vt 0.019035 0.484450 +vt 0.016624 0.484628 +vt 0.035120 0.485508 +vt 0.014366 0.484871 +vt 0.012247 0.485174 +vt 0.010251 0.485535 +vt 0.040468 0.487000 +vt 0.008363 0.485948 +vt 0.006567 0.486412 +vt 0.004849 0.486920 +vt 0.003191 0.487471 +vt 0.045766 0.489074 +vt 0.001580 0.488060 +vt 0.000000 0.488682 +vt 0.009605 0.535033 +vt 0.050987 0.491721 +vt 0.132620 0.693792 +vt 0.088290 0.489412 +vt 0.132620 0.489412 +vt 0.084596 0.525544 +vt 0.056105 0.494932 +vt 0.061091 0.498698 +vt 0.065920 0.503011 +vt 0.070564 0.507860 +vt 0.074996 0.513238 +vt 0.079190 0.519136 +vt 0.016391 0.533208 +vt 0.014719 0.533596 +vt 0.013039 0.534029 +vt 0.011339 0.534508 +vt 0.083118 0.525544 +vt 0.023259 0.532113 +vt 0.021490 0.532318 +vt 0.019764 0.532569 +vt 0.018068 0.532866 +vt 0.078685 0.571894 +vt 0.075575 0.564894 +vt 0.072179 0.558656 +vt 0.068538 0.553150 +vt 0.064688 0.548347 +vt 0.060670 0.544219 +vt 0.056520 0.540735 +vt 0.052278 0.537868 +vt 0.047983 0.535587 +vt 0.043672 0.533864 +vt 0.039384 0.532669 +vt 0.035157 0.531973 +vt 0.031031 0.531748 +vt 0.028958 0.531771 +vt 0.026981 0.531839 +vt 0.025086 0.531953 +vt 0.078685 0.693792 +vt 0.343555 0.270073 +vt 0.288882 0.044891 +vt 0.343555 0.000000 +vt 0.175841 0.000000 +vt 0.175841 0.044891 +vt 0.288882 0.107299 +vt 0.288882 0.152555 +vt 0.192834 0.107299 +vt 0.192834 0.152555 +vt 0.288882 0.224818 +vt 0.000000 0.703709 +vt 0.131696 0.703709 +vt 0.131696 0.714506 +vt 0.916252 0.609672 +vt 0.916252 0.739781 +vt 0.914116 0.739781 +vt 0.739066 0.811666 +vt 0.739066 0.941775 +vt 0.736796 0.941775 +vt 0.717198 0.941775 +vt 0.717198 0.811666 +vt 0.718894 0.811666 +vt 0.280391 0.972763 +vt 0.280391 0.842654 +vt 0.286716 0.842654 +vt 0.393453 0.842654 +vt 0.393453 0.972764 +vt 0.386676 0.972763 +vt 0.961733 0.609672 +vt 0.961733 0.739781 +vt 0.957061 0.739781 +vt 0.558392 0.973773 +vt 0.558392 0.843663 +vt 0.560462 0.843663 +vt 0.644885 0.973773 +vt 0.644885 0.843663 +vt 0.650663 0.843663 +vt 0.386676 0.842654 +vt 0.380393 0.972763 +vt 0.923522 0.609672 +vt 0.923522 0.739781 +vt 0.920940 0.739781 +vt 0.793762 0.570314 +vt 0.662066 0.570314 +vt 0.662066 0.553834 +vt 0.549165 0.973773 +vt 0.549165 0.843663 +vt 0.550904 0.843663 +vt 0.610237 0.843663 +vt 0.612307 0.843663 +vt 0.612307 0.973773 +vt 0.822592 0.869891 +vt 0.822592 1.000000 +vt 0.815816 1.000000 +vt 0.396827 0.693059 +vt 0.528523 0.693059 +vt 0.528523 0.697688 +vt 0.715444 0.941775 +vt 0.715444 0.811666 +vt 0.749745 0.130110 +vt 0.749745 0.000000 +vt 0.760787 0.000000 +vt 0.952060 0.260219 +vt 0.952060 0.130110 +vt 0.996252 0.130110 +vt 0.053834 0.960358 +vt 0.053834 0.830249 +vt 0.058761 0.830249 +vt 0.000000 0.799734 +vt 0.131696 0.799734 +vt 0.131696 0.810754 +vt 0.955807 0.609672 +vt 0.955807 0.479562 +vt 1.000000 0.479562 +vt 0.835339 0.130109 +vt 0.835339 0.000000 +vt 0.847061 0.000000 +vt 0.952216 0.869891 +vt 0.952216 0.739781 +vt 0.996409 0.739781 +vt 0.697517 0.941775 +vt 0.697517 0.811666 +vt 0.700277 0.811666 +vt 0.817025 0.609672 +vt 0.817025 0.479562 +vt 0.824637 0.479562 +vt 0.264316 0.779822 +vt 0.132620 0.779822 +vt 0.132620 0.763555 +vt 0.500979 0.973773 +vt 0.500979 0.843663 +vt 0.502689 0.843663 +vt 0.000000 0.714506 +vt 0.131696 0.726038 +vt 0.852290 0.609672 +vt 0.852290 0.739781 +vt 0.842836 0.739781 +vt 0.631826 0.843663 +vt 0.631826 0.973773 +vt 0.630063 0.973773 +vt 0.264316 0.708611 +vt 0.132620 0.708611 +vt 0.132620 0.697702 +vt 0.793762 0.553834 +vt 0.662066 0.538446 +vt 0.884784 0.609672 +vt 0.884784 0.479562 +vt 0.891347 0.479562 +vt 0.089888 0.960358 +vt 0.089888 0.830249 +vt 0.095991 0.830249 +vt 0.906593 0.270073 +vt 0.906593 0.400182 +vt 0.793762 0.400182 +vt 0.499283 0.973773 +vt 0.499283 0.843663 +vt 0.070062 0.960358 +vt 0.070062 0.830249 +vt 0.076405 0.830249 +vt 0.568743 0.973773 +vt 0.568743 0.843663 +vt 0.572949 0.843663 +vt 0.311896 0.972763 +vt 0.311896 0.842654 +vt 0.316837 0.842654 +vt 0.725449 0.811666 +vt 0.725449 0.941775 +vt 0.723796 0.941775 +vt 0.661142 0.839656 +vt 0.529446 0.839656 +vt 0.529446 0.835027 +vt 0.904905 0.609672 +vt 0.904905 0.739781 +vt 0.903252 0.739781 +vt 0.618017 0.843663 +vt 0.618017 0.973773 +vt 0.616184 0.973773 +vt 0.000000 0.810754 +vt 0.131696 0.820976 +vt 0.692190 0.941775 +vt 0.692190 0.811666 +vt 0.803756 0.869891 +vt 0.803756 1.000000 +vt 0.798495 1.000000 +vt 0.705277 0.941775 +vt 0.705277 0.811666 +vt 0.707547 0.811666 +vt 0.901973 0.609672 +vt 0.901973 0.479562 +vt 0.662066 0.941775 +vt 0.662066 0.811666 +vt 0.666737 0.811666 +vt 0.793762 0.646485 +vt 0.662066 0.646485 +vt 0.662066 0.637347 +vt 0.518091 0.973773 +vt 0.518091 0.843663 +vt 0.522266 0.843663 +vt 0.931608 0.609672 +vt 0.931608 0.739781 +vt 0.926282 0.739781 +vt 0.824637 0.609672 +vt 0.832887 0.479562 +vt 0.589407 0.843663 +vt 0.589407 0.973773 +vt 0.585350 0.973773 +vt 0.734660 0.811666 +vt 0.734660 0.941775 +vt 0.732641 0.941775 +vt 0.793762 0.488769 +vt 0.662066 0.488769 +vt 0.824980 0.609672 +vt 0.824980 0.739781 +vt 0.817127 0.739781 +vt 0.720547 0.941775 +vt 0.720547 0.811666 +vt 0.722171 0.811666 +vt 0.784873 0.130109 +vt 0.784873 0.000000 +vt 0.797618 0.000000 +vt 0.906601 0.609672 +vt 0.906601 0.739781 +vt 0.554515 0.973773 +vt 0.554515 0.843663 +vt 0.556414 0.843663 +vt 0.891347 0.609672 +vt 0.897090 0.479562 +vt 0.396012 0.828743 +vt 0.264316 0.828743 +vt 0.264316 0.822799 +vt 0.095991 0.960358 +vt 0.101486 0.830249 +vt 0.223020 0.845800 +vt 0.223020 0.975910 +vt 0.178003 0.975910 +vt 0.762648 0.811666 +vt 0.762648 0.941775 +vt 0.757435 0.941775 +vt 0.264316 0.763555 +vt 0.132620 0.748242 +vt 0.650663 0.973773 +vt 0.655923 0.843663 +vt 0.178003 0.845800 +vt 0.132620 0.975909 +vt 0.890963 0.609672 +vt 0.890963 0.739781 +vt 0.884517 0.739781 +vt 0.064176 0.960358 +vt 0.064176 0.830249 +vt 0.264316 0.733940 +vt 0.132620 0.733940 +vt 0.132620 0.720710 +vt 0.513986 0.973773 +vt 0.513986 0.843663 +vt 0.623245 0.843663 +vt 0.623245 0.973773 +vt 0.621534 0.973773 +vt 0.793762 0.601285 +vt 0.662066 0.601285 +vt 0.662066 0.586474 +vt 0.396827 0.689051 +vt 0.528523 0.689051 +vt 0.374616 0.842654 +vt 0.374616 0.972763 +vt 0.369356 0.972763 +vt 0.728899 0.811666 +vt 0.728899 0.941775 +vt 0.727145 0.941775 +vt 0.581293 0.973773 +vt 0.581293 0.843663 +vt 0.585350 0.843663 +vt 0.552683 0.973773 +vt 0.552683 0.843663 +vt 0.083187 0.960358 +vt 0.083187 0.830249 +vt 0.495887 0.973773 +vt 0.495887 0.843663 +vt 0.497590 0.843663 +vt 0.396012 0.834017 +vt 0.264316 0.834017 +vt 0.936891 0.609672 +vt 0.936891 0.739781 +vt 0.662066 0.270073 +vt 0.793762 0.270073 +vt 0.793762 0.439465 +vt 0.661142 0.835027 +vt 0.529446 0.829752 +vt 0.777606 0.811666 +vt 0.777606 0.941775 +vt 0.772759 0.941775 +vt 0.000000 0.775910 +vt 0.131696 0.775910 +vt 0.131696 0.788069 +vt 0.889631 0.869890 +vt 0.889631 0.739781 +vt 0.858102 0.130109 +vt 0.858102 0.000000 +vt 0.868307 0.000000 +vt 0.741484 0.811666 +vt 0.741484 0.941775 +vt 0.000000 0.738158 +vt 0.131696 0.738158 +vt 0.131696 0.750719 +vt 0.540636 0.973773 +vt 0.540636 0.843663 +vt 0.542363 0.843663 +vt 0.793762 0.524197 +vt 0.662066 0.524197 +vt 0.662066 0.511135 +vt 0.832887 0.609672 +vt 0.841733 0.479562 +vt 0.910182 0.609672 +vt 0.910182 0.739781 +vt 0.908355 0.739781 +vt 0.264316 0.810695 +vt 0.132620 0.810695 +vt 0.132620 0.795995 +vt 0.912097 0.609672 +vt 0.912097 0.739781 +vt 0.833562 0.609672 +vt 0.833562 0.739781 +vt 0.616184 0.843663 +vt 0.614285 0.973773 +vt 0.396012 0.688042 +vt 0.264316 0.688042 +vt 0.264316 0.484303 +vt 0.897090 0.609672 +vt 0.711702 0.941775 +vt 0.711702 0.811666 +vt 0.713617 0.811666 +vt 0.577146 0.973773 +vt 0.577146 0.843663 +vt 0.896681 0.609672 +vt 0.896681 0.739781 +vt 0.809533 0.869891 +vt 0.809533 1.000000 +vt 0.626633 0.843663 +vt 0.626633 0.973773 +vt 0.624940 0.973773 +vt 0.772546 0.130110 +vt 0.772546 0.000000 +vt 0.942104 0.609672 +vt 0.942104 0.739781 +vt 0.509938 0.973773 +vt 0.509938 0.843663 +vt 0.511916 0.843663 +vt 0.058761 0.960358 +vt 0.369356 0.842654 +vt 0.364622 0.972763 +vt 0.810091 0.609672 +vt 0.810091 0.479562 +vt 0.396012 0.842654 +vt 0.264316 0.842654 +vt 0.264316 0.838646 +vt 0.396827 0.715542 +vt 0.528523 0.715542 +vt 0.528523 0.722894 +vt 0.960427 0.270073 +vt 0.264316 0.845800 +vt 0.132620 0.845800 +vt 0.132620 0.835614 +vt 0.847061 0.130109 +vt 0.504427 0.973773 +vt 0.504427 0.843663 +vt 0.506206 0.843663 +vt 0.746826 0.811666 +vt 0.746826 0.941775 +vt 0.744066 0.941775 +vt 0.655923 0.973773 +vt 0.660657 0.843663 +vt 0.538873 0.973773 +vt 0.538873 0.843663 +vt 0.597750 0.843663 +vt 0.597750 0.973773 +vt 0.593554 0.973773 +vt 0.877442 0.609672 +vt 0.877442 0.479562 +vt 0.709683 0.941775 +vt 0.709683 0.811666 +vt 0.914116 0.609672 +vt 0.793762 0.511135 +vt 0.662066 0.499310 +vt 0.842836 0.609672 +vt 0.444612 0.973773 +vt 0.444612 0.843663 +vt 0.492397 0.843663 +vt 0.076405 0.960358 +vt 0.380393 0.842654 +vt 0.638603 0.973773 +vt 0.638603 0.843663 +vt 0.550904 0.973773 +vt 0.901627 0.609672 +vt 0.901627 0.739781 +vt 0.815816 0.869891 +vt 0.661142 0.823809 +vt 0.529446 0.823809 +vt 0.529446 0.817173 +vt 0.760787 0.130110 +vt 0.793762 0.626749 +vt 0.662066 0.626749 +vt 0.662066 0.614719 +vt 0.798495 0.869891 +vt 0.793762 1.000000 +vt 0.793762 0.811666 +vt 0.610237 0.973773 +vt 0.606133 0.973773 +vt 0.681695 0.941775 +vt 0.681695 0.811666 +vt 0.686908 0.811666 +vt 0.572949 0.973773 +vt 0.752153 0.811666 +vt 0.752153 0.941775 +vt 0.793762 0.609672 +vt 0.793762 0.479562 +vt 0.798419 0.479562 +vt 0.000000 0.750719 +vt 0.131696 0.763410 +vt 0.926282 0.609672 +vt 0.506206 0.973773 +vt 0.508039 0.843663 +vt 0.132620 0.688042 +vt 0.396827 0.697688 +vt 0.528523 0.702962 +vt 0.526473 0.973773 +vt 0.526473 0.843663 +vt 0.530669 0.843663 +vt 0.797618 0.130109 +vt 0.810464 0.000000 +vt 0.396827 0.973773 +vt 0.396827 0.843663 +vt 0.997465 0.609672 +vt 0.614285 0.843663 +vt 0.793762 0.637347 +vt 0.264316 0.835614 +vt 0.132620 0.823907 +vt 0.851135 0.609672 +vt 0.851135 0.479562 +vt 0.860577 0.479562 +vt 0.492397 0.973773 +vt 0.494160 0.843663 +vt 0.264316 0.720710 +vt 0.628336 0.843663 +vt 0.628336 0.973773 +vt 0.707547 0.941775 +vt 0.817127 0.609672 +vt 0.810041 0.739781 +vt 0.986157 0.000000 +vt 0.986157 0.130109 +vt 0.940774 0.130109 +vt 0.727145 0.811666 +vt 0.884517 0.609672 +vt 0.877384 0.739781 +vt 0.757435 0.811666 +vt 0.798321 0.609672 +vt 0.798321 0.739781 +vt 0.793762 0.739781 +vt 0.686908 0.941775 +vt 0.730726 0.811666 +vt 0.730726 0.941775 +vt 0.952215 0.609672 +vt 0.947221 0.739781 +vt 0.530669 0.973773 +vt 0.534816 0.843663 +vt 0.396012 0.816163 +vt 0.264316 0.816163 +vt 0.264316 0.808811 +vt 0.666737 0.941776 +vt 0.671583 0.811666 +vt 0.630063 0.843663 +vt 0.508039 0.973773 +vt 0.793762 0.499310 +vt 0.269176 0.972764 +vt 0.269176 0.842654 +vt 0.274539 0.842654 +vt 0.606133 0.843663 +vt 0.601957 0.973773 +vt 0.732641 0.811666 +vt 0.823089 0.130109 +vt 0.823089 0.000000 +vt 0.556414 0.973773 +vt 0.798419 0.609672 +vt 0.803875 0.479562 +vt 0.494160 0.973773 +vt 0.396827 0.702962 +vt 0.528523 0.708906 +vt 0.396012 0.808811 +vt 0.661142 0.817173 +vt 0.529446 0.809820 +vt 0.856309 0.260219 +vt 0.739567 0.260219 +vt 0.739567 0.130110 +vt 0.547455 0.973773 +vt 0.547455 0.843663 +vt 0.861228 0.609672 +vt 0.861228 0.739781 +vt 0.793762 0.869891 +vt 0.918522 0.609672 +vt 0.918522 0.739781 +vt 0.860577 0.609672 +vt 0.869359 0.479562 +vt 0.793762 0.614719 +vt 0.783750 0.941775 +vt 0.783750 0.811666 +vt 0.785223 0.811666 +vt 0.996159 0.270073 +vt 0.996159 0.400182 +vt 0.960427 0.400182 +vt 0.306352 0.972763 +vt 0.306352 0.842654 +vt 0.000000 0.726038 +vt 0.274539 0.972763 +vt 0.534816 0.973773 +vt 0.793762 0.538446 +vt 0.957061 0.609672 +vt 0.624940 0.843663 +vt 0.792289 0.941775 +vt 0.792289 0.811666 +vt 0.739567 0.203739 +vt 0.607871 0.203739 +vt 0.607871 0.000000 +vt 0.601957 0.843663 +vt 0.782277 0.811666 +vt 0.782277 0.941775 +vt 0.739567 0.000000 +vt 0.564567 0.973773 +vt 0.564567 0.843663 +vt 0.920940 0.609672 +vt 0.000000 0.763410 +vt 0.000000 0.820976 +vt 0.131696 0.830249 +vt 0.475251 0.269226 +vt 0.343555 0.269226 +vt 0.744066 0.811666 +vt 0.702859 0.941775 +vt 0.702859 0.811666 +vt 0.396827 0.708906 +vt 0.000000 0.960358 +vt 0.000000 0.830249 +vt 0.264316 0.823907 +vt 0.364622 0.842654 +vt 0.316837 0.972763 +vt 0.671583 0.941775 +vt 0.676578 0.811666 +vt 0.545760 0.973773 +vt 0.545760 0.843663 +vt 0.542363 0.973773 +vt 0.544067 0.843663 +vt 0.502689 0.973773 +vt 0.000000 0.693792 +vt 0.131696 0.693792 +vt 0.718894 0.941775 +vt 0.258752 0.845800 +vt 0.258752 0.975909 +vt 0.783750 0.811666 +vt 0.713617 0.941775 +vt 0.903252 0.609672 +vt 0.264316 0.748242 +vt 0.264316 0.697702 +vt 0.723796 0.811666 +vt 0.722172 0.941775 +vt 0.619796 0.843663 +vt 0.619796 0.973773 +vt 0.810041 0.609672 +vt 0.803760 0.739781 +vt 0.803760 0.609672 +vt 0.522266 0.973773 +vt 0.497590 0.973773 +vt 0.940774 0.000000 +vt 0.868307 0.130109 +vt 0.661142 0.829752 +vt 0.810464 0.130110 +vt 0.803875 0.609672 +vt 0.101486 0.960358 +vt 0.106364 0.830249 +vt 0.676578 0.941776 +vt 0.661142 0.809820 +vt 0.529446 0.689051 +vt 0.841733 0.609672 +vt 0.793762 0.586474 +vt 0.869607 0.609672 +vt 0.869607 0.739781 +vt 0.736796 0.811666 +vt 0.908355 0.609672 +vt 0.869359 0.609672 +vt 0.293498 0.972763 +vt 0.293498 0.842654 +vt 0.300216 0.842654 +vt 0.661142 0.843663 +vt 0.529446 0.843663 +vt 0.286716 0.972763 +vt 0.621534 0.843663 +vt 0.560462 0.973773 +vt 0.300216 0.972763 +vt 0.767765 0.811666 +vt 0.767765 0.941775 +vt 0.947221 0.609672 +vt 0.000000 0.788069 +vt 0.511916 0.973773 +vt 0.264316 0.972764 +vt 0.772759 0.811666 +vt 0.700277 0.941775 +vt 0.396012 0.822799 +vt 0.396827 0.722894 +vt 0.528523 0.843663 +vt 0.396012 0.838646 +vt 0.264316 0.795995 +vt 0.544067 0.973773 +vt 0.593554 0.843663 +vt 0.996252 0.260219 +vt 1.000000 0.609672 +vt 0.996409 0.869891 +vt 0.662066 0.439465 +vt 0.396012 0.484303 +vt 0.660657 0.973773 +vt 0.132620 0.484303 +vt 0.997465 0.739781 +vt 0.856309 0.130110 +vt 0.785223 0.941775 +vt 0.793762 0.941775 +vt 0.475251 0.000000 +vt 0.106364 0.960358 +vt 0.661142 0.689051 +vn -1.000000 -0.000000 0.000000 +vn -1.000000 0.000100 0.000000 +vn -1.000000 0.000200 0.000000 +vn -1.000000 -0.000100 -0.000000 +vn 1.000000 0.000100 0.000000 +vn 1.000000 0.000000 0.000000 +vn 1.000000 -0.000100 0.000000 +vn 1.000000 -0.000200 0.000000 +vn 1.000000 -0.000500 0.000100 +vn 0.000000 0.898000 0.440100 +vn 0.000000 0.989700 -0.143500 +vn 0.000000 0.994100 -0.108200 +vn 0.000000 0.947800 -0.318800 +vn 0.000000 -0.970700 0.240300 +vn 0.000000 0.518000 0.855400 +vn 0.000000 0.794500 0.607300 +vn -0.000000 -0.999900 0.011200 +vn -0.000000 0.631400 0.775500 +vn 0.000000 0.574900 0.818300 +vn 0.000000 0.999100 -0.042900 +vn -0.000000 0.058000 0.998300 +vn -0.000000 -0.989300 0.145600 +vn 0.000000 -0.999900 0.011100 +vn 0.000000 -0.693200 -0.720800 +vn 0.000000 0.957900 -0.287000 +vn 0.000000 -0.898400 -0.439100 +vn 0.000000 1.000000 -0.000000 +vn 0.000000 0.730300 -0.683200 +vn 0.000000 0.831400 -0.555600 +vn 0.000000 -0.898400 0.439100 +vn 0.000000 0.999900 -0.013700 +vn 0.000000 0.287300 0.957800 +vn 0.000000 -0.058600 -0.998300 +vn 0.000000 -0.984700 0.174300 +vn 0.000000 0.948000 0.318300 +vn 0.000000 -0.034600 -0.999400 +vn -0.000000 -0.956200 0.292900 +vn 0.000000 -0.654500 -0.756100 +vn -0.000000 0.179000 0.983900 +vn 0.000000 -0.385900 0.922600 +vn 0.000000 0.971500 0.237100 +vn 0.000000 -1.000000 -0.000000 +vn 0.000000 -0.979300 0.202200 +vn 0.000000 0.971500 -0.237100 +vn 0.000000 -0.962500 -0.271400 +vn 0.000000 -0.830400 -0.557200 +vn 0.000000 0.937900 -0.346900 +vn 0.000000 -0.996100 0.088200 +vn 0.000000 0.749200 -0.662400 +vn -0.000000 0.998400 0.057000 +vn 0.000000 0.687300 0.726400 +vn -0.000000 -0.654500 0.756100 +vn 0.000000 -0.986400 -0.164300 +vn 0.000000 0.194300 0.980900 +vn 0.000000 -0.825300 -0.564700 +vn 0.000000 0.983700 -0.179900 +vn -0.000000 0.749200 0.662400 +vn 0.000000 0.194300 -0.980900 +vn 0.000000 0.928800 -0.370500 +vn -0.000000 -0.997900 -0.064200 +vn -0.000000 -0.998100 0.060800 +vn 0.000000 -0.495900 0.868400 +vn 0.000000 -0.547000 -0.837100 +vn 0.000000 0.916500 0.399900 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.962300 0.271800 +vn 0.000000 -0.180600 -0.983600 +vn 0.000000 -0.495900 -0.868400 +vn 0.000000 0.916500 -0.399900 +vn -0.000000 -0.428300 -0.903600 +vn 0.000000 -0.998500 -0.055200 +vn -0.000000 -0.180600 0.983600 +vn 0.000000 -0.762000 -0.647500 +vn 0.000000 0.997100 0.076200 +vn 0.000000 -0.967600 0.252700 +vn 0.000000 -0.620800 -0.784000 +vn 0.000000 0.985900 0.167600 +vn 0.000000 0.844100 0.536100 +vn 0.000000 0.948000 -0.318300 +vn 0.000000 -0.750700 0.660700 +vn 0.000000 0.997200 -0.074500 +vn 0.000000 0.997900 0.064200 +vn -0.000000 -0.961700 0.274200 +vn 0.000000 0.425800 0.904800 +vn 0.000000 0.110500 0.993900 +vn 0.000000 0.967600 -0.252600 +vn 0.000000 0.179000 -0.983900 +vn 0.000000 0.976300 -0.216500 +vn 0.000000 0.110500 -0.993900 +vn 0.000000 -0.998200 0.060800 +vn 0.000000 0.000000 1.000000 +vn 0.000000 -0.611200 0.791400 +vn 0.000000 -0.880900 -0.473400 +vn 0.000000 -0.611200 -0.791400 +vn 0.000000 -0.973500 0.228500 +vn -0.000000 -0.981400 -0.192100 +vn 0.000000 -0.999400 0.035000 +vn 0.000000 0.833800 -0.552100 +vn 0.000000 0.741800 0.670600 +vn 0.000000 0.389700 0.920900 +vn 0.000000 -0.402000 -0.915600 +vn 0.000000 0.543600 -0.839300 +vn 0.000000 -0.832400 0.554200 +vn 0.000000 -0.993200 0.116600 +vn 0.000000 -0.927000 -0.375100 +vn 0.000000 -0.284400 0.958700 +vn -0.000000 0.543600 0.839300 +vn 0.000000 0.034900 -0.999400 +vn 0.000000 -0.200600 -0.979700 +vn 0.000000 0.997100 -0.076200 +vn 0.000000 -0.725800 -0.687900 +vn 0.000000 -0.473600 -0.880800 +vn 0.000000 -0.948200 -0.317700 +vn -0.000000 -0.428300 0.903600 +vn 0.000000 0.730300 0.683200 +vn 0.000000 0.997900 -0.064200 +vn -0.000000 -0.997900 0.064200 +vn 0.000000 0.100500 -0.994900 +vn -0.000000 -0.546000 0.837800 +vn 0.000000 0.425800 -0.904800 +vn 0.000000 -0.034600 0.999400 +vn 0.000000 -0.546000 -0.837800 +vn 0.000000 0.287300 -0.957800 +vn 0.000000 -0.385900 -0.922600 +vn 0.000000 0.616100 -0.787700 +vn 0.000000 0.889700 0.456600 +vn -0.000000 0.652500 0.757800 +vn 0.000000 -0.830400 0.557200 +vn 0.000000 -0.948200 0.317700 +vn 0.000000 0.616100 0.787700 +vn 0.000000 -0.402000 -0.915700 +vn 0.000000 -0.109400 -0.994000 +vn 0.000000 -0.109400 0.994000 +vn 0.000000 -0.305100 0.952300 +vn 0.000000 -0.914500 -0.404500 +vn 0.000000 0.981300 0.192400 +vn 0.000000 -0.914500 0.404500 +vn -0.000000 0.302900 0.953000 +vn 0.000000 -0.832400 -0.554200 +vn 0.000000 0.981300 -0.192400 +vn 0.000000 0.652500 -0.757800 +vn 0.000000 0.302900 -0.953000 +vn 0.000000 0.831500 0.555600 +vn 0.000000 -0.305100 -0.952300 +vn 0.000000 -0.750700 -0.660700 +vn 0.000000 0.389700 -0.920900 +vn 0.000000 0.500400 -0.865800 +vn -0.000000 -0.981400 0.192100 +vn 0.000000 0.500400 0.865800 +vn 0.000000 0.833800 0.552100 +vn -0.000000 0.929700 0.368400 +vn 0.000000 0.034900 0.999400 +vn -0.000000 -0.058600 0.998300 +vn 0.000000 -0.192300 -0.981300 +vn 0.000000 -0.284400 -0.958700 +vn 0.000000 -0.192300 0.981300 +vn 0.000000 -0.997000 -0.077300 +vn 0.000000 -0.997000 0.077300 +vn 0.000000 -0.970700 -0.240300 +vn 0.000000 0.898000 -0.440100 +vn 0.000000 -0.725800 0.687900 +vn 0.000000 0.058000 -0.998300 +vn 0.000000 0.999100 -0.043000 +vn 0.000000 0.831500 -0.555600 +vn 0.000000 0.928800 -0.370600 +vn 0.000000 -0.956200 0.292800 +vn 0.000000 0.831400 0.555600 +s off +f 41/1/1 40/2/1 39/3/1 +f 41/1/1 39/3/1 38/4/1 +f 41/1/1 38/4/1 37/5/1 +f 42/6/1 41/1/1 37/5/1 +f 42/6/1 37/5/1 36/7/1 +f 42/6/1 36/7/1 35/8/1 +f 42/6/1 35/8/1 34/9/1 +f 43/10/1 42/6/1 34/9/1 +f 43/10/1 34/9/1 33/11/1 +f 43/10/1 33/11/1 32/12/1 +f 43/10/1 32/12/1 31/13/1 +f 43/10/1 31/13/1 30/14/1 +f 44/15/1 43/10/1 30/14/1 +f 44/15/1 30/14/1 29/16/1 +f 44/15/1 29/16/1 28/17/1 +f 44/15/1 28/17/1 27/18/1 +f 45/19/1 44/15/1 27/18/1 +f 1/20/1 55/21/1 54/22/1 +f 1/20/1 54/22/1 53/23/1 +f 46/24/1 45/19/1 27/18/1 +f 47/25/1 46/24/1 27/18/1 +f 48/26/1 47/25/1 27/18/1 +f 49/27/1 48/26/1 27/18/1 +f 50/28/1 49/27/1 27/18/1 +f 51/29/1 50/28/1 23/30/1 +f 23/30/1 50/28/1 24/31/1 +f 24/31/1 50/28/1 25/32/1 +f 25/32/2 50/28/2 26/33/2 +f 26/33/1 50/28/1 27/18/1 +f 52/34/1 51/29/1 19/35/1 +f 19/35/1 51/29/1 20/36/1 +f 20/36/1 51/29/1 21/37/1 +f 21/37/1 51/29/1 22/38/1 +f 22/38/3 51/29/3 23/30/3 +f 1/20/1 53/23/1 52/34/1 +f 1/20/1 52/34/1 3/39/1 +f 3/39/1 52/34/1 4/40/1 +f 4/40/1 52/34/1 5/41/1 +f 5/41/1 52/34/1 6/42/1 +f 6/42/1 52/34/1 7/43/1 +f 7/43/1 52/34/1 8/44/1 +f 8/44/1 52/34/1 9/45/1 +f 9/45/1 52/34/1 10/46/1 +f 10/46/1 52/34/1 11/47/1 +f 11/47/1 52/34/1 12/48/1 +f 12/48/1 52/34/1 13/49/1 +f 13/49/1 52/34/1 14/50/1 +f 14/50/1 52/34/1 15/51/1 +f 15/51/1 52/34/1 16/52/1 +f 16/52/2 52/34/2 17/53/2 +f 17/53/1 52/34/1 18/54/1 +f 18/54/1 52/34/1 19/35/1 +f 1/20/1 3/39/1 2/55/1 +f 81/56/1 80/57/1 79/58/1 +f 81/56/1 79/58/1 78/59/1 +f 82/60/1 81/56/1 78/59/1 +f 82/60/1 78/59/1 77/61/1 +f 83/62/1 82/60/1 77/61/1 +f 83/62/1 77/61/1 76/63/1 +f 84/64/1 83/62/1 76/63/1 +f 85/65/1 84/64/1 76/63/1 +f 85/65/1 76/63/1 75/66/1 +f 86/67/1 85/65/1 75/66/1 +f 86/67/1 75/66/1 74/68/1 +f 87/69/1 86/67/1 74/68/1 +f 87/69/1 74/68/1 73/70/1 +f 88/71/1 87/69/1 73/70/1 +f 88/71/1 73/70/1 128/72/1 +f 128/72/1 73/70/1 72/73/1 +f 88/71/2 128/72/2 127/74/2 +f 129/75/1 128/72/1 72/73/1 +f 88/71/1 127/74/1 126/76/1 +f 130/77/1 129/75/1 72/73/1 +f 88/71/1 126/76/1 125/78/1 +f 131/79/1 130/77/1 72/73/1 +f 88/71/1 125/78/1 124/80/1 +f 132/81/1 131/79/1 72/73/1 +f 89/82/1 88/71/1 124/80/1 +f 132/81/1 72/73/1 71/83/1 +f 89/82/1 124/80/1 123/84/1 +f 133/85/1 132/81/1 71/83/1 +f 89/82/1 123/84/1 122/86/1 +f 134/87/1 133/85/1 71/83/1 +f 89/82/1 122/86/1 121/88/1 +f 135/89/1 134/87/1 71/83/1 +f 90/90/1 89/82/1 121/88/1 +f 135/89/1 71/83/1 70/91/1 +f 90/90/1 121/88/1 120/92/1 +f 136/93/1 135/89/1 70/91/1 +f 90/90/1 120/92/1 119/94/1 +f 137/95/1 136/93/1 70/91/1 +f 91/96/1 90/90/1 119/94/1 +f 137/95/1 70/91/1 69/97/1 +f 91/96/1 119/94/1 118/98/1 +f 138/99/1 137/95/1 69/97/1 +f 91/96/1 118/98/1 117/100/1 +f 139/101/1 138/99/1 69/97/1 +f 92/102/1 91/96/1 117/100/1 +f 139/101/1 69/97/1 68/103/1 +f 92/102/1 117/100/1 116/104/1 +f 140/105/1 139/101/1 68/103/1 +f 93/106/1 92/102/1 116/104/1 +f 93/106/1 116/104/1 115/107/1 +f 141/108/1 140/105/1 68/103/1 +f 141/108/1 68/103/1 67/109/1 +f 93/106/1 115/107/1 114/110/1 +f 142/111/1 141/108/1 67/109/1 +f 94/112/1 93/106/1 114/110/1 +f 142/111/1 67/109/1 66/113/1 +f 94/112/1 114/110/1 113/114/1 +f 143/115/1 142/111/1 66/113/1 +f 94/112/1 113/114/1 112/116/1 +f 144/117/1 143/115/1 66/113/1 +f 95/118/1 94/112/1 112/116/1 +f 144/117/1 66/113/1 65/119/1 +f 95/118/1 112/116/1 111/120/1 +f 145/121/1 144/117/1 65/119/1 +f 95/118/1 111/120/1 110/122/1 +f 146/123/1 145/121/1 65/119/1 +f 96/124/1 95/118/1 110/122/1 +f 146/123/1 65/119/1 64/125/1 +f 96/124/1 110/122/1 109/126/1 +f 147/127/1 146/123/1 64/125/1 +f 96/124/1 109/126/1 108/128/1 +f 148/129/1 147/127/1 64/125/1 +f 96/124/1 108/128/1 107/130/1 +f 149/131/1 148/129/1 64/125/1 +f 97/132/1 96/124/1 107/130/1 +f 149/131/1 64/125/1 63/133/1 +f 97/132/1 107/130/1 106/134/1 +f 150/135/1 149/131/1 63/133/1 +f 97/132/1 106/134/1 105/136/1 +f 151/137/1 150/135/1 63/133/1 +f 97/132/1 105/136/1 104/138/1 +f 104/138/1 151/137/1 63/133/1 +f 97/132/1 104/138/1 63/133/1 +f 98/139/1 97/132/1 63/133/1 +f 98/139/1 63/133/1 62/140/1 +f 99/141/1 98/139/1 62/140/1 +f 99/141/1 62/140/1 61/142/1 +f 100/143/1 99/141/1 61/142/1 +f 100/143/1 61/142/1 60/144/1 +f 101/145/1 100/143/1 60/144/1 +f 101/145/1 60/144/1 59/146/1 +f 102/147/1 101/145/1 59/146/1 +f 102/147/1 59/146/1 58/148/1 +f 103/149/1 102/147/1 58/148/1 +f 103/149/1 58/148/1 57/150/1 +f 56/151/1 103/149/1 57/150/1 +f 192/152/1 191/153/1 190/154/1 +f 192/152/4 190/154/4 189/155/4 +f 192/152/1 189/155/1 188/156/1 +f 193/157/1 192/152/1 188/156/1 +f 193/157/1 188/156/1 187/158/1 +f 193/157/1 187/158/1 186/159/1 +f 193/157/1 186/159/1 185/160/1 +f 194/161/1 193/157/1 185/160/1 +f 194/161/1 185/160/1 184/162/1 +f 194/161/1 184/162/1 183/163/1 +f 194/161/1 183/163/1 182/164/1 +f 194/161/1 182/164/1 181/165/1 +f 195/166/1 194/161/1 181/165/1 +f 195/166/1 181/165/1 180/167/1 +f 195/166/1 180/167/1 179/168/1 +f 195/166/1 179/168/1 178/169/1 +f 196/170/1 195/166/1 178/169/1 +f 152/171/1 206/172/1 205/173/1 +f 152/171/1 205/173/1 204/174/1 +f 197/175/1 196/170/1 178/169/1 +f 198/176/1 197/175/1 178/169/1 +f 199/177/1 198/176/1 178/169/1 +f 200/178/1 199/177/1 178/169/1 +f 201/179/1 200/178/1 178/169/1 +f 202/180/1 201/179/1 174/181/1 +f 174/181/1 201/179/1 175/182/1 +f 175/182/1 201/179/1 176/183/1 +f 176/183/1 201/179/1 177/184/1 +f 177/184/1 201/179/1 178/169/1 +f 203/185/1 202/180/1 170/186/1 +f 170/186/1 202/180/1 171/187/1 +f 171/187/1 202/180/1 172/188/1 +f 172/188/1 202/180/1 173/189/1 +f 173/189/1 202/180/1 174/181/1 +f 152/171/1 204/174/1 203/185/1 +f 152/171/1 203/185/1 154/190/1 +f 154/190/1 203/185/1 155/191/1 +f 155/191/1 203/185/1 156/192/1 +f 156/192/1 203/185/1 157/193/1 +f 157/193/1 203/185/1 158/194/1 +f 158/194/1 203/185/1 159/195/1 +f 159/195/1 203/185/1 160/196/1 +f 160/196/1 203/185/1 161/197/1 +f 161/197/1 203/185/1 162/198/1 +f 162/198/1 203/185/1 163/199/1 +f 163/199/1 203/185/1 164/200/1 +f 164/200/1 203/185/1 165/201/1 +f 165/201/1 203/185/1 166/202/1 +f 166/202/1 203/185/1 167/203/1 +f 167/203/1 203/185/1 168/204/1 +f 168/204/1 203/185/1 169/205/1 +f 169/205/1 203/185/1 170/186/1 +f 152/171/1 154/190/1 153/206/1 +f 247/207/1 246/208/1 245/209/1 +f 247/207/1 245/209/1 244/210/1 +f 247/207/1 244/210/1 243/211/1 +f 248/212/1 247/207/1 243/211/1 +f 248/212/1 243/211/1 242/213/1 +f 248/212/1 242/213/1 241/214/1 +f 248/212/1 241/214/1 240/215/1 +f 249/216/1 248/212/1 240/215/1 +f 249/216/1 240/215/1 239/217/1 +f 249/216/1 239/217/1 238/218/1 +f 249/216/1 238/218/1 237/219/1 +f 249/216/1 237/219/1 236/220/1 +f 250/221/1 249/216/1 236/220/1 +f 250/221/1 236/220/1 235/222/1 +f 250/221/1 235/222/1 234/223/1 +f 250/221/1 234/223/1 233/224/1 +f 251/225/1 250/221/1 233/224/1 +f 207/226/1 261/227/1 260/228/1 +f 207/226/1 260/228/1 259/229/1 +f 252/230/1 251/225/1 233/224/1 +f 253/231/1 252/230/1 233/224/1 +f 254/232/1 253/231/1 233/224/1 +f 255/233/1 254/232/1 233/224/1 +f 256/234/1 255/233/1 233/224/1 +f 257/235/1 256/234/1 229/236/1 +f 229/236/1 256/234/1 230/237/1 +f 230/237/1 256/234/1 231/238/1 +f 231/238/1 256/234/1 232/239/1 +f 232/239/1 256/234/1 233/224/1 +f 258/240/1 257/235/1 225/241/1 +f 225/241/1 257/235/1 226/242/1 +f 226/242/1 257/235/1 227/243/1 +f 227/243/1 257/235/1 228/244/1 +f 228/244/1 257/235/1 229/236/1 +f 207/226/1 259/229/1 258/240/1 +f 207/226/1 258/240/1 209/245/1 +f 209/245/1 258/240/1 210/246/1 +f 210/246/1 258/240/1 211/247/1 +f 211/247/1 258/240/1 212/248/1 +f 212/248/1 258/240/1 213/249/1 +f 213/249/1 258/240/1 214/250/1 +f 214/250/1 258/240/1 215/251/1 +f 215/251/1 258/240/1 216/252/1 +f 216/252/1 258/240/1 217/253/1 +f 217/253/1 258/240/1 218/254/1 +f 218/254/1 258/240/1 219/255/1 +f 219/255/1 258/240/1 220/256/1 +f 220/256/1 258/240/1 221/257/1 +f 221/257/1 258/240/1 222/258/1 +f 222/258/1 258/240/1 223/259/1 +f 223/259/1 258/240/1 224/260/1 +f 224/260/1 258/240/1 225/241/1 +f 207/226/1 209/245/1 208/261/1 +f 262/262/1 273/263/1 270/264/1 +f 270/264/1 273/263/1 272/265/1 +f 270/264/1 272/265/1 271/266/1 +f 262/262/1 270/264/1 269/267/1 +f 262/262/1 269/267/1 266/268/1 +f 266/268/1 269/267/1 268/269/1 +f 266/268/1 268/269/1 267/270/1 +f 262/262/1 266/268/1 265/271/1 +f 262/262/1 265/271/1 264/272/1 +f 262/262/1 264/272/1 263/273/1 +f 426/274/5 336/275/5 337/276/5 +f 426/274/6 479/277/6 336/275/6 +f 426/274/6 478/278/6 479/277/6 +f 308/279/6 478/278/6 426/274/6 +f 308/279/6 307/280/6 478/278/6 +f 308/279/6 466/281/6 307/280/6 +f 308/279/6 512/282/6 466/281/6 +f 415/283/6 512/282/6 308/279/6 +f 415/283/6 414/284/6 512/282/6 +f 415/283/6 441/285/6 414/284/6 +f 415/283/6 489/286/6 441/285/6 +f 415/283/6 465/287/6 489/286/6 +f 409/288/6 465/287/6 415/283/6 +f 409/288/6 408/289/6 465/287/6 +f 409/288/6 539/290/6 408/289/6 +f 409/288/6 295/291/6 539/290/6 +f 475/292/6 295/291/6 409/288/6 +f 380/293/6 482/294/6 526/295/6 +f 380/293/6 463/296/6 482/294/6 +f 476/297/6 295/291/6 475/292/6 +f 296/298/6 295/291/6 476/297/6 +f 329/299/6 295/291/6 296/298/6 +f 424/300/6 295/291/6 329/299/6 +f 439/301/6 295/291/6 424/300/6 +f 348/302/6 487/303/6 439/301/6 +f 487/303/6 438/304/6 439/301/6 +f 438/304/6 358/305/6 439/301/6 +f 358/305/7 359/306/7 439/301/7 +f 359/306/6 295/291/6 439/301/6 +f 367/307/6 523/308/6 348/302/6 +f 523/308/6 538/309/6 348/302/6 +f 538/309/6 347/310/6 348/302/6 +f 347/310/6 486/311/6 348/302/6 +f 486/311/8 487/303/8 348/302/8 +f 380/293/6 367/307/6 463/296/6 +f 380/293/6 449/312/6 367/307/6 +f 449/312/6 541/313/6 367/307/6 +f 541/313/6 391/314/6 367/307/6 +f 391/314/6 499/315/6 367/307/6 +f 499/315/6 494/316/6 367/307/6 +f 494/316/6 448/317/6 367/307/6 +f 448/317/6 368/318/6 367/307/6 +f 368/318/6 369/319/6 367/307/6 +f 369/319/6 524/320/6 367/307/6 +f 524/320/6 540/321/6 367/307/6 +f 540/321/6 366/322/6 367/307/6 +f 366/322/6 488/323/6 367/307/6 +f 488/323/6 492/324/6 367/307/6 +f 492/324/6 447/325/6 367/307/6 +f 447/325/7 354/326/7 367/307/7 +f 354/326/6 355/327/6 367/307/6 +f 355/327/6 523/308/6 367/307/6 +f 380/293/6 381/328/6 449/312/6 +f 396/329/6 459/330/6 460/331/6 +f 396/329/6 294/332/6 459/330/6 +f 412/333/6 294/332/6 396/329/6 +f 412/333/6 293/334/6 294/332/6 +f 500/335/6 293/334/6 412/333/6 +f 500/335/6 325/336/6 293/334/6 +f 385/337/6 325/336/6 500/335/6 +f 274/338/6 325/336/6 385/337/6 +f 274/338/6 506/339/6 325/336/6 +f 275/340/6 506/339/6 274/338/6 +f 275/340/6 505/341/6 506/339/6 +f 316/342/6 505/341/6 275/340/6 +f 316/342/6 315/343/6 505/341/6 +f 360/344/6 315/343/6 316/342/6 +f 360/344/6 320/345/6 315/343/6 +f 320/345/6 462/346/6 315/343/6 +f 360/344/7 445/347/7 320/345/7 +f 511/348/6 462/346/6 320/345/6 +f 360/344/6 361/349/6 445/347/6 +f 472/350/6 462/346/6 511/348/6 +f 360/344/6 421/351/6 361/349/6 +f 473/352/6 462/346/6 472/350/6 +f 360/344/6 327/353/6 421/351/6 +f 531/354/6 462/346/6 473/352/6 +f 525/355/6 327/353/6 360/344/6 +f 531/354/6 364/356/6 462/346/6 +f 525/355/6 326/357/6 327/353/6 +f 365/358/6 364/356/6 531/354/6 +f 525/355/6 518/359/6 326/357/6 +f 517/360/6 364/356/6 365/358/6 +f 525/355/6 537/361/6 518/359/6 +f 420/362/6 364/356/6 517/360/6 +f 502/363/6 537/361/6 525/355/6 +f 420/362/6 302/364/6 364/356/6 +f 502/363/6 530/365/6 537/361/6 +f 321/366/6 302/364/6 420/362/6 +f 502/363/6 522/367/6 530/365/6 +f 322/368/6 302/364/6 321/366/6 +f 503/369/6 522/367/6 502/363/6 +f 322/368/6 301/370/6 302/364/6 +f 503/369/6 469/371/6 522/367/6 +f 470/372/6 301/370/6 322/368/6 +f 503/369/6 418/373/6 469/371/6 +f 471/374/6 301/370/6 470/372/6 +f 395/375/6 418/373/6 503/369/6 +f 471/374/6 404/376/6 301/370/6 +f 395/375/6 324/377/6 418/373/6 +f 529/378/6 404/376/6 471/374/6 +f 286/379/6 324/377/6 395/375/6 +f 286/379/6 323/380/6 324/377/6 +f 435/381/6 404/376/6 529/378/6 +f 435/381/6 434/382/6 404/376/6 +f 286/379/6 352/383/6 323/380/6 +f 516/384/6 434/382/6 435/381/6 +f 287/385/6 352/383/6 286/379/6 +f 516/384/6 509/386/6 434/382/6 +f 287/385/6 536/387/6 352/383/6 +f 417/388/6 509/386/6 516/384/6 +f 287/385/6 527/389/6 536/387/6 +f 313/390/6 509/386/6 417/388/6 +f 456/391/6 527/389/6 287/385/6 +f 313/390/6 328/392/6 509/386/6 +f 456/391/6 519/393/6 527/389/6 +f 314/394/6 328/392/6 313/390/6 +f 456/391/6 346/395/6 519/393/6 +f 467/396/6 328/392/6 314/394/6 +f 345/397/6 346/395/6 456/391/6 +f 467/396/6 342/398/6 328/392/6 +f 345/397/6 413/399/6 346/395/6 +f 428/400/6 342/398/6 467/396/6 +f 345/397/6 312/401/6 413/399/6 +f 343/402/6 342/398/6 428/400/6 +f 345/397/6 311/403/6 312/401/6 +f 431/404/6 342/398/6 343/402/6 +f 292/405/6 311/403/6 345/397/6 +f 431/404/6 344/406/6 342/398/6 +f 292/405/6 510/407/6 311/403/6 +f 508/408/6 344/406/6 431/404/6 +f 292/405/6 535/409/6 510/407/6 +f 291/410/6 344/406/6 508/408/6 +f 292/405/6 290/411/6 535/409/6 +f 290/411/6 344/406/6 291/410/6 +f 292/405/6 344/406/6 290/411/6 +f 515/412/6 344/406/6 292/405/6 +f 515/412/6 484/413/6 344/406/6 +f 319/414/6 484/413/6 515/412/6 +f 319/414/6 483/415/6 484/413/6 +f 279/416/6 483/415/6 319/414/6 +f 279/416/6 278/417/6 483/415/6 +f 416/418/6 278/417/6 279/416/6 +f 416/418/6 521/419/6 278/417/6 +f 452/420/6 521/419/6 416/418/6 +f 452/420/6 387/421/6 521/419/6 +f 388/422/6 387/421/6 452/420/6 +f 388/422/6 430/423/6 387/421/6 +f 429/424/6 430/423/6 388/422/6 +f 351/425/6 403/426/6 543/427/6 +f 351/425/6 402/428/6 403/426/6 +f 351/425/6 284/429/6 402/428/6 +f 285/430/6 284/429/6 351/425/6 +f 285/430/6 455/431/6 284/429/6 +f 285/430/6 464/432/6 455/431/6 +f 285/430/6 306/433/6 464/432/6 +f 423/434/6 306/433/6 285/430/6 +f 423/434/6 305/435/6 306/433/6 +f 423/434/6 422/436/6 305/435/6 +f 423/434/6 407/437/6 422/436/6 +f 423/434/6 406/438/6 407/437/6 +f 335/439/6 406/438/6 423/434/6 +f 335/439/6 507/440/6 406/438/6 +f 335/439/6 334/441/6 507/440/6 +f 335/439/6 332/442/6 334/441/6 +f 353/443/6 332/442/6 335/439/6 +f 317/444/6 341/445/6 461/446/6 +f 317/444/6 340/447/6 341/445/6 +f 333/448/6 332/442/6 353/443/6 +f 545/449/6 332/442/6 333/448/6 +f 432/450/6 332/442/6 545/449/6 +f 433/451/6 332/442/6 432/450/6 +f 394/452/6 332/442/6 433/451/6 +f 310/453/6 384/454/6 394/452/6 +f 384/454/6 542/455/6 394/452/6 +f 542/455/6 299/456/6 394/452/6 +f 299/456/6 300/457/6 394/452/6 +f 300/457/6 332/442/6 394/452/6 +f 378/458/6 453/459/6 310/453/6 +f 453/459/6 454/460/6 310/453/6 +f 454/460/6 309/461/6 310/453/6 +f 309/461/6 383/462/6 310/453/6 +f 383/462/9 384/454/9 310/453/9 +f 317/444/6 378/458/6 340/447/6 +f 317/444/6 468/463/6 378/458/6 +f 468/463/6 419/464/6 378/458/6 +f 419/464/6 528/465/6 378/458/6 +f 528/465/6 513/466/6 378/458/6 +f 513/466/6 514/467/6 378/458/6 +f 514/467/6 397/468/6 378/458/6 +f 397/468/6 288/469/6 378/458/6 +f 288/469/6 289/470/6 378/458/6 +f 289/470/6 458/471/6 378/458/6 +f 458/471/6 393/472/6 378/458/6 +f 393/472/6 504/473/6 378/458/6 +f 504/473/6 400/474/6 378/458/6 +f 400/474/6 401/475/6 378/458/6 +f 401/475/6 377/476/6 378/458/6 +f 377/476/6 276/477/6 378/458/6 +f 276/477/6 277/478/6 378/458/6 +f 277/478/6 453/459/6 378/458/6 +f 317/444/6 318/479/6 468/463/6 +f 376/480/6 375/481/6 451/482/6 +f 376/480/6 379/483/6 375/481/6 +f 376/480/6 496/484/6 379/483/6 +f 399/485/6 496/484/6 376/480/6 +f 399/485/6 495/486/6 496/484/6 +f 399/485/6 534/487/6 495/486/6 +f 399/485/6 398/488/6 534/487/6 +f 283/489/6 398/488/6 399/485/6 +f 283/489/6 457/490/6 398/488/6 +f 283/489/6 282/491/6 457/490/6 +f 283/489/6 350/492/6 282/491/6 +f 283/489/6 349/493/6 350/492/6 +f 411/494/6 349/493/6 283/489/6 +f 411/494/6 410/495/6 349/493/6 +f 411/494/6 485/496/6 410/495/6 +f 411/494/6 297/497/6 485/496/6 +f 493/498/6 297/497/6 411/494/6 +f 303/499/6 498/500/6 304/501/6 +f 303/499/6 386/502/6 498/500/6 +f 373/503/6 297/497/6 493/498/6 +f 374/504/6 297/497/6 373/503/6 +f 405/505/6 297/497/6 374/504/6 +f 298/506/6 297/497/6 405/505/6 +f 390/507/6 297/497/6 298/506/6 +f 444/508/6 372/509/6 390/507/6 +f 372/509/6 446/510/6 390/507/6 +f 446/510/6 501/511/6 390/507/6 +f 501/511/6 389/512/6 390/507/6 +f 389/512/6 297/497/6 390/507/6 +f 357/513/6 533/514/6 444/508/6 +f 533/514/6 491/515/6 444/508/6 +f 491/515/6 443/516/6 444/508/6 +f 443/516/6 371/517/6 444/508/6 +f 371/517/6 372/509/6 444/508/6 +f 303/499/6 357/513/6 386/502/6 +f 303/499/6 474/518/6 357/513/6 +f 474/518/6 481/519/6 357/513/6 +f 481/519/6 392/520/6 357/513/6 +f 392/520/6 338/521/6 357/513/6 +f 338/521/6 339/522/6 357/513/6 +f 339/522/6 544/523/6 357/513/6 +f 544/523/6 382/524/6 357/513/6 +f 382/524/6 427/525/6 357/513/6 +f 427/525/6 520/526/6 357/513/6 +f 520/526/6 477/527/6 357/513/6 +f 477/527/6 370/528/6 357/513/6 +f 370/528/6 330/529/6 357/513/6 +f 330/529/6 331/530/6 357/513/6 +f 331/530/6 546/531/6 357/513/6 +f 546/531/6 356/532/6 357/513/6 +f 356/532/6 442/533/6 357/513/6 +f 442/533/6 533/514/6 357/513/6 +f 303/499/6 425/534/6 474/518/6 +f 450/535/6 436/536/6 480/537/6 +f 436/536/6 437/538/6 480/537/6 +f 436/536/6 532/539/6 437/538/6 +f 450/535/6 440/540/6 436/536/6 +f 450/535/6 362/541/6 440/540/6 +f 362/541/6 490/542/6 440/540/6 +f 362/541/6 363/543/6 490/542/6 +f 450/535/6 497/544/6 362/541/6 +f 450/535/6 281/272/6 497/544/6 +f 450/535/6 280/273/6 281/272/6 +f 84/545/10 385/546/10 500/547/10 +f 36/548/11 307/549/11 466/550/11 +f 243/551/12 496/552/12 495/553/12 +f 182/554/13 407/555/13 406/556/13 +f 130/557/14 472/558/14 511/559/14 +f 258/560/15 357/561/15 444/562/15 +f 47/563/16 296/564/16 476/565/16 +f 167/566/17 377/567/17 401/568/17 +f 201/569/18 394/570/18 433/571/18 +f 257/572/19 444/562/19 390/573/19 +f 39/574/20 336/575/20 479/576/20 +f 92/577/21 395/578/21 503/579/21 +f 172/580/22 309/581/22 454/582/22 +f 221/583/23 222/584/23 546/585/23 +f 52/586/15 367/587/15 348/588/15 +f 214/589/24 544/590/24 339/591/24 +f 183/592/25 422/593/25 407/555/25 +f 60/594/26 278/595/26 521/596/26 +f 261/597/27 304/598/27 498/599/27 +f 109/600/28 413/601/28 312/602/28 +f 76/603/29 325/604/29 506/605/29 +f 55/606/27 526/607/27 482/608/27 +f 101/609/30 416/610/30 279/611/30 +f 206/612/27 461/613/27 341/614/27 +f 191/615/31 543/616/31 403/617/31 +f 144/618/32 313/619/32 417/620/32 +f 68/621/33 404/622/33 434/623/33 +f 22/624/34 486/625/34 347/626/34 +f 83/627/35 500/547/35 412/628/35 +f 117/629/36 418/630/36 324/631/36 +f 233/632/37 297/633/37 389/634/37 +f 63/635/38 344/636/38 484/637/38 +f 91/638/39 503/579/39 502/639/39 +f 136/640/40 321/641/40 420/642/40 +f 151/643/41 291/644/41 508/645/41 +f 271/646/42 532/647/42 436/648/42 +f 23/649/43 487/650/43 486/625/43 +f 106/651/44 510/652/44 535/653/44 +f 164/654/45 504/655/45 393/656/45 +f 125/657/46 421/658/46 327/659/46 +f 236/660/47 349/661/47 410/662/47 +f 159/663/24 397/664/24 514/665/24 +f 30/666/47 465/667/47 408/668/47 +f 225/669/48 533/670/48 442/671/48 +f 75/672/49 506/605/49 505/673/49 +f 192/674/50 351/675/50 543/616/50 +f 49/676/51 424/677/51 329/678/51 +f 188/679/12 284/680/12 455/681/12 +f 208/682/42 425/683/42 303/607/42 +f 198/684/16 545/685/16 333/686/16 +f 98/687/52 515/688/52 292/689/52 +f 14/690/53 488/691/53 366/692/53 +f 41/693/50 426/694/50 337/695/50 +f 143/696/54 417/620/54 516/697/54 +f 216/698/55 427/699/55 382/700/55 +f 241/701/56 534/702/56 398/703/56 +f 86/704/57 275/705/57 274/444/57 +f 114/706/58 352/707/58 536/708/58 +f 180/709/59 507/710/59 334/711/59 +f 57/712/60 430/713/60 429/714/60 +f 31/715/13 489/716/13 465/667/13 +f 169/717/61 277/718/61 276/719/61 +f 135/720/62 420/642/62 517/721/62 +f 6/722/63 499/723/63 391/724/63 +f 150/725/64 508/645/64 431/726/64 +f 272/727/65 437/728/65 532/729/65 +f 249/730/66 283/731/66 399/732/66 +f 67/733/67 434/623/67 509/734/67 +f 200/735/51 433/571/51 432/736/51 +f 264/737/65 281/729/65 280/738/65 +f 122/739/68 518/740/68 537/741/68 +f 107/742/69 311/743/69 510/652/69 +f 65/744/70 328/745/70 342/746/70 +f 15/747/71 492/748/71 488/691/71 +f 228/749/34 371/750/34 443/751/34 +f 94/752/72 287/753/72 286/754/72 +f 215/755/73 382/756/73 544/590/73 +f 255/757/51 298/758/51 405/759/51 +f 238/760/25 282/761/25 350/762/25 +f 161/763/55 289/764/55 288/765/55 +f 170/766/48 453/767/48 277/718/48 +f 104/768/74 290/769/74 291/644/74 +f 25/770/75 358/771/75 438/772/75 +f 7/773/76 494/774/76 499/723/76 +f 42/775/77 308/776/77 426/694/77 +f 263/777/42 280/778/42 450/779/42 +f 158/780/76 514/665/76 513/781/76 +f 252/782/78 373/783/78 493/784/78 +f 78/785/79 294/786/79 293/787/79 +f 270/788/65 436/789/65 440/613/65 +f 99/790/80 319/791/80 515/792/80 +f 244/793/81 379/794/81 496/552/81 +f 81/795/82 396/796/82 460/797/82 +f 177/798/83 300/799/83 299/800/83 +f 89/801/84 525/802/84 360/803/84 +f 142/804/85 516/697/85 435/805/85 +f 33/806/86 414/807/86 441/808/86 +f 70/809/87 302/810/87 301/811/87 +f 34/812/88 512/813/88 414/807/88 +f 115/814/89 323/815/89 352/707/89 +f 224/816/90 442/671/90 356/817/90 +f 207/818/91 303/819/91 304/820/91 +f 134/821/92 517/721/92 365/683/92 +f 185/822/88 306/823/88 305/824/88 +f 162/825/93 458/826/93 289/764/93 +f 123/827/94 326/828/94 518/740/94 +f 50/829/18 439/830/18 424/677/18 +f 230/831/95 446/832/95 372/833/95 +f 58/834/96 387/835/96 430/713/96 +f 43/836/66 415/837/66 308/776/66 +f 17/838/97 354/839/97 447/840/97 +f 108/841/98 312/602/98 311/743/98 +f 254/842/99 405/759/99 374/843/99 +f 145/844/100 314/845/100 313/619/100 +f 9/846/73 368/847/73 448/848/73 +f 210/849/101 481/850/101 474/851/101 +f 153/647/42 318/646/42 317/852/42 +f 73/853/102 315/854/102 462/855/102 +f 100/856/103 279/611/103 319/791/103 +f 20/857/104 538/858/104 523/859/104 +f 246/860/31 451/861/31 375/862/31 +f 199/863/99 432/736/99 545/864/99 +f 178/865/37 332/866/37 300/799/37 +f 218/867/105 477/868/105 520/869/105 +f 137/870/106 322/871/106 321/641/106 +f 186/872/56 464/873/56 306/823/56 +f 35/874/56 466/550/56 512/813/56 +f 88/875/107 360/803/107 316/876/107 +f 116/877/108 324/631/108 323/815/108 +f 28/878/109 539/879/109 295/880/109 +f 105/881/110 535/653/110 290/769/110 +f 256/882/18 390/573/18 298/758/18 +f 202/883/19 310/884/19 394/570/19 +f 171/885/104 454/582/104 453/767/104 +f 124/886/111 327/887/111 326/828/111 +f 51/888/19 348/588/19 439/830/19 +f 156/889/112 528/890/112 419/891/112 +f 59/892/113 521/596/113 387/835/113 +f 96/893/114 345/894/114 456/895/114 +f 48/896/99 329/678/99 296/897/99 +f 273/688/27 480/687/27 437/898/27 +f 221/583/71 331/899/71 330/900/71 +f 194/901/66 423/902/66 285/903/66 +f 163/904/105 393/656/105 458/826/105 +f 247/905/50 376/906/50 451/861/50 +f 148/907/115 343/908/115 428/909/115 +f 80/910/116 460/797/116 459/911/116 +f 40/912/31 337/695/31 336/575/31 +f 19/913/48 523/859/48 355/914/48 +f 206/820/91 152/819/91 317/915/91 +f 213/916/76 339/591/76 338/917/76 +f 12/918/105 540/919/105 524/920/105 +f 56/921/117 429/714/117 388/922/117 +f 179/923/109 334/924/109 332/879/109 +f 205/564/118 341/563/118 340/925/118 +f 223/926/97 356/817/97 546/585/97 +f 97/927/119 292/689/119 345/894/119 +f 72/928/120 462/855/120 364/929/120 +f 140/930/121 529/931/121 471/932/121 +f 27/933/37 295/880/37 359/934/37 +f 64/935/122 342/746/122 344/636/122 +f 231/936/75 501/937/75 446/832/75 +f 187/938/11 455/681/11 464/873/11 +f 113/939/123 536/708/123 527/940/123 +f 268/941/65 490/942/65 363/943/65 +f 237/944/13 350/762/13 349/661/13 +f 121/945/124 537/741/124 530/946/124 +f 248/947/77 399/732/77 376/906/77 +f 110/948/125 346/949/125 413/950/125 +f 193/951/77 285/903/77 351/675/77 +f 239/952/86 457/953/86 282/761/86 +f 45/954/126 475/613/126 409/955/126 +f 11/956/93 524/920/93 369/957/93 +f 4/958/101 541/959/101 449/960/101 +f 197/961/78 333/686/78 353/962/78 +f 232/963/83 389/634/83 501/937/83 +f 18/964/61 355/914/61 354/839/61 +f 87/965/127 316/876/127 275/705/127 +f 132/966/128 531/967/128 473/968/128 +f 220/969/53 330/900/53 370/970/53 +f 240/971/88 398/703/88 457/953/88 +f 102/972/129 452/973/129 416/610/129 +f 168/974/97 276/719/97 377/567/97 +f 147/975/130 428/909/130 467/976/130 +f 26/977/83 359/934/83 358/771/83 +f 212/978/63 338/917/63 392/979/63 +f 3/980/65 449/960/65 381/819/65 +f 155/981/131 419/891/131 468/982/131 +f 264/983/27 265/984/27 497/985/27 +f 173/986/34 383/987/34 309/581/34 +f 118/988/132 469/989/132 418/630/132 +f 267/990/42 363/950/42 362/789/42 +f 37/991/12 478/992/12 307/549/12 +f 139/993/133 471/932/133 470/994/133 +f 95/995/134 456/895/134 287/753/134 +f 204/996/27 340/997/27 378/998/27 +f 260/999/118 498/1000/118 386/1001/118 +f 126/1002/135 361/1003/135 421/658/135 +f 82/1004/136 412/628/136 396/796/136 +f 131/1005/137 473/968/137 472/558/137 +f 10/1006/55 369/957/55 368/866/55 +f 90/1007/138 502/639/138 525/802/138 +f 46/1008/78 476/565/78 475/613/78 +f 229/1009/43 372/833/43 371/750/43 +f 53/1010/27 463/1011/27 367/898/27 +f 1/1012/91 380/1013/91 526/1014/91 +f 219/1015/45 370/970/45 477/868/45 +f 253/1016/16 374/1017/16 373/783/16 +f 61/985/139 483/1018/139 278/595/139 +f 165/1019/53 400/1020/53 504/655/53 +f 38/1021/81 479/576/81 478/992/81 +f 79/1022/140 459/911/140 294/786/140 +f 74/1023/141 505/673/141 315/1024/141 +f 262/1025/91 450/1026/91 480/537/91 +f 245/1027/20 375/862/20 379/794/20 +f 189/1028/81 402/1029/81 284/680/81 +f 211/1030/112 392/979/112 481/850/112 +f 2/1031/42 381/1032/42 380/601/42 +f 71/1033/142 364/929/142 302/810/142 +f 234/1034/109 485/843/109 297/1035/109 +f 203/633/15 378/632/15 310/884/15 +f 196/1036/126 353/962/126 335/1037/126 +f 174/1038/43 384/1039/43 383/987/43 +f 176/1040/75 299/800/75 542/1041/75 +f 21/1042/22 347/626/22 538/858/22 +f 85/1043/143 274/1044/143 385/546/143 +f 181/1045/47 406/556/47 507/710/47 +f 54/1046/118 482/1047/118 463/728/118 +f 259/1017/27 386/1016/27 357/1048/27 +f 184/1049/86 305/824/86 422/593/86 +f 29/1050/59 408/668/59 539/887/59 +f 66/1051/144 509/734/144 328/745/144 +f 62/1052/145 484/637/145 483/915/145 +f 235/1053/59 410/662/59 485/1054/59 +f 226/1055/104 491/1056/104 533/670/104 +f 112/1057/146 527/940/146 519/1058/146 +f 111/1059/147 519/1058/147 346/949/147 +f 13/1060/45 366/692/45 540/919/45 +f 24/1061/95 438/772/95 487/650/95 +f 266/1062/65 362/943/65 497/1063/65 +f 157/1064/63 513/781/63 528/890/63 +f 103/1065/148 388/922/148 452/973/148 +f 146/1066/149 467/976/149 314/845/149 +f 149/1067/150 431/726/150 343/1068/150 +f 195/1069/151 335/1037/151 423/902/151 +f 154/1070/65 468/982/65 318/1071/65 +f 141/1072/152 435/805/152 529/931/152 +f 93/1073/153 286/754/153 395/578/153 +f 119/1074/154 522/1075/154 469/989/154 +f 242/1076/11 495/553/11 534/702/11 +f 120/870/155 530/946/155 522/1075/155 +f 32/1077/25 441/808/25 489/716/25 +f 138/1078/156 470/994/156 322/871/156 +f 128/1079/157 320/1080/157 445/1081/157 +f 269/598/27 440/597/27 490/983/27 +f 160/1082/73 288/1083/73 397/664/73 +f 129/1084/158 511/559/158 320/1080/158 +f 227/1085/22 443/751/22 491/1056/22 +f 166/1086/71 401/568/71 400/1020/71 +f 127/1087/159 445/1081/159 361/1003/159 +f 250/1088/151 411/1089/151 283/731/151 +f 44/1090/151 409/955/151 415/837/151 +f 77/1091/160 293/787/160 325/604/160 +f 16/1092/17 447/840/17 492/748/17 +f 133/1093/161 365/847/161 531/967/161 +f 251/1094/126 493/784/126 411/1089/126 +f 190/1095/20 403/617/20 402/1029/20 +f 5/1096/112 391/724/112 541/959/112 +f 209/1097/65 474/851/65 425/1098/65 +f 8/1099/24 448/848/24 494/774/24 +f 69/1100/162 301/811/162 404/622/162 +f 175/1101/95 542/1041/95 384/1039/95 +f 217/1102/93 520/869/93 427/699/93 +f 83/627/10 84/545/10 500/547/10 +f 35/874/11 36/548/11 466/550/11 +f 242/1076/12 243/551/12 495/553/12 +f 181/1045/13 182/554/13 406/556/13 +f 129/1084/14 130/557/14 511/559/14 +f 257/572/15 258/560/15 444/562/15 +f 46/1008/16 47/563/16 476/565/16 +f 166/1086/23 167/566/23 401/568/23 +f 200/735/18 201/569/18 433/571/18 +f 256/882/19 257/572/19 390/573/19 +f 38/1021/163 39/574/163 479/576/163 +f 91/638/21 92/577/21 503/579/21 +f 171/885/22 172/580/22 454/582/22 +f 331/899/17 221/583/17 546/585/17 +f 51/888/15 52/586/15 348/588/15 +f 213/916/24 214/589/24 339/591/24 +f 182/554/25 183/592/25 407/555/25 +f 59/892/26 60/594/26 521/596/26 +f 260/1103/27 261/597/27 498/599/27 +f 108/841/28 109/600/28 312/602/28 +f 75/672/164 76/603/164 506/605/164 +f 54/1104/27 55/606/27 482/608/27 +f 100/856/30 101/609/30 279/611/30 +f 205/1105/27 206/612/27 341/614/27 +f 190/1095/31 191/615/31 403/617/31 +f 143/696/32 144/618/32 417/620/32 +f 67/733/33 68/621/33 434/623/33 +f 21/1042/34 22/624/34 347/626/34 +f 82/1004/35 83/627/35 412/628/35 +f 116/877/36 117/629/36 324/631/36 +f 232/963/37 233/632/37 389/634/37 +f 62/1052/38 63/635/38 484/637/38 +f 90/1007/39 91/638/39 502/639/39 +f 135/720/40 136/640/40 420/642/40 +f 150/725/41 151/643/41 508/645/41 +f 270/778/42 271/646/42 436/648/42 +f 22/624/43 23/649/43 486/625/43 +f 105/881/44 106/651/44 535/653/44 +f 163/904/45 164/654/45 393/656/45 +f 124/1035/46 125/657/46 327/659/46 +f 235/1053/47 236/660/47 410/662/47 +f 158/780/24 159/663/24 514/665/24 +f 29/1050/47 30/666/47 408/668/47 +f 224/816/48 225/669/48 442/671/48 +f 74/1023/49 75/672/49 505/673/49 +f 191/615/50 192/674/50 543/616/50 +f 48/896/51 49/676/51 329/678/51 +f 187/938/12 188/679/12 455/681/12 +f 207/606/42 208/682/42 303/607/42 +f 197/961/16 198/684/16 333/686/16 +f 97/927/52 98/687/52 292/689/52 +f 13/1060/53 14/690/53 366/692/53 +f 40/912/50 41/693/50 337/695/50 +f 142/804/54 143/696/54 516/697/54 +f 215/765/55 216/698/55 382/700/55 +f 240/971/56 241/701/56 398/703/56 +f 85/908/57 86/704/57 274/444/57 +f 113/939/58 114/706/58 536/708/58 +f 179/1054/165 180/709/165 334/711/165 +f 56/921/60 57/712/60 429/714/60 +f 30/666/13 31/715/13 465/667/13 +f 168/974/90 169/717/90 276/719/90 +f 134/821/62 135/720/62 517/721/62 +f 5/1096/63 6/722/63 391/724/63 +f 149/1067/64 150/725/64 431/726/64 +f 271/737/65 272/727/65 532/729/65 +f 248/947/66 249/730/66 399/732/66 +f 66/1051/67 67/733/67 509/734/67 +f 199/863/51 200/735/51 432/736/51 +f 263/854/65 264/737/65 280/738/65 +f 121/945/68 122/739/68 537/741/68 +f 106/651/69 107/742/69 510/652/69 +f 64/935/70 65/744/70 342/746/70 +f 14/690/71 15/747/71 488/691/71 +f 227/1085/34 228/749/34 443/751/34 +f 93/1073/72 94/752/72 286/754/72 +f 214/589/73 215/755/73 544/590/73 +f 254/842/51 255/757/51 405/759/51 +f 237/944/25 238/760/25 350/762/25 +f 160/700/55 161/763/55 288/765/55 +f 169/717/48 170/766/48 277/718/48 +f 151/643/74 104/768/74 291/644/74 +f 24/1061/75 25/770/75 438/772/75 +f 6/722/76 7/773/76 499/723/76 +f 41/693/77 42/775/77 426/694/77 +f 262/1106/42 263/777/42 450/779/42 +f 157/1064/76 158/780/76 513/781/76 +f 251/1094/78 252/782/78 493/784/78 +f 77/1091/79 78/785/79 293/787/79 +f 269/612/65 270/788/65 440/613/65 +f 98/1063/80 99/790/80 515/792/80 +f 243/551/81 244/793/81 496/552/81 +f 80/910/82 81/795/82 460/797/82 +f 176/1040/83 177/798/83 299/800/83 +f 88/875/84 89/801/84 360/803/84 +f 141/1072/85 142/804/85 435/805/85 +f 32/1077/86 33/806/86 441/808/86 +f 69/1100/87 70/809/87 301/811/87 +f 33/806/88 34/812/88 414/807/88 +f 114/706/89 115/814/89 352/707/89 +f 223/926/61 224/816/61 356/817/61 +f 261/1107/91 207/818/91 304/820/91 +f 133/682/92 134/821/92 365/683/92 +f 184/1049/88 185/822/88 305/824/88 +f 161/763/93 162/825/93 289/764/93 +f 122/739/94 123/827/94 518/740/94 +f 49/676/18 50/829/18 424/677/18 +f 229/1009/95 230/831/95 372/833/95 +f 57/712/96 58/834/96 430/713/96 +f 42/775/66 43/836/66 308/776/66 +f 16/1092/97 17/838/97 447/840/97 +f 107/742/98 108/841/98 311/743/98 +f 253/1034/99 254/842/99 374/843/99 +f 144/618/100 145/844/100 313/619/100 +f 8/1099/73 9/846/73 448/848/73 +f 209/1097/101 210/849/101 474/851/101 +f 152/1001/42 153/647/42 317/852/42 +f 72/928/102 73/853/102 462/855/102 +f 99/790/103 100/856/103 319/791/103 +f 19/913/104 20/857/104 523/859/104 +f 245/1027/31 246/860/31 375/862/31 +f 198/1108/99 199/863/99 545/864/99 +f 177/798/37 178/865/37 300/799/37 +f 217/1102/105 218/867/105 520/869/105 +f 136/640/106 137/870/106 321/641/106 +f 185/822/56 186/872/56 306/823/56 +f 34/812/56 35/874/56 512/813/56 +f 87/965/107 88/875/107 316/876/107 +f 115/814/108 116/877/108 323/815/108 +f 27/933/109 28/878/109 295/880/109 +f 104/768/110 105/881/110 290/769/110 +f 255/757/18 256/882/18 298/758/18 +f 201/569/19 202/883/19 394/570/19 +f 170/766/104 171/885/104 453/767/104 +f 123/827/111 124/886/111 326/828/111 +f 50/829/19 51/888/19 439/830/19 +f 155/981/112 156/889/112 419/891/112 +f 58/834/113 59/892/113 387/835/113 +f 95/995/114 96/893/114 456/895/114 +f 47/990/99 48/896/99 296/897/99 +f 272/685/27 273/688/27 437/898/27 +f 220/969/71 221/583/71 330/900/71 +f 193/951/66 194/901/66 285/903/66 +f 162/825/105 163/904/105 458/826/105 +f 246/860/50 247/905/50 451/861/50 +f 147/975/115 148/907/115 428/909/115 +f 79/1022/116 80/910/116 459/911/116 +f 39/574/31 40/912/31 336/575/31 +f 18/964/48 19/913/48 355/914/48 +f 461/1109/91 206/820/91 317/915/91 +f 212/978/76 213/916/76 338/917/76 +f 11/956/105 12/918/105 524/920/105 +f 103/1065/117 56/921/117 388/922/117 +f 178/878/109 179/923/109 332/879/109 +f 204/1110/118 205/564/118 340/925/118 +f 222/584/97 223/926/97 546/585/97 +f 96/893/119 97/927/119 345/894/119 +f 71/1033/120 72/928/120 364/929/120 +f 139/993/121 140/930/121 471/932/121 +f 26/977/166 27/933/166 359/934/166 +f 63/635/122 64/935/122 344/636/122 +f 230/831/75 231/936/75 446/832/75 +f 186/872/11 187/938/11 464/873/11 +f 112/1057/123 113/939/123 527/940/123 +f 267/1062/65 268/941/65 363/943/65 +f 236/660/13 237/944/13 349/661/13 +f 120/870/124 121/945/124 530/946/124 +f 247/905/77 248/947/77 376/906/77 +f 109/907/125 110/948/125 413/950/125 +f 192/674/77 193/951/77 351/675/77 +f 238/760/86 239/952/86 282/761/86 +f 44/1090/126 45/954/126 409/955/126 +f 10/1006/93 11/956/93 369/957/93 +f 3/980/101 4/958/101 449/960/101 +f 196/1036/78 197/961/78 353/962/78 +f 231/936/83 232/963/83 501/937/83 +f 17/838/90 18/964/90 354/839/90 +f 86/704/127 87/965/127 275/705/127 +f 131/1005/128 132/966/128 473/968/128 +f 219/1015/53 220/969/53 370/970/53 +f 239/952/88 240/971/88 457/953/88 +f 101/609/129 102/972/129 416/610/129 +f 167/566/97 168/974/97 377/567/97 +f 146/1066/130 147/975/130 467/976/130 +f 25/770/83 26/977/83 358/771/83 +f 211/1030/63 212/978/63 392/979/63 +f 2/818/65 3/980/65 381/819/65 +f 154/1070/101 155/981/101 468/982/101 +f 281/1111/27 264/983/27 497/985/27 +f 172/580/34 173/986/34 309/581/34 +f 117/629/132 118/988/132 418/630/132 +f 266/788/42 267/990/42 362/789/42 +f 36/548/12 37/991/12 307/549/12 +f 138/1078/133 139/993/133 470/994/133 +f 94/752/134 95/995/134 287/753/134 +f 203/1112/27 204/996/27 378/998/27 +f 259/852/118 260/999/118 386/1001/118 +f 125/657/135 126/1002/135 421/658/135 +f 81/795/136 82/1004/136 396/796/136 +f 130/557/137 131/1005/137 472/558/137 +f 9/865/55 10/1006/55 368/866/55 +f 89/801/138 90/1007/138 525/802/138 +f 45/954/78 46/1008/78 475/613/78 +f 228/749/43 229/1009/43 371/750/43 +f 52/1113/27 53/1010/27 367/898/27 +f 55/1018/91 1/1012/91 526/1014/91 +f 218/867/45 219/1015/45 477/868/45 +f 252/782/16 253/1016/16 373/783/16 +f 60/594/139 61/985/139 278/595/139 +f 164/654/53 165/1019/53 504/655/53 +f 37/991/81 38/1021/81 478/992/81 +f 78/785/140 79/1022/140 294/786/140 +f 73/1032/141 74/1023/141 315/1024/141 +f 273/1114/91 262/1025/91 480/537/91 +f 244/793/163 245/1027/163 379/794/163 +f 188/679/81 189/1028/81 284/680/81 +f 210/849/112 211/1030/112 481/850/112 +f 1/600/42 2/1031/42 380/601/42 +f 70/809/142 71/1033/142 302/810/142 +f 233/659/109 234/1034/109 297/1035/109 +f 202/883/15 203/633/15 310/884/15 +f 195/1069/126 196/1036/126 335/1037/126 +f 173/986/43 174/1038/43 383/987/43 +f 175/1101/75 176/1040/75 542/1041/75 +f 20/857/22 21/1042/22 538/858/22 +f 84/545/167 85/1043/167 385/546/167 +f 180/709/47 181/1045/47 507/710/47 +f 53/727/118 54/1046/118 463/728/118 +f 258/996/27 259/1017/27 357/1048/27 +f 183/592/86 184/1049/86 422/593/86 +f 28/886/165 29/1050/165 539/887/165 +f 65/744/144 66/1051/144 328/745/144 +f 61/819/145 62/1052/145 483/915/145 +f 234/711/165 235/1053/165 485/1054/165 +f 225/669/104 226/1055/104 533/670/104 +f 111/1059/146 112/1057/146 519/1058/146 +f 110/948/147 111/1059/147 346/949/147 +f 12/918/45 13/1060/45 540/919/45 +f 23/649/95 24/1061/95 487/650/95 +f 265/792/65 266/1062/65 497/1063/65 +f 156/889/63 157/1064/63 528/890/63 +f 102/972/148 103/1065/148 452/973/148 +f 145/844/149 146/1066/149 314/845/149 +f 148/1115/150 149/1067/150 343/1068/150 +f 194/901/151 195/1069/151 423/902/151 +f 153/1116/65 154/1070/65 318/1071/65 +f 140/930/152 141/1072/152 529/931/152 +f 92/577/153 93/1073/153 395/578/153 +f 118/988/154 119/1074/154 469/989/154 +f 241/701/11 242/1076/11 534/702/11 +f 119/1074/155 120/870/155 522/1075/155 +f 31/715/25 32/1077/25 489/716/25 +f 137/870/156 138/1078/156 322/871/156 +f 127/1087/157 128/1079/157 445/1081/157 +f 268/1111/27 269/598/27 490/983/27 +f 159/663/73 160/1082/73 397/664/73 +f 128/1079/158 129/1084/158 320/1080/158 +f 226/1055/22 227/1085/22 491/1056/22 +f 165/1019/71 166/1086/71 400/1020/71 +f 126/1002/159 127/1087/159 361/1003/159 +f 249/730/151 250/1088/151 283/731/151 +f 43/836/151 44/1090/151 415/837/151 +f 76/603/160 77/1091/160 325/604/160 +f 15/747/23 16/1092/23 492/748/23 +f 132/966/161 133/1093/161 531/967/161 +f 250/1088/126 251/1094/126 411/1089/126 +f 189/1028/163 190/1095/163 402/1029/163 +f 4/958/112 5/1096/112 541/959/112 +f 208/924/65 209/1097/65 425/1098/65 +f 7/773/24 8/1099/24 494/774/24 +f 68/621/162 69/1100/162 404/622/162 +f 174/1038/95 175/1101/95 384/1039/95 +f 216/698/93 217/1102/93 427/699/93 diff --git a/src/main/resources/assets/avatarmod/shaders/bloom_h.frag b/src/main/resources/assets/avatarmod/shaders/bloom_h.frag new file mode 100644 index 0000000000..9bb17cba55 --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/bloom_h.frag @@ -0,0 +1,17 @@ +#version 120 + +const float[] gauss = float[](0.197448, 0.174697, 0.120999, 0.065602, 0.02784, 0.009246, 0.002403, 0.000489); + +uniform sampler2D texture; +uniform float frag_width; + +varying vec2 tex_coord; + +void main(){ + vec4 final_color = vec4(0.0); + for(int i = 0; i < gauss.length()*2-1; i ++){ + int place = i-gauss.length()+1; + final_color += gauss[int(abs(float(place)))]*texture2D(texture, tex_coord + vec2(frag_width*place, 0)); + } + gl_FragColor = final_color; +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/bloom_h.vert b/src/main/resources/assets/avatarmod/shaders/bloom_h.vert new file mode 100644 index 0000000000..0773fcf1fc --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/bloom_h.vert @@ -0,0 +1,8 @@ +#version 120 + +varying vec2 tex_coord; + +void main(){ + tex_coord = gl_MultiTexCoord0.st; + gl_Position = gl_Vertex; +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/bloom_test.frag b/src/main/resources/assets/avatarmod/shaders/bloom_test.frag new file mode 100644 index 0000000000..b775bee267 --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/bloom_test.frag @@ -0,0 +1,7 @@ +#version 120 + +uniform vec4 color; + +void main(){ + gl_FragColor = color; +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/bloom_test.vert b/src/main/resources/assets/avatarmod/shaders/bloom_test.vert new file mode 100644 index 0000000000..91b6b1cae9 --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/bloom_test.vert @@ -0,0 +1,5 @@ +#version 120 + +void main(){ + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/bloom_v.frag b/src/main/resources/assets/avatarmod/shaders/bloom_v.frag new file mode 100644 index 0000000000..8e0447e3c6 --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/bloom_v.frag @@ -0,0 +1,17 @@ +#version 120 + +const float[] gauss = float[](0.197448, 0.174697, 0.120999, 0.065602, 0.02784, 0.009246, 0.002403, 0.000489); + +uniform sampler2D texture; +uniform float frag_height; + +varying vec2 tex_coord; + +void main(){ + vec4 final_color = vec4(0.0); + for(int i = 0; i < gauss.length()*2-1; i ++){ + int place = i-gauss.length()+1; + final_color += gauss[int(abs(float(place)))]*texture2D(texture, tex_coord + vec2(0, frag_height*place)); + } + gl_FragColor = final_color; +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/bloom_v.vert b/src/main/resources/assets/avatarmod/shaders/bloom_v.vert new file mode 100644 index 0000000000..0773fcf1fc --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/bloom_v.vert @@ -0,0 +1,8 @@ +#version 120 + +varying vec2 tex_coord; + +void main(){ + tex_coord = gl_MultiTexCoord0.st; + gl_Position = gl_Vertex; +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/crucible_lightning.frag b/src/main/resources/assets/avatarmod/shaders/crucible_lightning.frag new file mode 100644 index 0000000000..1b0593c357 --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/crucible_lightning.frag @@ -0,0 +1,7 @@ +#version 120 + +varying vec4 color; + +void main(){ + gl_FragColor = color; +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/crucible_lightning.vert b/src/main/resources/assets/avatarmod/shaders/crucible_lightning.vert new file mode 100644 index 0000000000..14fac81283 --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/crucible_lightning.vert @@ -0,0 +1,18 @@ +#version 120 + +attribute vec3 pos; +attribute vec2 tex; +attribute vec4 in_color; + +uniform sampler2D noise; +uniform float time; + +varying vec4 color; + +void main(){ + color = in_color; + vec3 noise_a = texture2DLod(noise, tex.ss + vec2(time*0.001, time*-0.02), 0).xyz; + vec3 noise_b = texture2DLod(noise, tex.ss + vec2(time*0.01, time*0.015), 0).xyz; + vec3 offset = (noise_a.xyz*noise_b.zxy-vec3(0.5))*0.1; + gl_Position = gl_ModelViewProjectionMatrix * vec4(pos+offset, 1); +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/downsample.frag b/src/main/resources/assets/avatarmod/shaders/downsample.frag new file mode 100644 index 0000000000..ddd1b332ae --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/downsample.frag @@ -0,0 +1,14 @@ +#version 120 + +uniform vec2 texel; +uniform sampler2D tex; + +varying vec2 tex_coord; + +void main(){ + vec4 color = texture2D(tex, tex_coord + vec2(texel.x, texel.y)); + color += texture2D(tex, tex_coord + vec2(-texel.x, texel.y)); + color += texture2D(tex, tex_coord + vec2(texel.x, -texel.y)); + color += texture2D(tex, tex_coord + vec2(-texel.x, -texel.y)); + gl_FragColor = color*0.25; +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/downsample.vert b/src/main/resources/assets/avatarmod/shaders/downsample.vert new file mode 100644 index 0000000000..0773fcf1fc --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/downsample.vert @@ -0,0 +1,8 @@ +#version 120 + +varying vec2 tex_coord; + +void main(){ + tex_coord = gl_MultiTexCoord0.st; + gl_Position = gl_Vertex; +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/flashlight_deferred.frag b/src/main/resources/assets/avatarmod/shaders/flashlight_deferred.frag new file mode 100644 index 0000000000..1c88b346f9 --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/flashlight_deferred.frag @@ -0,0 +1,31 @@ +#version 120 + +uniform sampler2D colors; +uniform sampler2D positions; +uniform sampler2D normals; +uniform sampler2D proj_coords; +uniform sampler2D shadowTex; +uniform sampler2D flashlightTex; +uniform vec2 windowSize; +uniform vec3 pos; +uniform float height; + +void main(){ + vec2 tex = gl_FragCoord.xy/windowSize; + vec4 color = texture2D(colors, tex); + vec3 worldPos = texture2D(positions, tex).xyz; + vec3 proj_coord = texture2D(proj_coords, tex).xyz; + vec3 normal = texture2D(normals, tex).xyz; + + //Clamp it so only the fragments that fit on the flashlight texture show up + int test = int(proj_coord.s >= 0 && proj_coord.s <= 1 && proj_coord.t >= 0 && proj_coord.t <= 1); + //Dot product, fragments that the flashlight directly faces shound be brighter, while normals parallel to the light direction should be dimmer. + float dproduct = dot(normal, -normalize(worldPos - pos)); + //Fade with distance, light becomes less bright as it reaches the end of its cone. + float distanceFade = 1-length(worldPos - pos)/height; + //The shadow calculation, how much of it is in the light + float shadow = proj_coord.p; + + //Multiply everything together to get the final color (also threw in a 2 so it looked bright enough) + gl_FragColor = vec4(texture2D(flashlightTex, proj_coord.st).rgb*color.rgb*2*test*distanceFade*dproduct*shadow, 1); +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/flashlight_deferred.vert b/src/main/resources/assets/avatarmod/shaders/flashlight_deferred.vert new file mode 100644 index 0000000000..fd88ecc211 --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/flashlight_deferred.vert @@ -0,0 +1,5 @@ +#version 120 + +void main(){ + gl_Position = gl_Vertex; +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/flashlight_nogeo.frag b/src/main/resources/assets/avatarmod/shaders/flashlight_nogeo.frag new file mode 100644 index 0000000000..993c939c8c --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/flashlight_nogeo.frag @@ -0,0 +1,64 @@ +#version 120 + +//const int radius = 1; + +uniform float angle; +uniform vec3 pos; +uniform vec3 direction; +uniform float height; +uniform sampler2D flashlightTex; +uniform sampler2D shadowTex; +uniform sampler2D mc_tex; + +varying vec3 worldPos; +varying vec3 normal; +varying vec3 color; +varying vec4 fragPosShadowSpace; +varying vec2 texture_coord; + +//float calcShadow(vec3 proj_coord){ + //float texel = 1/1024; + //float light = 0; + //for(int i = -radius; i <= radius; i ++){ + // for(int j = -radius; j <= radius; j ++){ + // float shadow = texture2D(shadowTex, proj_coord.st + vec2(i, j)*texel).r; + // light += float(shadow + 0.00018 > proj_coord.p); + // } + //} + //float shadow1 = texture2D(shadowTex, proj_coord.st).r; + //If the shadow + an arbitrary bias so fragments don't shadow themselves is less than the flashlight projected depth, it's in shadow, and we don't light it up. + //if(shadow1 + 0.00018 <= proj_coord.p){ + // return 0; + //} + //float area = radius*2 + 1; + //area = area * area; + //return 1; +//} + +float calcShadow(vec3 proj_coord){ + float shadow = 0.0; + vec2 texelSize = 1.0 / vec2(1024); + for(int x = -1; x <= 1; ++x) + { + for(int y = -1; y <= 1; ++y) + { + float pcfDepth = texture2D(shadowTex, proj_coord.xy + vec2(x, y) * texelSize).r; + shadow += proj_coord.z - 0.0001777 > pcfDepth ? 1.0 : 0.0; + } + } + shadow /= 9.0; + return 1-shadow; +} + +void main(){ + //Perspective divide and remap from -1 to 1 space to the texture coordinate 0 to 1 space + vec3 proj_coord = fragPosShadowSpace.xyz/fragPosShadowSpace.w; + proj_coord = proj_coord * 0.5 + 0.5; + float shadow = calcShadow(proj_coord); + proj_coord.p = shadow; + + gl_FragData[0] = texture2D(mc_tex, texture_coord); + gl_FragData[1] = vec4(worldPos, 1); + gl_FragData[2] = vec4(proj_coord, 1); + gl_FragData[3] = vec4(normal, 1); +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/flashlight_nogeo.vert b/src/main/resources/assets/avatarmod/shaders/flashlight_nogeo.vert new file mode 100644 index 0000000000..769dbef273 --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/flashlight_nogeo.vert @@ -0,0 +1,23 @@ +#version 120 + +uniform mat4 shadow_view; +uniform mat4 shadow_proj; +uniform mat4 mc_view; + +varying vec3 worldPos; +varying vec3 color; +varying vec4 fragPosShadowSpace; +varying vec2 texture_coord; +varying vec3 normal; + +void main(){ + vec3 pos = gl_Vertex.xyz; + color = gl_Color.rgb; + texture_coord = gl_MultiTexCoord0.st; + vec4 world = mc_view * gl_ModelViewMatrix * gl_Vertex; + worldPos = world.xyz; + gl_Position = gl_ProjectionMatrix * world; + normal = (mat3(mc_view) * gl_NormalMatrix * gl_Normal).xyz; + + fragPosShadowSpace = shadow_proj * shadow_view * gl_ModelViewMatrix * gl_Vertex; +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/gpu_particle_render.frag b/src/main/resources/assets/avatarmod/shaders/gpu_particle_render.frag new file mode 100644 index 0000000000..af1b68a63f --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/gpu_particle_render.frag @@ -0,0 +1,15 @@ +#version 120 + +varying vec2 pass_tex; +varying vec2 pass_lightmap; +varying vec4 pass_color; + +uniform sampler2D texture; +uniform sampler2D lightmap; + +void main(){ + vec4 tex = texture2D(texture, pass_tex); + vec4 lmap = texture2D(lightmap, pass_lightmap); + + gl_FragColor = tex * lmap * pass_color; +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/gpu_particle_render.vert b/src/main/resources/assets/avatarmod/shaders/gpu_particle_render.vert new file mode 100644 index 0000000000..65054b3027 --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/gpu_particle_render.vert @@ -0,0 +1,63 @@ +#version 120 +#extension GL_EXT_gpu_shader4 : enable + +//Verticals are flipped because for some reason textures are upside down otherwise +const vec2 BOTTOM_LEFT = vec2(-0.5, 0.5); +const vec2 BOTTOM_RIGHT = vec2(0.5, 0.5); +const vec2 TOP_LEFT = vec2(-0.5, -0.5); +const vec2 TOP_RIGHT = vec2(0.5, -0.5); +const int PARTICLE_TEX_SIZE = 1024; +const int MAX_PARTICLE_TYPES = 1; + +uniform mat4 modelview; +uniform mat4 projection; +uniform mat4 invPlayerRot; +//Contains position and color +uniform sampler2D particleData0; +//Contains velocity and scale +uniform sampler2D particleData1; +//Contains age, max age, and particle id +uniform sampler2D particleData2; +uniform vec4 particleTypeTexCoords[MAX_PARTICLE_TYPES]; + +varying vec2 pass_tex; +varying vec2 pass_lightmap; +varying vec4 pass_color; + +vec4 colorFromFloat(float f){ + int argb = int(f*2147483647); + float a = (argb >> 24) & 0xFF; + float r = (argb >> 16) & 0xFF; + float g = (argb >> 8) & 0xFF; + float b = (argb) & 0xFF; + return vec4(r, g, b, a); +} + +void main(){ + vec3 pos = gl_Position.xyz; + vec2 particle_coord = vec2((gl_InstanceID%PARTICLE_TEX_SIZE)/PARTICLE_TEX_SIZE, + (gl_InstanceID/PARTICLE_TEX_SIZE)/PARTICLE_TEX_SIZE); + vec4 dat0 = texture2DLod(particleData0, particle_coord, 0); + vec4 dat1 = texture2DLod(particleData1, particle_coord, 0); + vec4 dat2 = texture2DLod(particleData2, particle_coord, 0); + + int particleId = int(dat2.z*32767); + vec3 offsetPos = dat0.xyz; + vec4 color = colorFromFloat(dat0.w); + float scale = dat1.w; + vec4 texData = particleTypeTexCoords[particleId]; + vec2 lightmap = vec2(0.94117647058, 0.94117647058); + + vec2 tex = texData.xy*float((pos.xy == BOTTOM_LEFT)) + + vec2(texData.x+texData.z, texData.y)*float((pos.xy == BOTTOM_RIGHT)) + + vec2(texData.x, texData.y+texData.w)*float((pos.xy == TOP_LEFT)) + + (texData.xy+texData.zw)*float((pos.xy == TOP_RIGHT)); + + pass_tex = tex; + pass_lightmap = lightmap; + pass_color = color; + + vec4 position = invPlayerRot * vec4(pos*scale, 1); + position = modelview * vec4(position.xyz+offsetPos, position.w); + gl_Position = projection*position; +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/gpu_particle_update.frag b/src/main/resources/assets/avatarmod/shaders/gpu_particle_update.frag new file mode 100644 index 0000000000..a002f16572 --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/gpu_particle_update.frag @@ -0,0 +1,53 @@ +#version 120 +#extension GL_EXT_gpu_shader4 : enable + +//Contains position and color +uniform sampler2D particleData0; +//Contains velocity and scale +uniform sampler2D particleData1; +//Contains age, max age, and particle id +uniform sampler2D particleData2; + +varying vec2 texCoord; + +vec4 colorFromFloat(float f){ + int argb = int(f*2147483647); + float a = (argb >> 24) & 0xFF; + float r = (argb >> 16) & 0xFF; + float g = (argb >> 8) & 0xFF; + float b = (argb) & 0xFF; + return vec4(r, g, b, a); +} + +float floatFromColor(vec4 color){ + int r = int(color.r*255); + int g = int(color.g*255); + int b = int(color.b*255); + int a = int(color.a*255); + int argb = (a << 24) | (r << 16) | (g << 8) | (b); + return argb/2147483647; +} + +void main(){ + vec4 data0 = texture2D(particleData0, texCoord); + vec4 data1 = texture2D(particleData0, texCoord); + vec4 data2 = texture2D(particleData0, texCoord); + + int age = int(data2.x*32767); + int maxAge = int(data2.y*32767); + int particleType = int(data2.z*32767); + vec4 color = colorFromFloat(data0.w); + + if(particleType == 0){ + float alpha = 1-(age/maxAge); + color.a = alpha; + } + + age = (age+1)*int(age != maxAge)+(-1)*int(age == maxAge); + data2.x = age/32767; + data0.w = floatFromColor(color); + + gl_FragData[0] = data0; + gl_FragData[1] = data1; + gl_FragData[2] = data2; +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/gpu_particle_update.vert b/src/main/resources/assets/avatarmod/shaders/gpu_particle_update.vert new file mode 100644 index 0000000000..cf9ab4fa2e --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/gpu_particle_update.vert @@ -0,0 +1,8 @@ +#version 120 + +varying vec2 texCoord; + +void main(){ + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + texCoord = gl_MultiTexCoord0.xy; +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/lightning/crucible_lightning.frag b/src/main/resources/assets/avatarmod/shaders/lightning/crucible_lightning.frag new file mode 100644 index 0000000000..1b0593c357 --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/lightning/crucible_lightning.frag @@ -0,0 +1,7 @@ +#version 120 + +varying vec4 color; + +void main(){ + gl_FragColor = color; +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/lightning/crucible_lightning.vert b/src/main/resources/assets/avatarmod/shaders/lightning/crucible_lightning.vert new file mode 100644 index 0000000000..14fac81283 --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/lightning/crucible_lightning.vert @@ -0,0 +1,18 @@ +#version 120 + +attribute vec3 pos; +attribute vec2 tex; +attribute vec4 in_color; + +uniform sampler2D noise; +uniform float time; + +varying vec4 color; + +void main(){ + color = in_color; + vec3 noise_a = texture2DLod(noise, tex.ss + vec2(time*0.001, time*-0.02), 0).xyz; + vec3 noise_b = texture2DLod(noise, tex.ss + vec2(time*0.01, time*0.015), 0).xyz; + vec3 offset = (noise_a.xyz*noise_b.zxy-vec3(0.5))*0.1; + gl_Position = gl_ModelViewProjectionMatrix * vec4(pos+offset, 1); +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/lightning/lightning.frag b/src/main/resources/assets/avatarmod/shaders/lightning/lightning.frag new file mode 100644 index 0000000000..eea1bab71d --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/lightning/lightning.frag @@ -0,0 +1,16 @@ +#version 120 + +uniform sampler2D texture; +uniform sampler2D noise; +uniform vec4 duck; +uniform float age; + +varying vec2 pass_tex; +varying vec2 noise_tex; +varying vec4 pass_color; +varying float fade; + +void main(){ + float noise = texture2D(noise, pass_tex * vec2(6, 0.25)).g; + gl_FragColor = duck*vec4(step(fade, noise))*vec4(pass_color.rgb, step(0.5, pass_color.a)); +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/lightning/lightning.vert b/src/main/resources/assets/avatarmod/shaders/lightning/lightning.vert new file mode 100644 index 0000000000..88409ed2aa --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/lightning/lightning.vert @@ -0,0 +1,28 @@ +#version 120 +#extension GL_EXT_gpu_shader4 : enable + +attribute vec3 pos; +attribute vec2 tex; +attribute vec4 color; + +uniform int vertices; +uniform float age; +uniform float fadeoverride; + +varying vec2 pass_tex; +varying vec2 noise_tex; +varying vec4 pass_color; +varying float fade; + +void main(){ + if(fadeoverride != 1){ + fade = fadeoverride; + } else { + float vertPosN = float((vertices - gl_VertexID + age*1.4))/max(float(vertices), 10); + fade = clamp((vertPosN-1)*2, 0, 1); + } + pass_tex = tex; + pass_color = color; + gl_Position = gl_ModelViewProjectionMatrix * vec4(pos, 1); + noise_tex = (gl_Position.xy/gl_Position.ww + 1)*3; +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/lightning/lightning_gib.frag b/src/main/resources/assets/avatarmod/shaders/lightning/lightning_gib.frag new file mode 100644 index 0000000000..ef0d51566d --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/lightning/lightning_gib.frag @@ -0,0 +1,32 @@ +#version 120 + +uniform sampler2D tex; +uniform sampler2D lightmap; +uniform sampler2D noise; +uniform float age; +uniform int bloom; + +varying vec2 texCoord; +varying vec2 lightmapTexCoord; +varying vec3 lightSum; + +void main(){ + vec4 texture = texture2D(tex, texCoord); + float noise_tex = texture2D(noise, texCoord).r; + float noiseA = texture2D(noise, texCoord + vec2(age*0.01, age*0.01)).r*2; + float noiseB = texture2D(noise, texCoord + vec2(age*2*0.01, -age*0.01)).b*2; + float brightA = int(noise_tex < age*0.04 + 0.05)*int(noise_tex > age*0.04 - 0.05); + float dissolve = step(age*0.04, noise_tex); + //Rectangle + float brightB = int(fract(noiseA) < 0.6)*int(fract(noiseA) > 0.4)*int(fract(noiseB) < 0.6)*int(fract(noiseB) > 0.4)*dissolve; + + //Static branching should be ok, right? + if(bloom == 0){ + gl_FragColor = vec4(texture.rgb * lightSum, texture.a) * texture2D(lightmap, lightmapTexCoord) * gl_Color * dissolve + + vec4(1, 1, 1, 0)*brightA + + vec4(1, 1, 1, 0)*brightB; + } else if(bloom == 1){ + vec3 bloomColor = vec3(0.2, 0.8, 1)*1; + gl_FragColor = vec4(bloomColor*brightA + bloomColor*brightB, texture.a * gl_Color.a); + } +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/lightning/lightning_gib.vert b/src/main/resources/assets/avatarmod/shaders/lightning/lightning_gib.vert new file mode 100644 index 0000000000..e87066f275 --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/lightning/lightning_gib.vert @@ -0,0 +1,24 @@ +#version 120 + +varying vec2 texCoord; +varying vec2 lightmapTexCoord; +varying vec3 lightSum; + +void main(){ + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + texCoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy; + lightmapTexCoord = (gl_TextureMatrix[1] * gl_MultiTexCoord1).xy; + gl_FrontColor = gl_Color; + + vec3 normal = (gl_NormalMatrix * gl_Normal).xyz; + vec4 totalLight = vec4(0.0F); + + for (int i = 0; i < gl_MaxLights; i ++){ + + vec4 diffuse = gl_FrontLightProduct[i].diffuse * max(dot(normal,gl_LightSource[i].position.xyz), 0.0f); + diffuse = clamp(diffuse, 0.0F, 1.0F); + + totalLight += diffuse + gl_FrontLightProduct[i].ambient; + } + lightSum = clamp((totalLight + gl_LightModel.ambient).rgb, 0.0F, 1.0F); +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/maxdepth.frag b/src/main/resources/assets/avatarmod/shaders/maxdepth.frag new file mode 100644 index 0000000000..045f125a1d --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/maxdepth.frag @@ -0,0 +1,6 @@ +#version 120 + +void main(){ + gl_FragDepth = 0; + gl_FragColor = vec4(1, 1, 1, 1); +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/maxdepth.vert b/src/main/resources/assets/avatarmod/shaders/maxdepth.vert new file mode 100644 index 0000000000..91b6b1cae9 --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/maxdepth.vert @@ -0,0 +1,5 @@ +#version 120 + +void main(){ + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/testlut.frag b/src/main/resources/assets/avatarmod/shaders/testlut.frag new file mode 100644 index 0000000000..33879f92c5 --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/testlut.frag @@ -0,0 +1,17 @@ +#version 120 + +uniform sampler2D tex0; +uniform sampler2D tempTest; + +varying vec2 texCoord; + +void main(){ + vec4 colorIn = texture2D(tex0, texCoord); + vec3 colorR = colorIn.rgb; + int index = int(colorR.b*63); + float v = colorR.g*0.125+((index/8)*0.125); + float u = colorR.r*0.125+mod(index, 8)*0.125; + + vec4 outColor = texture2D(tempTest, vec2(u, v)); + gl_FragColor = vec4(outColor.rgb, 1.0); +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/shaders/testlut.vert b/src/main/resources/assets/avatarmod/shaders/testlut.vert new file mode 100644 index 0000000000..460e93d254 --- /dev/null +++ b/src/main/resources/assets/avatarmod/shaders/testlut.vert @@ -0,0 +1,8 @@ +#version 120 + +varying vec2 texCoord; + +void main(){ + texCoord = gl_MultiTexCoord0.st; + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; +} \ No newline at end of file diff --git a/src/main/resources/assets/avatarmod/textures/misc/noise_2.png b/src/main/resources/assets/avatarmod/textures/misc/noise_2.png new file mode 100644 index 0000000000..c7ba567933 Binary files /dev/null and b/src/main/resources/assets/avatarmod/textures/misc/noise_2.png differ diff --git a/src/main/resources/assets/avatarmod/textures/models/bfg/additivebeam.png b/src/main/resources/assets/avatarmod/textures/models/bfg/additivebeam.png new file mode 100644 index 0000000000..1a7642883a Binary files /dev/null and b/src/main/resources/assets/avatarmod/textures/models/bfg/additivebeam.png differ diff --git a/src/main/resources/assets/avatarmod/textures/models/bfg/fresnel.png b/src/main/resources/assets/avatarmod/textures/models/bfg/fresnel.png new file mode 100644 index 0000000000..2985f6f6a4 Binary files /dev/null and b/src/main/resources/assets/avatarmod/textures/models/bfg/fresnel.png differ diff --git a/src/main/resources/assets/avatarmod/textures/models/bfg/fresnel_m.png b/src/main/resources/assets/avatarmod/textures/models/bfg/fresnel_m.png new file mode 100644 index 0000000000..cd2ed106e5 Binary files /dev/null and b/src/main/resources/assets/avatarmod/textures/models/bfg/fresnel_m.png differ diff --git a/src/main/resources/assets/avatarmod/textures/models/bfg/fresnel_ms.png b/src/main/resources/assets/avatarmod/textures/models/bfg/fresnel_ms.png new file mode 100644 index 0000000000..a22ce0c5dc Binary files /dev/null and b/src/main/resources/assets/avatarmod/textures/models/bfg/fresnel_ms.png differ diff --git a/src/main/resources/assets/avatarmod/textures/models/bfg/lightning_isolated.png b/src/main/resources/assets/avatarmod/textures/models/bfg/lightning_isolated.png new file mode 100644 index 0000000000..bceef92080 Binary files /dev/null and b/src/main/resources/assets/avatarmod/textures/models/bfg/lightning_isolated.png differ diff --git a/src/main/resources/assets/avatarmod/textures/models/bfg/multi_tester.png b/src/main/resources/assets/avatarmod/textures/models/bfg/multi_tester.png new file mode 100644 index 0000000000..56aada2a93 Binary files /dev/null and b/src/main/resources/assets/avatarmod/textures/models/bfg/multi_tester.png differ diff --git a/src/main/resources/assets/avatarmod/textures/models/ducc_st_engineer.png b/src/main/resources/assets/avatarmod/textures/models/ducc_st_engineer.png new file mode 100644 index 0000000000..2b838516aa Binary files /dev/null and b/src/main/resources/assets/avatarmod/textures/models/ducc_st_engineer.png differ diff --git a/src/main/resources/assets/avatarmod/textures/models/turbofan_blades.png b/src/main/resources/assets/avatarmod/textures/models/turbofan_blades.png new file mode 100644 index 0000000000..298622faac Binary files /dev/null and b/src/main/resources/assets/avatarmod/textures/models/turbofan_blades.png differ