/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2014-2015 Sri Harsha Chilakapati
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package com.shc.silenceengine.scene;

import com.shc.silenceengine.core.IUpdatable;
import com.shc.silenceengine.core.SilenceEngine;
import com.shc.silenceengine.graphics.ModelBatch;
import com.shc.silenceengine.graphics.cameras.BaseCamera;
import com.shc.silenceengine.graphics.opengl.GL3Context;
import com.shc.silenceengine.math.Frustum;
import com.shc.silenceengine.math.Transform;
import com.shc.silenceengine.scene.entity.Entity3D;
import org.lwjgl.opengl.GL11;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Sri Harsha Chilakapati
 */
public class Scene3D implements IUpdatable
{
    private List<SceneComponent> components;
    private List<Entity3D>       entities;

    private Transform transform;

    private boolean frustumCulling;

    public Scene3D()
    {
        components = new ArrayList<>();
        entities = new ArrayList<>();
        transform = new Transform();

        setFrustumCulling(true);
    }

    public void update(float delta)
    {
        for (int i = 0; i < entities.size(); i++)
        {
            Entity3D entity = entities.get(i);

            if (entity.isDestroyed())
            {
                entities.remove(entity);
                i--;
                continue;
            }

            entity.preUpdate(delta);
        }

        for (SceneComponent component : components)
            component.update(delta);
    }

    public void render(float delta)
    {
        // Quit early if there are no children
        if (entities.size() == 0)
            return;

        // Get the Frustum once to save unnecessary calculations
        Frustum frustum = BaseCamera.CURRENT.getFrustum();

        doRender(delta, frustum);

        for (SceneComponent component : components)
        {
            GL3Context.blendFunc(GL11.GL_ONE, GL11.GL_ONE);
            GL3Context.depthMask(false);
            GL3Context.depthFunc(GL11.GL_EQUAL);

            component.use();
            doRender(delta, frustum);
            component.release();

            GL3Context.depthFunc(GL11.GL_LESS);
            GL3Context.depthMask(true);
            GL3Context.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
        }
    }

    private void doRender(float delta, Frustum frustum)
    {
        ModelBatch batch = SilenceEngine.graphics.getModelBatch();

        batch.begin(transform);
        {
            entities.forEach(e ->
            {
                if (frustumCulling && frustum.intersects(e.getPolyhedron()))
                    e.render(delta, batch);
            });
        }
        batch.end();
    }

    public void addChild(Entity3D e)
    {
        entities.add(e);
    }

    public void addComponent(SceneComponent c)
    {
        components.add(c);
    }

    public void removeChild(Entity3D e)
    {
        entities.remove(e);
    }

    public void removeComponent(SceneComponent component)
    {
        components.remove(component);
    }

    public void destroy()
    {
        entities.forEach(Entity3D::destroy);
        components.forEach(SceneComponent::dispose);

        entities.clear();
        components.clear();
    }

    public Transform getTransform()
    {
        return transform;
    }

    public List<Entity3D> getEntities()
    {
        return entities;
    }

    public List<SceneComponent> getComponents()
    {
        return components;
    }

    public boolean isFrustumCullingEnabled()
    {
        return frustumCulling;
    }

    public void setFrustumCulling(boolean frustumCulling)
    {
        this.frustumCulling = frustumCulling;
    }
}

@@ -3547,29 +3547,35 @@
     
-entities.forEach(e -%3E
+for (Entity3D e : entities)
 %0A   
@@ -3623,16 +3623,17 @@
 ling && 
+!
 frustum.
@@ -3663,24 +3663,51 @@
 ron()))%0A    
+                continue;%0A%0A
             
@@ -3747,18 +3747,16 @@
        %7D
-);
 %0A       

Fix scene not rendering when frustum culling disabled