From 7a24c74435096bc343355eedae7d22381a44e2f2 Mon Sep 17 00:00:00 2001 From: Bob Date: Sat, 4 Sep 2021 18:20:09 +0200 Subject: [PATCH] tried and failed shader magic --- src/main/java/api/hbm/item/IGasMask.java | 15 ++ .../blocks/machine/MachineFractionTower.java | 3 +- .../java/com/hbm/crafting/ToolRecipes.java | 2 +- .../java/com/hbm/entity/mob/EntityDuck.java | 40 +++-- .../com/hbm/handler/BulletConfiguration.java | 1 - .../handler/guncfg/Gun357MagnumFactory.java | 4 + src/main/java/com/hbm/items/ModItems.java | 6 +- .../com/hbm/items/armor/ArmorGasMask.java | 162 ++++++++++++++++++ .../java/com/hbm/items/armor/ArmorModel.java | 97 +---------- .../com/hbm/main/ModEventHandlerClient.java | 2 +- .../java/com/hbm/main/ResourceManager.java | 4 + .../java/com/hbm/render/shader/Shader.java | 42 +++++ .../com/hbm/render/shader/ShaderManager.java | 81 +++++++++ .../java/com/hbm/render/shader/Uniform.java | 6 + .../tileentity/RenderTurretChekhov.java | 4 + src/main/java/com/hbm/util/ArmorRegistry.java | 14 +- src/main/java/com/hbm/util/ArmorUtil.java | 5 +- src/main/resources/assets/hbm/lang/de_DE.lang | 3 +- src/main/resources/assets/hbm/lang/en_US.lang | 3 +- .../assets/hbm/shaders/test_shader.frag | 25 +++ .../assets/hbm/shaders/test_shader.vert | 26 +++ .../models/machines/crane_console.png | Bin 0 -> 19388 bytes 22 files changed, 416 insertions(+), 129 deletions(-) create mode 100644 src/main/java/api/hbm/item/IGasMask.java create mode 100644 src/main/java/com/hbm/items/armor/ArmorGasMask.java create mode 100644 src/main/java/com/hbm/render/shader/Shader.java create mode 100644 src/main/java/com/hbm/render/shader/ShaderManager.java create mode 100644 src/main/java/com/hbm/render/shader/Uniform.java create mode 100644 src/main/resources/assets/hbm/shaders/test_shader.frag create mode 100644 src/main/resources/assets/hbm/shaders/test_shader.vert create mode 100644 src/main/resources/assets/hbm/textures/models/machines/crane_console.png diff --git a/src/main/java/api/hbm/item/IGasMask.java b/src/main/java/api/hbm/item/IGasMask.java new file mode 100644 index 000000000..d9be1c421 --- /dev/null +++ b/src/main/java/api/hbm/item/IGasMask.java @@ -0,0 +1,15 @@ +package api.hbm.item; + +import java.util.List; + +import com.hbm.util.ArmorRegistry.HazardClass; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +public interface IGasMask { + + public List getBlacklist(ItemStack stack, EntityPlayer player); + public ItemStack getFilter(ItemStack stack, EntityPlayer player); + public void damageFilter(ItemStack stack, EntityPlayer player); +} diff --git a/src/main/java/com/hbm/blocks/machine/MachineFractionTower.java b/src/main/java/com/hbm/blocks/machine/MachineFractionTower.java index ba7c68a28..9a1d73749 100644 --- a/src/main/java/com/hbm/blocks/machine/MachineFractionTower.java +++ b/src/main/java/com/hbm/blocks/machine/MachineFractionTower.java @@ -10,6 +10,7 @@ import net.minecraft.block.material.Material; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ChatComponentText; +import net.minecraft.util.ChatComponentTranslation; import net.minecraft.util.EnumChatFormatting; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; @@ -64,7 +65,7 @@ public class MachineFractionTower extends BlockDummyable { player.addChatComponentMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "=== FRACTIONING TOWER Y:" + pos[1] + " ===")); for(int i = 0; i < frac.tanks.length; i++) - player.addChatComponentMessage(new ChatComponentText(frac.tanks[i].getTankType() + ": " + frac.tanks[i].getFill() + "/" + frac.tanks[i].getMaxFill() + "mB")); + player.addChatComponentMessage(new ChatComponentTranslation("hbmfluid." + frac.tanks[i].getTankType().getName().toLowerCase()).appendSibling(new ChatComponentText(": " + frac.tanks[i].getFill() + "/" + frac.tanks[i].getMaxFill() + "mB"))); } else { if(world.getTileEntity(pos[0], pos[1] - 3, pos[2]) instanceof TileEntityMachineFractionTower) { diff --git a/src/main/java/com/hbm/crafting/ToolRecipes.java b/src/main/java/com/hbm/crafting/ToolRecipes.java index 6b51a76a5..4a628acee 100644 --- a/src/main/java/com/hbm/crafting/ToolRecipes.java +++ b/src/main/java/com/hbm/crafting/ToolRecipes.java @@ -49,7 +49,7 @@ public class ToolRecipes { addHoe( ModItems.ingot_combine_steel, ModItems.cmb_hoe); addSword( "ingotDesh", ModItems.desh_sword); addPickaxe( "ingotDesh", ModItems.desh_pickaxe); - addAxe( "ingotDesh", ModItems.desh_pickaxe); + addAxe( "ingotDesh", ModItems.desh_axe); addShovel( "ingotDesh", ModItems.desh_shovel); addHoe( "ingotDesh", ModItems.desh_hoe); diff --git a/src/main/java/com/hbm/entity/mob/EntityDuck.java b/src/main/java/com/hbm/entity/mob/EntityDuck.java index c263eeb93..018409d8d 100644 --- a/src/main/java/com/hbm/entity/mob/EntityDuck.java +++ b/src/main/java/com/hbm/entity/mob/EntityDuck.java @@ -2,6 +2,8 @@ package com.hbm.entity.mob; import net.minecraft.entity.EntityAgeable; import net.minecraft.entity.passive.EntityChicken; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.DamageSource; import net.minecraft.world.World; public class EntityDuck extends EntityChicken { @@ -9,21 +11,29 @@ public class EntityDuck extends EntityChicken { public EntityDuck(World world) { super(world); } + + protected String getLivingSound() { + return "hbm:entity.ducc"; + } + + protected String getHurtSound() { + return "hbm:entity.ducc"; + } + + protected String getDeathSound() { + return "hbm:entity.ducc"; + } + + public EntityDuck createChild(EntityAgeable entity) { + return new EntityDuck(this.worldObj); + } - protected String getLivingSound() { - return "hbm:entity.ducc"; - } + protected void damageEntity(DamageSource p_70665_1_, float p_70665_2_) { + super.damageEntity(p_70665_1_, p_70665_2_); + } - protected String getHurtSound() { - return "hbm:entity.ducc"; - } - - protected String getDeathSound() { - return "hbm:entity.ducc"; - } - - public EntityDuck createChild(EntityAgeable entity) - { - return new EntityDuck(this.worldObj); - } + public void onDeath(DamageSource p_70645_1_) { + if(!worldObj.isRemote) MinecraftServer.getServer().getConfigurationManager().sendChatMsg(this.func_110142_aN().func_151521_b()); + super.onDeath(p_70645_1_); + } } diff --git a/src/main/java/com/hbm/handler/BulletConfiguration.java b/src/main/java/com/hbm/handler/BulletConfiguration.java index 61fa9b04a..4a4d7a919 100644 --- a/src/main/java/com/hbm/handler/BulletConfiguration.java +++ b/src/main/java/com/hbm/handler/BulletConfiguration.java @@ -12,7 +12,6 @@ import com.hbm.interfaces.IBulletUpdateBehavior; import com.hbm.interfaces.Untested; import com.hbm.lib.ModDamageSource; -import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.item.Item; import net.minecraft.potion.PotionEffect; diff --git a/src/main/java/com/hbm/handler/guncfg/Gun357MagnumFactory.java b/src/main/java/com/hbm/handler/guncfg/Gun357MagnumFactory.java index 16f89d24c..a8415ca7e 100644 --- a/src/main/java/com/hbm/handler/guncfg/Gun357MagnumFactory.java +++ b/src/main/java/com/hbm/handler/guncfg/Gun357MagnumFactory.java @@ -6,6 +6,7 @@ import com.hbm.handler.BulletConfigSyncingUtil; import com.hbm.handler.BulletConfiguration; import com.hbm.handler.GunConfiguration; import com.hbm.items.ModItems; +import com.hbm.lib.ModDamageSource; import com.hbm.potion.HbmPotion; import com.hbm.render.util.RenderScreenOverlay.Crosshair; @@ -292,10 +293,13 @@ public class Gun357MagnumFactory { bullet.bulletsMax = 6; bullet.dmgMin = 50; bullet.dmgMax = 150; + bullet.doesRicochet = false; bullet.destroysBlocks = true; bullet.style = bullet.STYLE_BOLT; bullet.trail = bullet.BOLT_NIGHTMARE; + bullet.damageType = ModDamageSource.s_laser; + return bullet; } diff --git a/src/main/java/com/hbm/items/ModItems.java b/src/main/java/com/hbm/items/ModItems.java index eac9c385c..c719ae7e1 100644 --- a/src/main/java/com/hbm/items/ModItems.java +++ b/src/main/java/com/hbm/items/ModItems.java @@ -4553,9 +4553,9 @@ public class ModItems { goggles = new ArmorModel(ArmorMaterial.IRON, 7, 0).setUnlocalizedName("goggles").setMaxStackSize(1).setTextureName(RefStrings.MODID + ":goggles"); ashglasses = new ArmorAshGlasses(ArmorMaterial.IRON, 7, 0).setUnlocalizedName("ashglasses").setMaxStackSize(1).setTextureName(RefStrings.MODID + ":ashglasses"); - gas_mask = new ArmorModel(ArmorMaterial.IRON, 7, 0).setUnlocalizedName("gas_mask").setMaxStackSize(1).setTextureName(RefStrings.MODID + ":gas_mask"); - gas_mask_m65 = new ArmorModel(ArmorMaterial.IRON, 7, 0).setUnlocalizedName("gas_mask_m65").setMaxStackSize(1).setTextureName(RefStrings.MODID + ":gas_mask_m65"); - gas_mask_mono = new ArmorModel(ArmorMaterial.IRON, 7, 0).setUnlocalizedName("gas_mask_mono").setMaxStackSize(1).setTextureName(RefStrings.MODID + ":gas_mask_mono"); + gas_mask = new ArmorGasMask().setUnlocalizedName("gas_mask").setMaxStackSize(1).setTextureName(RefStrings.MODID + ":gas_mask"); + gas_mask_m65 = new ArmorGasMask().setUnlocalizedName("gas_mask_m65").setMaxStackSize(1).setTextureName(RefStrings.MODID + ":gas_mask_m65"); + gas_mask_mono = new ArmorGasMask().setUnlocalizedName("gas_mask_mono").setMaxStackSize(1).setTextureName(RefStrings.MODID + ":gas_mask_mono"); hat = new ArmorHat(ArmorMaterial.IRON, 7, 0).setUnlocalizedName("nossy_hat").setMaxStackSize(1).setTextureName(RefStrings.MODID + ":hat"); beta = new ItemDrop().setUnlocalizedName("beta").setMaxStackSize(1).setTextureName(RefStrings.MODID + ":beta"); //oxy_mask = new ArmorModel(ArmorMaterial.IRON, 7, 0).setUnlocalizedName("oxy_mask").setMaxStackSize(1).setTextureName(RefStrings.MODID + ":oxy_mask"); diff --git a/src/main/java/com/hbm/items/armor/ArmorGasMask.java b/src/main/java/com/hbm/items/armor/ArmorGasMask.java new file mode 100644 index 000000000..f5c0cd417 --- /dev/null +++ b/src/main/java/com/hbm/items/armor/ArmorGasMask.java @@ -0,0 +1,162 @@ +package com.hbm.items.armor; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.lwjgl.opengl.GL11; + +import com.hbm.items.ModItems; +import com.hbm.lib.RefStrings; +import com.hbm.render.model.ModelGasMask; +import com.hbm.render.model.ModelM65; +import com.hbm.util.ArmorRegistry.HazardClass; + +import api.hbm.item.IGasMask; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.model.ModelBiped; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemArmor; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; + +public class ArmorGasMask extends ItemArmor implements IGasMask { + + @SideOnly(Side.CLIENT) + private ModelGasMask modelGas; + @SideOnly(Side.CLIENT) + private ModelM65 modelM65; + + private ResourceLocation[] googleBlur = new ResourceLocation[] { + new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_goggles_0.png"), + new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_goggles_1.png"), + new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_goggles_2.png"), + new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_goggles_3.png"), + new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_goggles_4.png"), + new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_goggles_5.png") + }; + + private ResourceLocation[] maskBlur = new ResourceLocation[] { + new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_gasmask_0.png"), + new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_gasmask_1.png"), + new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_gasmask_2.png"), + new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_gasmask_3.png"), + new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_gasmask_4.png"), + new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_gasmask_5.png") + }; + + public ArmorGasMask() { + super(ArmorMaterial.IRON, 7, 0); + } + + @Override + @SideOnly(Side.CLIENT) + public ModelBiped getArmorModel(EntityLivingBase entityLiving, ItemStack itemStack, int armorSlot) { + + if(this == ModItems.gas_mask) { + if(armorSlot == 0) { + if(this.modelGas == null) { + this.modelGas = new ModelGasMask(); + } + return this.modelGas; + } + } + + if(this == ModItems.gas_mask_m65 || this == ModItems.gas_mask_mono) { + if(armorSlot == 0) { + if(this.modelM65 == null) { + this.modelM65 = new ModelM65(); + } + return this.modelM65; + } + } + + return null; + } + + @Override + public String getArmorTexture(ItemStack stack, Entity entity, int slot, String type) { + + if(stack.getItem() == ModItems.gas_mask) { + return "hbm:textures/models/GasMask.png"; + } + if(stack.getItem() == ModItems.gas_mask_m65) { + return "hbm:textures/models/ModelM65.png"; + } + if(stack.getItem() == ModItems.gas_mask_mono) { + return "hbm:textures/models/ModelM65Mono.png"; + } + + return null; + } + + @SideOnly(Side.CLIENT) + public void renderHelmetOverlay(ItemStack stack, EntityPlayer player, ScaledResolution resolution, float partialTicks, boolean hasScreen, int mouseX, int mouseY) { + + ResourceLocation tex = null; + + if(this == ModItems.goggles || this == ModItems.gas_mask_m65) { + int index = (int) ((double) stack.getItemDamage() / (double) stack.getMaxDamage() * 6D); + tex = this.googleBlur[index]; + } + + if(this == ModItems.gas_mask) { + int index = (int) ((double) stack.getItemDamage() / (double) stack.getMaxDamage() * 6D); + tex = this.maskBlur[index]; + } + + if(tex == null) + return; + + Minecraft.getMinecraft().getTextureManager().bindTexture(tex); + + GL11.glDisable(GL11.GL_DEPTH_TEST); + GL11.glDepthMask(false); + OpenGlHelper.glBlendFunc(770, 771, 1, 0); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + GL11.glDisable(GL11.GL_ALPHA_TEST); + + Tessellator tessellator = Tessellator.instance; + tessellator.startDrawingQuads(); + tessellator.addVertexWithUV(0.0D, (double) resolution.getScaledHeight(), -90.0D, 0.0D, 1.0D); + tessellator.addVertexWithUV((double) resolution.getScaledWidth(), (double) resolution.getScaledHeight(), -90.0D, 1.0D, 1.0D); + tessellator.addVertexWithUV((double) resolution.getScaledWidth(), 0.0D, -90.0D, 1.0D, 0.0D); + tessellator.addVertexWithUV(0.0D, 0.0D, -90.0D, 0.0D, 0.0D); + tessellator.draw(); + GL11.glDepthMask(true); + GL11.glEnable(GL11.GL_DEPTH_TEST); + GL11.glEnable(GL11.GL_ALPHA_TEST); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + } + + @Override + public List getBlacklist(ItemStack stack, EntityPlayer player) { + + if(this == ModItems.gas_mask_mono) { + return Arrays.asList(new HazardClass[] {HazardClass.GAS_CHLORINE, HazardClass.BACTERIA}); + } + + return new ArrayList(); + } + + @Override + public ItemStack getFilter(ItemStack stack, EntityPlayer player) { + + if(stack == null || !(stack.getItem() instanceof IGasMask) || !stack.hasTagCompound()) + return null; + + return null; + } + + @Override + public void damageFilter(ItemStack stack, EntityPlayer player) { + + } +} diff --git a/src/main/java/com/hbm/items/armor/ArmorModel.java b/src/main/java/com/hbm/items/armor/ArmorModel.java index 0531aa3d6..b5ba32358 100644 --- a/src/main/java/com/hbm/items/armor/ArmorModel.java +++ b/src/main/java/com/hbm/items/armor/ArmorModel.java @@ -8,7 +8,6 @@ import com.hbm.interfaces.Spaghetti; import com.hbm.items.ModItems; import com.hbm.lib.RefStrings; import com.hbm.render.model.ModelCloak; -import com.hbm.render.model.ModelGasMask; import com.hbm.render.model.ModelGoggles; import com.hbm.render.model.ModelHat; import com.hbm.render.model.ModelM65; @@ -35,8 +34,6 @@ public class ArmorModel extends ItemArmor { @SideOnly(Side.CLIENT) private ModelGoggles modelGoggles; @SideOnly(Side.CLIENT) - private ModelGasMask modelGas; - @SideOnly(Side.CLIENT) private ModelCloak modelCloak; @SideOnly(Side.CLIENT) private ModelOxygenMask modelOxy; @@ -51,59 +48,11 @@ public class ArmorModel extends ItemArmor { private ResourceLocation goggleBlur3 = new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_goggles_3.png"); private ResourceLocation goggleBlur4 = new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_goggles_4.png"); private ResourceLocation goggleBlur5 = new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_goggles_5.png"); - private ResourceLocation gasmaskBlur0 = new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_gasmask_0.png"); - private ResourceLocation gasmaskBlur1 = new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_gasmask_1.png"); - private ResourceLocation gasmaskBlur2 = new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_gasmask_2.png"); - private ResourceLocation gasmaskBlur3 = new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_gasmask_3.png"); - private ResourceLocation gasmaskBlur4 = new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_gasmask_4.png"); - private ResourceLocation gasmaskBlur5 = new ResourceLocation(RefStrings.MODID + ":textures/misc/overlay_gasmask_5.png"); public ArmorModel(ArmorMaterial armorMaterial, int renderIndex, int armorType) { super(armorMaterial, renderIndex, armorType); } - //there was no reason to override this - /*@Override - public boolean isValidArmor(ItemStack stack, int armorType, Entity entity) { - if (this == ModItems.goggles) { - return armorType == 0; - } - if (this == ModItems.gas_mask) { - return armorType == 0; - } - if (this == ModItems.gas_mask_m65) { - return armorType == 0; - } - if (this == ModItems.gas_mask_mono) { - return armorType == 0; - } - if (this == ModItems.hat) { - return armorType == 0; - } - if (this == ModItems.hazmat_helmet_red) { - return armorType == 0; - } - if (this == ModItems.hazmat_helmet_grey) { - return armorType == 0; - } - if (this == ModItems.oxy_mask) { - return armorType == 0; - } - if (this == ModItems.cape_test) { - return armorType == 1; - } - if (this == ModItems.cape_radiation) { - return armorType == 1; - } - if (this == ModItems.cape_gasmask) { - return armorType == 1; - } - if (this == ModItems.cape_schrabidium) { - return armorType == 1; - } - return armorType == 0; - }*/ - @Override @SideOnly(Side.CLIENT) public ModelBiped getArmorModel(EntityLivingBase entityLiving, ItemStack itemStack, int armorSlot) { @@ -115,15 +64,7 @@ public class ArmorModel extends ItemArmor { return this.modelGoggles; } } - if (this == ModItems.gas_mask) { - if (armorSlot == 0) { - if (this.modelGas == null) { - this.modelGas = new ModelGasMask(); - } - return this.modelGas; - } - } - if (this == ModItems.gas_mask_m65 || this == ModItems.hazmat_helmet_red || this == ModItems.hazmat_helmet_grey || this == ModItems.gas_mask_mono) { + if (this == ModItems.hazmat_helmet_red || this == ModItems.hazmat_helmet_grey) { if (armorSlot == 0) { if (this.modelM65 == null) { this.modelM65 = new ModelM65(); @@ -163,15 +104,6 @@ public class ArmorModel extends ItemArmor { if (stack.getItem() == ModItems.goggles) { return "hbm:textures/models/Goggles.png"; } - if (stack.getItem() == ModItems.gas_mask) { - return "hbm:textures/models/GasMask.png"; - } - if (stack.getItem() == ModItems.gas_mask_m65) { - return "hbm:textures/models/ModelM65.png"; - } - if (stack.getItem() == ModItems.gas_mask_mono) { - return "hbm:textures/models/ModelM65Mono.png"; - } if (stack.getItem() == ModItems.hazmat_helmet_red) { return "hbm:textures/models/ModelHazRed.png"; } @@ -209,7 +141,7 @@ public class ArmorModel extends ItemArmor { GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); GL11.glDisable(GL11.GL_ALPHA_TEST); - if(this == ModItems.goggles || this == ModItems.gas_mask_m65 || this == ModItems.hazmat_helmet_red || this == ModItems.hazmat_helmet_grey) { + if(this == ModItems.hazmat_helmet_red || this == ModItems.hazmat_helmet_grey) { switch((int)((double)stack.getItemDamage() / (double)stack.getMaxDamage() * 6D)) { case 0: Minecraft.getMinecraft().getTextureManager().bindTexture(goggleBlur0); break; @@ -227,24 +159,6 @@ public class ArmorModel extends ItemArmor { Minecraft.getMinecraft().getTextureManager().bindTexture(goggleBlur5); break; } } - if(this == ModItems.gas_mask) { - switch((int)((double)stack.getItemDamage() / (double)stack.getMaxDamage() * 6D)) { - case 0: - Minecraft.getMinecraft().getTextureManager().bindTexture(gasmaskBlur0); break; - case 1: - Minecraft.getMinecraft().getTextureManager().bindTexture(gasmaskBlur1); break; - case 2: - Minecraft.getMinecraft().getTextureManager().bindTexture(gasmaskBlur2); break; - case 3: - Minecraft.getMinecraft().getTextureManager().bindTexture(gasmaskBlur3); break; - case 4: - Minecraft.getMinecraft().getTextureManager().bindTexture(gasmaskBlur4); break; - case 5: - Minecraft.getMinecraft().getTextureManager().bindTexture(gasmaskBlur5); break; - default: - Minecraft.getMinecraft().getTextureManager().bindTexture(gasmaskBlur5); break; - } - } Tessellator tessellator = Tessellator.instance; tessellator.startDrawingQuads(); @@ -271,12 +185,5 @@ public class ArmorModel extends ItemArmor { if(this == ModItems.cape_schrabidium) { list.add("Avalible for everyone"); } - - if(this == ModItems.gas_mask || this == ModItems.gas_mask_m65) { - list.add("Protects against most harmful gasses"); - } - if(this == ModItems.gas_mask_mono) { - list.add("Protects against carbon monoxide"); - } } } diff --git a/src/main/java/com/hbm/main/ModEventHandlerClient.java b/src/main/java/com/hbm/main/ModEventHandlerClient.java index 69e9dcc43..544946cdf 100644 --- a/src/main/java/com/hbm/main/ModEventHandlerClient.java +++ b/src/main/java/com/hbm/main/ModEventHandlerClient.java @@ -466,7 +466,7 @@ public class ModEventHandlerClient { List list = event.toolTip; /// HAZMAT INFO /// - List hazInfo = ArmorRegistry.armor.get(stack.getItem()); + List hazInfo = ArmorRegistry.hazardClasses.get(stack.getItem()); if(hazInfo != null) { list.add(EnumChatFormatting.GOLD + I18nUtil.resolveKey("hazard.prot")); diff --git a/src/main/java/com/hbm/main/ResourceManager.java b/src/main/java/com/hbm/main/ResourceManager.java index 2131dfdf2..9557b1d30 100644 --- a/src/main/java/com/hbm/main/ResourceManager.java +++ b/src/main/java/com/hbm/main/ResourceManager.java @@ -2,12 +2,16 @@ package com.hbm.main; import com.hbm.lib.RefStrings; import com.hbm.render.loader.HFRWavefrontObject; +import com.hbm.render.shader.Shader; +import com.hbm.render.shader.ShaderManager; import net.minecraft.util.ResourceLocation; import net.minecraftforge.client.model.AdvancedModelLoader; import net.minecraftforge.client.model.IModelCustom; public class ResourceManager { + + public static final Shader test_shader = ShaderManager.loadShader(new ResourceLocation(RefStrings.MODID, "shaders/test_shader")); //God public static final IModelCustom error = AdvancedModelLoader.loadModel(new ResourceLocation(RefStrings.MODID, "models/error.obj")); diff --git a/src/main/java/com/hbm/render/shader/Shader.java b/src/main/java/com/hbm/render/shader/Shader.java new file mode 100644 index 000000000..f7bf4f321 --- /dev/null +++ b/src/main/java/com/hbm/render/shader/Shader.java @@ -0,0 +1,42 @@ +package com.hbm.render.shader; + +import java.util.ArrayList; +import java.util.List; + +import org.lwjgl.opengl.GL20; + +public 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(!ShaderManager.enableShaders) + return; + + GL20.glUseProgram(shader); + for(Uniform u : uniforms) { + u.apply(shader); + } + } + + public void release() { + GL20.glUseProgram(0); + } + + public int getShaderId() { + return shader; + } +} diff --git a/src/main/java/com/hbm/render/shader/ShaderManager.java b/src/main/java/com/hbm/render/shader/ShaderManager.java new file mode 100644 index 000000000..a00e3d6c1 --- /dev/null +++ b/src/main/java/com/hbm/render/shader/ShaderManager.java @@ -0,0 +1,81 @@ +package com.hbm.render.shader; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; + +import org.apache.commons.io.IOUtils; +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL20; + +import com.hbm.main.MainRegistry; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.ResourceLocation; + +public class ShaderManager { + + public static boolean enableShaders = true; + + public static final Uniform LIGHTMAP = shader -> { + GL20.glUniform1i(GL20.glGetUniformLocation(shader, "lightmap"), 1); + }; + + public static Shader loadShader(ResourceLocation file) { + + if(!enableShaders) + return new Shader(0); + + int vertexShader = 0; + int fragmentShader = 0; + + try { + int program = GL20.glCreateProgram(); + + vertexShader = GL20.glCreateShader(GL20.GL_VERTEX_SHADER); + GL20.glShaderSource(vertexShader, readFileToBuf(new ResourceLocation(file.getResourceDomain(), file.getResourcePath() + ".vert"))); + GL20.glCompileShader(vertexShader); + if(GL20.glGetShaderi(vertexShader, GL20.GL_COMPILE_STATUS) == GL11.GL_FALSE) { + MainRegistry.logger.error(GL20.glGetShaderInfoLog(vertexShader, GL20.GL_INFO_LOG_LENGTH)); + throw new RuntimeException("Error creating vertex shader: " + file); + } + + fragmentShader = GL20.glCreateShader(GL20.GL_FRAGMENT_SHADER); + GL20.glShaderSource(fragmentShader, readFileToBuf(new ResourceLocation(file.getResourceDomain(), file.getResourcePath() + ".frag"))); + GL20.glCompileShader(fragmentShader); + if(GL20.glGetShaderi(fragmentShader, GL20.GL_COMPILE_STATUS) == GL11.GL_FALSE) { + MainRegistry.logger.error(GL20.glGetShaderInfoLog(fragmentShader, GL20.GL_INFO_LOG_LENGTH)); + throw new RuntimeException("Error creating fragment shader: " + file); + } + + GL20.glAttachShader(program, vertexShader); + GL20.glAttachShader(program, fragmentShader); + GL20.glLinkProgram(program); + if(GL20.glGetProgrami(program, GL20.GL_LINK_STATUS) == GL11.GL_FALSE) { + MainRegistry.logger.error(GL20.glGetProgramInfoLog(program, GL20.GL_INFO_LOG_LENGTH)); + throw new RuntimeException("Error creating fragment shader: " + file); + } + + GL20.glDeleteShader(vertexShader); + GL20.glDeleteShader(fragmentShader); + + return new Shader(program); + } catch(Exception x) { + GL20.glDeleteShader(vertexShader); + GL20.glDeleteShader(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; + } +} diff --git a/src/main/java/com/hbm/render/shader/Uniform.java b/src/main/java/com/hbm/render/shader/Uniform.java new file mode 100644 index 000000000..0a32c8893 --- /dev/null +++ b/src/main/java/com/hbm/render/shader/Uniform.java @@ -0,0 +1,6 @@ +package com.hbm.render.shader; + +public interface Uniform { + + public void apply(int shader); +} diff --git a/src/main/java/com/hbm/render/tileentity/RenderTurretChekhov.java b/src/main/java/com/hbm/render/tileentity/RenderTurretChekhov.java index 46ba75490..f58e73b40 100644 --- a/src/main/java/com/hbm/render/tileentity/RenderTurretChekhov.java +++ b/src/main/java/com/hbm/render/tileentity/RenderTurretChekhov.java @@ -16,6 +16,8 @@ public class RenderTurretChekhov extends RenderTurretBase { TileEntityTurretChekhov turret = (TileEntityTurretChekhov)te; Vec3 pos = turret.getHorizontalOffset(); + + ResourceManager.test_shader.use(); GL11.glPushMatrix(); GL11.glTranslated(x + pos.xCoord, y, z + pos.zCoord); @@ -50,5 +52,7 @@ public class RenderTurretChekhov extends RenderTurretBase { GL11.glShadeModel(GL11.GL_FLAT); GL11.glPopMatrix(); + + ResourceManager.test_shader.release(); } } diff --git a/src/main/java/com/hbm/util/ArmorRegistry.java b/src/main/java/com/hbm/util/ArmorRegistry.java index b1ecefd9f..b3c486fc5 100644 --- a/src/main/java/com/hbm/util/ArmorRegistry.java +++ b/src/main/java/com/hbm/util/ArmorRegistry.java @@ -8,11 +8,11 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; public class ArmorRegistry { + + public static HashMap> hazardClasses = new HashMap(); - public static HashMap> armor = new HashMap(); - - public static void registerArmor(Item item, HazardClass... hazards) { - armor.put(item, Arrays.asList(hazards)); + public static void registerHazard(Item item, HazardClass... hazards) { + hazardClasses.put(item, Arrays.asList(hazards)); } public static boolean hasProtection(EntityPlayer player, int slot, HazardClass clazz) { @@ -20,7 +20,7 @@ public class ArmorRegistry { if(ArmorUtil.checkArmorNull(player, slot)) return false; - List list = armor.get(player.inventory.armorInventory[slot].getItem()); + List list = hazardClasses.get(player.inventory.armorInventory[slot].getItem()); if(list == null) return false; @@ -43,12 +43,12 @@ public class ArmorRegistry { } } - public static enum ArmorClass { + /*public static enum ArmorClass { MASK_FILTERED, MASK_OXY, GOGGLES, HAZMAT_HEAT, HAZMAT_RADIATION, HAZMAT_BIO; - } + }*/ } diff --git a/src/main/java/com/hbm/util/ArmorUtil.java b/src/main/java/com/hbm/util/ArmorUtil.java index 7af6793a0..903aaf804 100644 --- a/src/main/java/com/hbm/util/ArmorUtil.java +++ b/src/main/java/com/hbm/util/ArmorUtil.java @@ -17,9 +17,8 @@ import net.minecraft.network.NetHandlerPlayServer; public class ArmorUtil { public static void register() { - ArmorRegistry.registerArmor(ModItems.gas_mask, HazardClass.PARTICLE_COARSE, HazardClass.PARTICLE_FINE, HazardClass.GAS_CHLORINE); - ArmorRegistry.registerArmor(ModItems.gas_mask_m65, HazardClass.PARTICLE_COARSE, HazardClass.PARTICLE_FINE, HazardClass.GAS_CHLORINE); - ArmorRegistry.registerArmor(ModItems.gas_mask_mono, HazardClass.PARTICLE_COARSE, HazardClass.GAS_MONOXIDE); + ArmorRegistry.registerHazard(ModItems.gas_mask_filter_mono, HazardClass.PARTICLE_COARSE, HazardClass.GAS_MONOXIDE); + ArmorRegistry.registerHazard(ModItems.gas_mask_filter, HazardClass.PARTICLE_COARSE, HazardClass.PARTICLE_FINE, HazardClass.GAS_CHLORINE, HazardClass.BACTERIA); } public static boolean checkArmor(EntityPlayer player, Item... armor) { diff --git a/src/main/resources/assets/hbm/lang/de_DE.lang b/src/main/resources/assets/hbm/lang/de_DE.lang index 137414d45..937201eb5 100644 --- a/src/main/resources/assets/hbm/lang/de_DE.lang +++ b/src/main/resources/assets/hbm/lang/de_DE.lang @@ -312,6 +312,7 @@ death.attack.euthanizedSelf2=%1$s gewinnt den Darwin Award. death.attack.euthanizedSelf=%1$s hat sich selbst eingeschläfert, was für ein Vollpfosten. death.attack.exhaust=%1$s wurde von einer startenden Rakete verbrutzelt. death.attack.flamethrower=%1$s wurde von %2$s gegrillt. +death.attack.flamethrower.item=%1$s wurde von %2$s mit %3$s gegrillt. death.attack.ice=%1$s wurde von %2$s in ein Eis am Stiel verwandelt. death.attack.laser=%1$s wurde von %2$s zerbröselt. death.attack.laser.item=%1$s wurde von %2$s mit %3$s zerbröselt. @@ -326,7 +327,7 @@ death.attack.pc=%1$s wurde zu einer Pfütze in der pinken Wolke. death.attack.plasma=%1$s wurde von %2$s eingeäschert. death.attack.radiation=%1$s starb an Strahlenvergiftung. death.attack.revolverBullet=%1$s wurde von %2$s in den Kopf geschossen. -death.attack.revolverBullet.item=%1$s wurde von %2$s mit %3$s in den Kopf geschossen. +death.attack.revolverBullet.item.item=%1$s wurde von %2$s mit %3$s in den Kopf geschossen. death.attack.rubble=%1$s wurde von Schutt zerquetscht. death.attack.shrapnel=%1$s wurde von einem Schrapnell zerfetzt. death.attack.spikes=%1$s wurde aufgespießt. diff --git a/src/main/resources/assets/hbm/lang/en_US.lang b/src/main/resources/assets/hbm/lang/en_US.lang index df6f71956..56056927d 100644 --- a/src/main/resources/assets/hbm/lang/en_US.lang +++ b/src/main/resources/assets/hbm/lang/en_US.lang @@ -380,6 +380,7 @@ death.attack.euthanizedSelf2=%1$s wins the Darwin Award. death.attack.euthanizedSelf=%1$s euthanized himself, what a dork. death.attack.exhaust=%1$s was turned into shish kebab by a starting rocket. death.attack.flamethrower=%1$s was cremated by %2$s. +death.attack.flamethrower.item=%1$s was cremated by %2$s using %3$s. death.attack.ice=%1$s was turned into a popsicle by %2$s. death.attack.laser=%1$s was turned into ash by %2$s. death.attack.laser.item=%1$s was turned into ash by %2$s using %3$s. @@ -394,7 +395,7 @@ death.attack.pc=%1$s was reduced to a puddle in the pink cloud. death.attack.plasma=%1$s was immolated by %2$s. death.attack.radiation=%1$s died from radiation poisoning. death.attack.revolverBullet=%1$s was shot in the head by %2$s. -death.attack.revolverBullet=%1$s was shot in the head by %2$s using %3$s. +death.attack.revolverBullet.item=%1$s was shot in the head by %2$s using %3$s. death.attack.rubble=%1$s was squashed by debris. death.attack.shrapnel=%1$s was ragged by a shrapnel. death.attack.spikes=%1$s got impaled. diff --git a/src/main/resources/assets/hbm/shaders/test_shader.frag b/src/main/resources/assets/hbm/shaders/test_shader.frag new file mode 100644 index 000000000..2e6f3ab0b --- /dev/null +++ b/src/main/resources/assets/hbm/shaders/test_shader.frag @@ -0,0 +1,25 @@ +#version 330 compatibility + +in vec2 texCoord; +in vec2 lightCoord; +in vec4 color; +in vec3 lighting; +out vec4 FragColor; + +uniform sampler2D texture; +uniform sampler2D lightmap; + +void main(){ + vec4 center = texture2D(DiffuseSampler, texCoord); + vec4 up = texture2D(DiffuseSampler, texCoord + vec2( 0.0, -oneTexel.y)); + vec4 down = texture2D(DiffuseSampler, texCoord + vec2( oneTexel.x, 0.0)); + vec4 left = texture2D(DiffuseSampler, texCoord + vec2(-oneTexel.x, 0.0)); + vec4 right = texture2D(DiffuseSampler, texCoord + vec2( 0.0, oneTexel.y)); + vec4 uDiff = center - up; + vec4 dDiff = center - down; + vec4 lDiff = center - left; + vec4 rDiff = center - right; + vec4 sum = uDiff + dDiff + lDiff + rDiff; + vec3 clamped = clamp(center.rgb - sum.rgb, 0.0, 1.0); + gl_FragColor = vec4(clamped, center.a); +} diff --git a/src/main/resources/assets/hbm/shaders/test_shader.vert b/src/main/resources/assets/hbm/shaders/test_shader.vert new file mode 100644 index 000000000..29c5d6a14 --- /dev/null +++ b/src/main/resources/assets/hbm/shaders/test_shader.vert @@ -0,0 +1,26 @@ +#version 330 compatibility + +out vec2 texCoord; +out vec2 lightCoord; +out vec4 color; +out vec3 lighting; + +void main(){ + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + texCoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).st; + lightCoord = (gl_TextureMatrix[1] * gl_MultiTexCoord1).st; + color = gl_Color; + + vec3 totalLighting = vec3(gl_LightModel.ambient) * vec3(gl_FrontMaterial.emission); + vec3 normal = (gl_NormalMatrix * gl_Normal).xyz; + vec4 difftot = vec4(0.0F); + + for (int i = 0; i < gl_MaxLights; i ++){ + + vec4 diff = gl_FrontLightProduct[i].diffuse * max(dot(normal,gl_LightSource[i].position.xyz), 0.0f); + diff = clamp(diff, 0.0F, 1.0F); + + difftot += diff; + } + lighting = clamp((difftot + gl_LightModel.ambient).rgb, 0.0F, 1.0F); +} diff --git a/src/main/resources/assets/hbm/textures/models/machines/crane_console.png b/src/main/resources/assets/hbm/textures/models/machines/crane_console.png new file mode 100644 index 0000000000000000000000000000000000000000..d0dcad029ee23fd0d0b4d6d717a45e35c261562d GIT binary patch literal 19388 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 KMNUMnLSTXe80&Tb literal 0 HcmV?d00001