package de.frajul.endlessroll.rendering.renderer;

import android.content.Context;
import android.opengl.GLES20;

import de.frajul.endlessroll.entities.particles.Particle;
import de.frajul.endlessroll.entities.particles.ParticleEffect;
import de.frajul.endlessroll.entities.particles.ParticleSource;
import de.frajul.endlessroll.main.GameLog;
import de.frajul.endlessroll.main.game.Scene;
import de.frajul.endlessroll.rendering.Fbo;
import de.frajul.endlessroll.rendering.MatrixCreator;
import de.frajul.endlessroll.rendering.Quad;
import de.frajul.endlessroll.rendering.shader.ParticleShader;

import javax.microedition.khronos.opengles.GL10;

/**
 * Created by Julian on 10.08.2016.
 */
public class ParticleRenderer {

    private Context context;
    private Quad quad;
    private MatrixCreator matrixCreator;
    private boolean additiveBlending = false;

    private ParticleShader particleShader;
    private Fbo fbo;

    public ParticleRenderer(Context context, Quad quad, MatrixCreator matrixCreator) {
        this.context = context;
        this.quad = quad;
        this.matrixCreator = matrixCreator;
    }

    public void createContext() throws Exception {
        particleShader = new ParticleShader(context);
    }

    public void createFbo(int width, int height) {
        fbo = new Fbo(width, height);
    }

    public void renderParticlesToFbo(GL10 gl, Scene scene) {
        fbo.bind();
        GLES20.glClearColor(0, 0, 0, 0.0f);
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

        particleShader.start();
        particleShader.loadMVPMatrix(matrixCreator, scene.getCamera());
        synchronized (scene.getParticleSystem().getEffects()) {
            for (ParticleEffect effect : scene.getParticleSystem().getEffects()) {
                gl.glActiveTexture(GL10.GL_TEXTURE0);
                gl.glBindTexture(GL10.GL_TEXTURE_2D, effect.getTexture().getId());

                switchAdditiveBlending(gl, effect.getOptions().isAdditive());
                synchronized (effect.getSources()) {
                    for (ParticleSource source : effect.getSources()) {
                        source.getActiveParticleLock().lock();
                        for (Particle particle : source.getActiveParticles())
                            renderParticle(particle);
                        source.getActiveParticleLock().unlock();
                    }
                }
            }
        }
        disableAdditiveBlending(gl);

        particleShader.stop();
        fbo.unbind();
    }


    private void renderParticle(Particle particle) {
        particleShader.loadTransformationMatrix(matrixCreator, particle);
        particleShader.loadColor(particle.getColor());
        particleShader.loadAlpha(particle.getAlpha());
        quad.draw();
    }

    private void switchAdditiveBlending(GL10 gl, boolean additive) {
        if (additive && !additiveBlending)
            enableAdditiveBlending(gl);
        if (!additive && additiveBlending)
            disableAdditiveBlending(gl);
    }

    private void enableAdditiveBlending(GL10 gl) {
        if (!additiveBlending) {
            additiveBlending = true;
            gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE);
        }
    }

    private void disableAdditiveBlending(GL10 gl) {
        if (additiveBlending) {
            additiveBlending = false;
            gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
        }
    }

    public int getFboTexture() {
        return fbo.getTexture();
    }
}
