/*
 * Copyright 2016 MovingBlocks
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.terasology.rendering.dag.nodes;

import org.lwjgl.opengl.GL11;
import org.terasology.engine.ComponentSystemManager;
import org.terasology.entitySystem.systems.RenderSystem;
import org.terasology.monitoring.PerformanceMonitor;
import org.terasology.registry.In;
import org.terasology.rendering.dag.AbstractNode;
import org.terasology.rendering.dag.stateChanges.BindFBO;
import static org.lwjgl.opengl.GL11.GL_BLEND;
import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_SRC_ALPHA;
import static org.lwjgl.opengl.GL11.GL_SRC_ALPHA;
import static org.terasology.rendering.opengl.DefaultDynamicFBOs.READ_ONLY_GBUFFER;
import org.terasology.rendering.opengl.fbms.DisplayResolutionDependentFBOs;

/**
 * TODO: Add diagram of this node
 */
public class SimpleBlendMaterialsNode extends AbstractNode {

    @In
    private ComponentSystemManager componentSystemManager;

    @In
    private DisplayResolutionDependentFBOs displayResolutionDependentFBOs;


    @Override
    public void initialise() {
        addDesiredStateChange(new BindFBO(READ_ONLY_GBUFFER.getName(), displayResolutionDependentFBOs)); // TODO: might be removed, verify it
        // TODO: review - might be redundant to setRenderBufferMask(sceneOpaque) again at the end of the process() method
    }

    @Override
    public void process() {
        PerformanceMonitor.startActivity("rendering/simpleBlendMaterials");
        preRenderSetupSimpleBlendMaterials();

        for (RenderSystem renderer : componentSystemManager.iterateRenderSubscribers()) {
            renderer.renderAlphaBlend();
        }

        postRenderCleanupSimpleBlendMaterials();
        PerformanceMonitor.endActivity();
    }

    /**
     * Sets the state for the rendering of objects or portions of objects having some degree of transparency.
     * <p>
     * Generally speaking objects drawn with this state will have their color blended with the background
     * color, depending on their opacity. I.e. a 25% opaque foreground object will provide 25% of its
     * color while the background will provide the remaining 75%. The sum of the two RGBA vectors gets
     * written onto the output buffer.
     * <p>
     * Important note: this method disables writing to the Depth Buffer. This is why filters relying on
     * depth information (i.e. DoF) have problems with transparent objects: the depth of their pixels is
     * found to be that of the background. This is an unresolved (unresolv-able?) issue that would only
     * be reversed, not eliminated, by re-enabling writing to the Depth Buffer.
     */
    private void preRenderSetupSimpleBlendMaterials() {
        READ_ONLY_GBUFFER.setRenderBufferMask(true, true, true);
        GL11.glEnable(GL_BLEND);
        GL11.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // (*)
        GL11.glDepthMask(false);

        // (*) In this context SRC is Foreground. This effectively says:
        // Resulting RGB = ForegroundRGB * ForegroundAlpha + BackgroundRGB * (1 - ForegroundAlpha)
        // Which might still look complicated, but it's actually the most typical alpha-driven composite.
        // A neat tool to play with this settings can be found here: http://www.andersriggelsen.dk/glblendfunc.php
    }

    /**
     * Resets the state after the rendering of semi-opaque/semi-transparent objects.
     * <p>
     * See preRenderSetupSimpleBlendMaterials() for additional information.
     */
    private void postRenderCleanupSimpleBlendMaterials() {
        GL11.glDisable(GL_BLEND);
        GL11.glDepthMask(true);
    }
}

@@ -975,54 +975,8 @@
 BO;%0A
-import static org.lwjgl.opengl.GL11.GL_BLEND;%0A
 impo
@@ -1073,32 +1073,164 @@
 1.GL_SRC_ALPHA;%0A
+import org.terasology.rendering.dag.stateChanges.DisableDepthMask;%0Aimport org.terasology.rendering.dag.stateChanges.EnableBlending;%0A
 import static or
@@ -1630,17 +1630,16 @@
 tFBOs;%0A%0A
-%0A
     @Ove
@@ -1938,16 +1938,125 @@
 ) method
+%0A%0A        addDesiredStateChange(new EnableBlending());%0A        addDesiredStateChange(new DisableDepthMask());
 %0A    %7D%0A%0A
@@ -2366,57 +2366,8 @@
  %7D%0A%0A
-        postRenderCleanupSimpleBlendMaterials();%0A
     
@@ -3427,41 +3427,8 @@
 e);%0A
-        GL11.glEnable(GL_BLEND);%0A
     
@@ -3497,41 +3497,8 @@
  (*)
-%0A        GL11.glDepthMask(false);
 %0A%0A  
@@ -3897,327 +3897,7 @@
    %7D
-%0A%0A    /**%0A     * Resets the state after the rendering of semi-opaque/semi-transparent objects.%0A     * %3Cp%3E%0A     * See preRenderSetupSimpleBlendMaterials() for additional information.%0A     */%0A    private void postRenderCleanupSimpleBlendMaterials() %7B%0A        GL11.glDisable(GL_BLEND);%0A        GL11.glDepthMask(true);%0A    %7D
 %0A%7D%0A

Add desiredStateChanges to SimpleBlendMaterialsNode