/*******************************************************************************************************************
* Authors: SanAndreasP
* Copyright: SanAndreasP
* License: Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
* http://creativecommons.org/licenses/by-nc-sa/4.0/
*******************************************************************************************************************/
package de.sanandrew.core.manpack.mod.client.particle;
import com.google.common.base.Predicate;
import com.google.common.collect.*;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import de.sanandrew.core.manpack.util.client.EntityParticle;
import de.sanandrew.core.manpack.util.client.event.SAPFxLayerRenderEvent;
import de.sanandrew.core.manpack.util.helpers.SAPUtils;
import de.sanandrew.core.manpack.util.javatuples.Pair;
import net.minecraft.client.particle.EntityFX;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.entity.Entity;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.opengl.GL11;
import javax.annotation.Nullable;
import java.util.*;
import java.util.Map.Entry;
@SideOnly( Side.CLIENT )
public class SAPEffectRenderer
{
private static final ResourceLocation PARTICLE_TEXTURES = new ResourceLocation("textures/particle/particles.png");
private int defaultFxLayer = 0;
private Map<Integer, Pair<ResourceLocation, Boolean>> fxLayers = new HashMap<>();
private Multimap<Integer, EntityParticle> particles = ArrayListMultimap.create();
private TextureManager textureManager;
private static boolean isInitialized = false;
public static final SAPEffectRenderer INSTANCE = new SAPEffectRenderer();
public int getDefaultFxLayer() {
return this.defaultFxLayer;
}
public void addEffect(EntityParticle particle) {
particles.put(particle.getFXLayer(), particle);
}
public int registerFxLayer(ResourceLocation resource, boolean hasAlpha) {
Pair<ResourceLocation, Boolean> newEntry = Pair.with(resource, hasAlpha);
int newIndex = this.fxLayers.size();
this.fxLayers.put(newIndex, newEntry);
return newIndex;
}
public void updateEffects() {
Iterator<EntityParticle> particleIt = this.particles.values().iterator();
while( particleIt.hasNext() ) {
EntityParticle particle = particleIt.next();
try {
if( particle != null ) {
particle.onUpdate();
}
} catch( Throwable throwable ) {
throw new RuntimeException("Error in ticking particle!");
}
if( particle == null || particle.isDead ) {
particleIt.remove();
}
}
}
public void renderParticles(Entity viewingEntity, float partTicks, boolean alpha) {
float rotX = ActiveRenderInfo.rotationX;
float rotZ = ActiveRenderInfo.rotationZ;
float rotYZ = ActiveRenderInfo.rotationYZ;
float rotXY = ActiveRenderInfo.rotationXY;
float rotXZ = ActiveRenderInfo.rotationXZ;
EntityFX.interpPosX = viewingEntity.lastTickPosX + (viewingEntity.posX - viewingEntity.lastTickPosX) * partTicks;
EntityFX.interpPosY = viewingEntity.lastTickPosY + (viewingEntity.posY - viewingEntity.lastTickPosY) * partTicks;
EntityFX.interpPosZ = viewingEntity.lastTickPosZ + (viewingEntity.posZ - viewingEntity.lastTickPosZ) * partTicks;
Collection<Entry<Integer, Pair<ResourceLocation, Boolean>>> currLayers = Collections2.filter(this.fxLayers.entrySet(), new SortingFilter(alpha));
for( Entry<Integer, Pair<ResourceLocation, Boolean>> layer : currLayers ) {
Pair<ResourceLocation, Boolean> layerData = layer.getValue();
Collection<EntityParticle> particles = this.particles.get(layer.getKey());
if( !particles.isEmpty() ) {
Tessellator tessellator = Tessellator.instance;
tessellator.startDrawingQuads();
for( final EntityParticle particle : particles ) {
if( particle == null ) {
continue;
}
tessellator.setBrightness(particle.getBrightnessForRender(partTicks));
try {
particle.renderParticle(tessellator, partTicks, rotX, rotXZ, rotZ, rotYZ, rotXY);
} catch( Throwable throwable ) {
throw new RuntimeException("Couldn't render particle!", throwable);
}
}
this.textureManager.bindTexture(layerData.getValue0());
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
if( layerData.getValue1() ) {
GL11.glEnable(GL11.GL_BLEND);
OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
}
SAPUtils.EVENT_BUS.post(new SAPFxLayerRenderEvent.Pre(layer.getKey(), tessellator));
tessellator.draw();
SAPUtils.EVENT_BUS.post(new SAPFxLayerRenderEvent.Post(layer.getKey()));
if( layerData.getValue1() ) {
GL11.glDisable(GL11.GL_BLEND);
}
}
}
}
public static void initialize(TextureManager texManager) {
if( isInitialized ) {
return;
}
isInitialized = true;
INSTANCE.textureManager = texManager;
INSTANCE.defaultFxLayer = INSTANCE.registerFxLayer(PARTICLE_TEXTURES, false);
}
private static class SortingFilter
implements Predicate<Entry<Integer, Pair<ResourceLocation, Boolean>>>
{
private final boolean hasAlpha;
public SortingFilter(boolean alpha) {
this.hasAlpha = alpha;
}
@Override
public boolean apply(@Nullable Entry<Integer, Pair<ResourceLocation, Boolean>> input) {
return input != null && input.getValue().getValue1() == this.hasAlpha;
}
}
}