Add Proximity Based Alpha Handling for Energy Projectiles

This commit is contained in:
Kam committed 2026-03-09 00:50:42 -04:00
1 parent bc448c2af2
commit 8e29350f12
7 files changed
+134 -20

No files matched your search

@@ -5,11 +5,14 @@ import cpw.mods.fml.relauncher.SideOnly;
import kamkeel.npcs.client.renderer.lightning.AttachedLightningRenderer;
import kamkeel.npcs.entity.EntityEnergyAbility;
import kamkeel.npcs.entity.EntityEnergyProjectile;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ResourceLocation;
import noppes.npcs.config.ConfigClient;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
@@ -338,6 +341,68 @@ public abstract class RenderEnergy extends Render {
state.render();
}
// ==================== PROXIMITY ALPHA ====================
/**
* Calculate a proximity-based alpha multiplier for owner's energy projectiles.
* Returns a factor between ProximityAlphaMin and 1.0 based on:
* - Distance from camera (close = faded, far = full)
* - Entity age (young = faded, old = full; ignored while charging)
* <p>
* Only applies to the owning player's client. Non-owners always get 1.0.
*
* @param entity the energy projectile entity
* @param x camera-relative X (from doRender)
* @param y camera-relative Y (from doRender)
* @param z camera-relative Z (from doRender)
* @return alpha multiplier between ProximityAlphaMin and 1.0
*/
protected float getProximityAlphaFactor(EntityEnergyAbility entity, double x, double y, double z) {
return getProximityAlphaFactor(entity, x, y, z, false);
}
/**
* Overload that allows forcing proximity-only fade (no age fade-out).
* Used for attached beams and lasers that stay connected to the owner.
*
* @param alwaysUseProximity if true, age factor is ignored (proximity fade never expires)
*/
protected float getProximityAlphaFactor(EntityEnergyAbility entity, double x, double y, double z, boolean alwaysUseProximity) {
float minAlpha = ConfigClient.ProximityAlphaMin;
if (minAlpha >= 1.0f) return 1.0f;
// Only apply to the owner's client
EntityPlayer player = Minecraft.getMinecraft().thePlayer;
if (player == null || entity.getOwnerEntityId() != player.getEntityId()) {
return 1.0f;
}
// Distance factor: ramp from minAlpha at 0 to 1.0 at maxDist
float maxDist = ConfigClient.ProximityAlphaDistance;
float dist = (float) Math.sqrt(x * x + y * y + z * z);
float distFactor = Math.min(1.0f, dist / maxDist);
// Age factor: ramp from 0 to 1.0 over ageTicks
// Charging, attached beams/lasers, and alwaysUseProximity skip age fade
float ageFactor;
if (entity.isCharging() || alwaysUseProximity) {
ageFactor = 0.0f; // Always apply full proximity fade
} else {
int ageTicks = ConfigClient.ProximityAlphaAgeTicks;
if (ageTicks <= 0) {
ageFactor = 1.0f; // Age fade disabled
} else {
ageFactor = Math.min(1.0f, (float) entity.ticksExisted / ageTicks);
}
}
// Combined: take the max of both factors (either being far OR being old restores alpha)
float combinedFactor = Math.max(distFactor, ageFactor);
// Lerp between minAlpha and 1.0
return minAlpha + (1.0f - minAlpha) * combinedFactor;
}
@Override
protected ResourceLocation getEntityTexture(Entity entity) {
return WHITE_TEXTURE;
@@ -34,9 +34,12 @@ public class RenderEnergyBeam extends RenderEnergy {
setupRenderState();
// Proximity alpha fade for owner (attached beams always use proximity, never age out)
float proximityAlpha = getProximityAlphaFactor(beam, x, y, z, beam.isAttachedToOwner());
// Handle charging state (windup phase) - render only growing orb
if (beam.isCharging()) {
renderChargingOrb(beam, x, y, z, partialTicks);
renderChargingOrb(beam, x, y, z, partialTicks, proximityAlpha);
restoreRenderState();
return;
}
@@ -65,7 +68,7 @@ public class RenderEnergyBeam extends RenderEnergy {
float headSize = beam.getHeadSize();
int innerColor = beam.getInnerColor();
int outerColor = beam.getOuterColor();
float outerAlpha = beam.getOuterColorAlpha();
float outerAlpha = beam.getOuterColorAlpha() * proximityAlpha;
// Render everything relative to origin position
GL11.glPushMatrix();
@@ -77,10 +80,10 @@ public class RenderEnergyBeam extends RenderEnergy {
// Render tail orb at origin (0,0,0) - only in anchored mode
// Don't render if head is too close to origin (would cause overlap/extra orb appearance)
if (beam.shouldRenderTailOrb() && headDistFromOrigin > headSize * 0.5) {
renderTailOrb(headSize * 0.8f, innerColor, outerColor, beam.isOuterColorEnabled(), beam.getOuterColorWidth(), outerAlpha, beam.getInnerAlpha());
renderTailOrb(headSize * 0.8f, innerColor, outerColor, beam.isOuterColorEnabled(), beam.getOuterColorWidth(), outerAlpha, beam.getInnerAlpha() * proximityAlpha);
}
float innerAlpha = beam.getInnerAlpha();
float innerAlpha = beam.getInnerAlpha() * proximityAlpha;
// Render trail segments with smooth connections (with fading for non-anchored)
if (beam.hasFadingTrail()) {
@@ -101,7 +104,7 @@ public class RenderEnergyBeam extends RenderEnergy {
* Render the charging orb during windup phase.
* Grows from 0 to headSize based on charge progress.
*/
private void renderChargingOrb(EntityAbilityBeam beam, double x, double y, double z, float partialTicks) {
private void renderChargingOrb(EntityAbilityBeam beam, double x, double y, double z, float partialTicks, float proximityAlpha) {
float headSize = beam.getHeadSize();
float chargeProgress = beam.getInterpolatedChargeProgress(partialTicks);
float size = headSize * chargeProgress;
@@ -133,7 +136,7 @@ public class RenderEnergyBeam extends RenderEnergy {
// Render outer glow only if enabled
if (beam.isOuterColorEnabled()) {
float outerScale = innerScale + beam.getOuterColorWidth();
float outerAlpha = beam.getOuterColorAlpha();
float outerAlpha = beam.getOuterColorAlpha() * proximityAlpha;
GL11.glDepthMask(false);
GL11.glPushMatrix();
GL11.glScalef(outerScale, outerScale, outerScale);
@@ -144,7 +147,7 @@ public class RenderEnergyBeam extends RenderEnergy {
// Render inner core
GL11.glScalef(innerScale, innerScale, innerScale);
renderCube(innerColor, beam.getInnerAlpha(), 0.5f);
renderCube(innerColor, beam.getInnerAlpha() * proximityAlpha, 0.5f);
GL11.glPopMatrix();
GL11.glPopMatrix();
@@ -77,17 +77,20 @@ public class RenderEnergyDisc extends RenderEnergy {
// Inner scale defines the core size
float innerScale = 0.6f;
// Proximity alpha fade for owner
float proximityAlpha = getProximityAlphaFactor(disc, x, y, z);
// Render outer square (translucent) - only if enabled
// outerColorWidth is an additive offset from inner size
if (disc.isOuterColorEnabled()) {
float outerScale = innerScale + disc.getOuterColorWidth();
GL11.glDepthMask(false);
renderFlatSquare(disc.getOuterColor(), disc.getOuterColorAlpha(), radius * outerScale, thickness);
renderFlatSquare(disc.getOuterColor(), disc.getOuterColorAlpha() * proximityAlpha, radius * outerScale, thickness);
GL11.glDepthMask(true);
}
// Render inner square (solid)
renderFlatSquare(disc.getInnerColor(), disc.getInnerAlpha(), radius * innerScale, thickness * 1.2f);
renderFlatSquare(disc.getInnerColor(), disc.getInnerAlpha() * proximityAlpha, radius * innerScale, thickness * 1.2f);
GL11.glPopMatrix();
GL11.glPopMatrix();
@@ -27,8 +27,11 @@ public class RenderEnergyLaser extends RenderEnergy {
setupRenderState();
// Proximity alpha fade for owner (lasers are always attached, never age out)
float proximityAlpha = getProximityAlphaFactor(laser, x, y, z, true);
if (laser.isCharging()) {
renderChargingOrb(laser, x, y, z, partialTicks);
renderChargingOrb(laser, x, y, z, partialTicks, proximityAlpha);
restoreRenderState();
return;
}
@@ -126,14 +129,14 @@ public class RenderEnergyLaser extends RenderEnergy {
renderBeamRectangle(renderStartX, renderStartY, renderStartZ,
renderEndX, renderEndY, renderEndZ,
horzX, horzY, horzZ, vertX, vertY, vertZ,
outerWidth, laser.getOuterColor(), alpha * 0.4f);
outerWidth, laser.getOuterColor(), alpha * 0.4f * proximityAlpha);
// Render middle layer (halfway between inner and outer)
float midWidth = innerWidth + (outerWidth - innerWidth) * 0.5f;
renderBeamRectangle(renderStartX, renderStartY, renderStartZ,
renderEndX, renderEndY, renderEndZ,
horzX, horzY, horzZ, vertX, vertY, vertZ,
midWidth, laser.getOuterColor(), alpha * 0.7f);
midWidth, laser.getOuterColor(), alpha * 0.7f * proximityAlpha);
GL11.glDepthMask(true);
}
@@ -141,7 +144,7 @@ public class RenderEnergyLaser extends RenderEnergy {
renderBeamRectangle(renderStartX, renderStartY, renderStartZ,
renderEndX, renderEndY, renderEndZ,
horzX, horzY, horzZ, vertX, vertY, vertZ,
innerWidth, laser.getInnerColor(), alpha * laser.getInnerAlpha());
innerWidth, laser.getInnerColor(), alpha * laser.getInnerAlpha() * proximityAlpha);
// Render lightning along the laser beam
if (laser.hasLightningEffect() && laser.getCurrentLength() > 0.1f) {
@@ -152,7 +155,7 @@ public class RenderEnergyLaser extends RenderEnergy {
restoreRenderState();
}
private void renderChargingOrb(EntityAbilityLaser laser, double x, double y, double z, float partialTicks) {
private void renderChargingOrb(EntityAbilityLaser laser, double x, double y, double z, float partialTicks, float proximityAlpha) {
float headSize = laser.getLaserWidth() * 0.5f;
float chargeProgress = laser.getInterpolatedChargeProgress(partialTicks);
float size = headSize * chargeProgress;
@@ -184,7 +187,7 @@ public class RenderEnergyLaser extends RenderEnergy {
// Render outer glow only if enabled
if (laser.isOuterColorEnabled()) {
float outerScale = innerScale + laser.getOuterColorWidth();
float outerAlpha = laser.getOuterColorAlpha();
float outerAlpha = laser.getOuterColorAlpha() * proximityAlpha;
GL11.glDepthMask(false);
GL11.glPushMatrix();
GL11.glScalef(outerScale, outerScale, outerScale);
@@ -195,7 +198,7 @@ public class RenderEnergyLaser extends RenderEnergy {
// Render inner core
GL11.glScalef(innerScale, innerScale, innerScale);
renderCube(innerColor, laser.getInnerAlpha(), 0.5f);
renderCube(innerColor, laser.getInnerAlpha() * proximityAlpha, 0.5f);
GL11.glPopMatrix();
GL11.glPopMatrix();
@@ -69,6 +69,9 @@ public class RenderEnergyOrb extends RenderEnergy {
// Inner scale defines the core size
float innerScale = 0.6f;
// Proximity alpha fade for owner
float proximityAlpha = getProximityAlphaFactor(orb, x, y, z);
// Render outer cube (translucent) - only if enabled
// outerColorWidth is an additive offset from inner size
if (orb.isOuterColorEnabled()) {
@@ -76,14 +79,14 @@ public class RenderEnergyOrb extends RenderEnergy {
GL11.glDepthMask(false);
GL11.glPushMatrix();
GL11.glScalef(outerScale, outerScale, outerScale);
renderCube(orb.getOuterColor(), orb.getOuterColorAlpha(), 0.5f);
renderCube(orb.getOuterColor(), orb.getOuterColorAlpha() * proximityAlpha, 0.5f);
GL11.glPopMatrix();
GL11.glDepthMask(true);
}
// Render inner cube (solid)
GL11.glScalef(innerScale, innerScale, innerScale);
renderCube(orb.getInnerColor(), orb.getInnerAlpha(), 0.5f);
renderCube(orb.getInnerColor(), orb.getInnerAlpha() * proximityAlpha, 0.5f);
GL11.glPopMatrix();
GL11.glPopMatrix();
@@ -47,17 +47,20 @@ public class RenderEnergySlicer extends RenderEnergy {
float innerScale = 0.7f;
// Proximity alpha fade for owner
float proximityAlpha = getProximityAlphaFactor(slicer, x, y, z);
// Render outer blade (translucent glow)
if (slicer.isOuterColorEnabled()) {
float outerScale = 1.0f + slicer.getOuterColorWidth() * 0.2f;
GL11.glDepthMask(false);
renderBlade(slicer.getOuterColor(), slicer.getOuterColorAlpha(),
renderBlade(slicer.getOuterColor(), slicer.getOuterColorAlpha() * proximityAlpha,
width * 0.5f * outerScale, thickness * 2.0f, 0.05f);
GL11.glDepthMask(true);
}
// Render inner blade (solid core)
renderBlade(slicer.getInnerColor(), slicer.getInnerAlpha(),
renderBlade(slicer.getInnerColor(), slicer.getInnerAlpha() * proximityAlpha,
width * 0.5f * innerScale, thickness, 0.03f);
GL11.glPopMatrix();
@@ -57,6 +57,16 @@ public class ConfigClient {
public static Property LowResExplosionProperty;
public static boolean LowResExplosion = false;
// Proximity Alpha (owner-only fade for energy projectiles near camera)
public static Property ProximityAlphaMinProperty;
public static float ProximityAlphaMin = 0.15f;
public static Property ProximityAlphaDistanceProperty;
public static float ProximityAlphaDistance = 7.0f;
public static Property ProximityAlphaAgeTicksProperty;
public static int ProximityAlphaAgeTicks = 60;
/**
* Questing Properties
**/
@@ -291,6 +301,30 @@ public class ConfigClient {
);
LowResExplosion = LowResExplosionProperty.getBoolean(false);
ProximityAlphaMinProperty = config.get(
RENDERING,
"Proximity Alpha Min",
0.15,
"Minimum alpha for owner's energy projectiles when very close to camera. Set to 1.0 to disable proximity fade."
);
ProximityAlphaMin = (float) Math.max(0.0, Math.min(1.0, ProximityAlphaMinProperty.getDouble(0.15)));
ProximityAlphaDistanceProperty = config.get(
RENDERING,
"Proximity Alpha Distance",
7.0,
"Distance in blocks at which owner's energy projectiles reach full alpha."
);
ProximityAlphaDistance = (float) Math.max(1.0, ProximityAlphaDistanceProperty.getDouble(7.0));
ProximityAlphaAgeTicksProperty = config.get(
RENDERING,
"Proximity Alpha Age Ticks",
60,
"After this many ticks alive, proximity alpha fade is disabled (projectile always renders at full alpha). Does not apply while charging or to attached beams/lasers."
);
ProximityAlphaAgeTicks = Math.max(0, ProximityAlphaAgeTicksProperty.getInt(60));
DialogSpeedProperty = config.get(VISUAL, "Dialog Speed", true, "Only set for gradual dialogs");
DialogSpeed = DialogSpeedProperty.getInt(10);