<commit_before>/*
 * The MIT License (MIT)
 *
 * FXGL - JavaFX Game Library
 *
 * Copyright (c) 2015-2016 AlmasB (<EMAIL>)
 *
 * 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.almasb.fxgl.scene;

import com.almasb.ents.*;
import com.almasb.fxgl.app.FXGL;
import com.almasb.fxgl.app.GameApplication;
import com.almasb.fxgl.effect.ParticleControl;
import com.almasb.fxgl.entity.EntityView;
import com.almasb.fxgl.entity.RenderLayer;
import com.almasb.fxgl.entity.component.MainViewComponent;
import com.almasb.fxgl.event.UpdateEvent;
import com.almasb.fxgl.logging.Logger;
import com.almasb.fxgl.physics.PhysicsWorld;
import com.almasb.fxgl.time.UpdateEventListener;
import com.almasb.fxgl.ui.UIFactory;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import javafx.beans.value.ChangeListener;
import javafx.collections.ObservableList;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.effect.BlendMode;
import javafx.scene.text.Text;

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

/**
 * Represents the scene that shows game objects on the screen during "play" mode.
 * Contains 3 layers. From bottom to top:
 * <ol>
 *     <li>Entities and their render layers</li>
 *     <li>Particles</li>
 *     <li>UI Overlay</li>
 * </ol>
 *
 * @author <NAME> (AlmasB) (<EMAIL>)
 */
@Singleton
public final class GameScene extends FXGLScene implements EntityWorldListener,
        UpdateEventListener, ComponentListener, ControlListener {

    private static final Logger log = FXGL.getLogger("FXGL.GameScene");

    /**
     * Root for entity views, it is affected by viewport movement.
     */
    private Group gameRoot = new Group();

    /**
     * Canvas for particles to accelerate drawing.
     */
    private Canvas particlesCanvas = new Canvas();

    /**
     * Graphics context for drawing particles.
     */
    private GraphicsContext particlesGC = particlesCanvas.getGraphicsContext2D();

    private List<ParticleControl> particles = new ArrayList<>();

    /**
     * The overlay root above {@link #gameRoot}. Contains UI elements, native JavaFX nodes.
     * uiRoot isn't affected by viewport movement.
     */
    private Group uiRoot = new Group();

    @Inject
    protected GameScene(@Named("appWidth") double width,
                        @Named("appHeight") double height) {
        getRoot().getChildren().addAll(gameRoot, particlesCanvas, uiRoot);

        initParticlesCanvas(width, height);
        initViewport(width, height);
        initFPSText(height);

        log.debug("Game scene initialized: " + width + "x" + height);
    }

    private void initParticlesCanvas(double w, double h) {
        particlesCanvas.setWidth(w);
        particlesCanvas.setHeight(h);
        particlesCanvas.setMouseTransparent(true);
    }

    private Viewport viewport;

    /**
     * @return viewport
     */
    public Viewport getViewport() {
        return viewport;
    }

    private void initViewport(double w, double h) {
        viewport = new Viewport(w, h);
        gameRoot.layoutXProperty().bind(viewport.xProperty().negate());
        gameRoot.layoutYProperty().bind(viewport.yProperty().negate());
    }

    private Text fpsText;

    private void initFPSText(double height) {
        fpsText = UIFactory.newText("", 24);
        fpsText.setTranslateY(height - 40);
    }

    /**
     * Converts a point on screen to a point within game scene.
     *
     * @param screenPoint point in UI coordinates
     * @return point in game coordinates
     */
    public Point2D screenToGame(Point2D screenPoint) {
        return screenPoint
                .multiply(1.0 / FXGL.getDisplay().getScaleRatio())
                .add(viewport.getOrigin());
    }

    /**
     * @return unmodifiable list of UI nodes
     */
    public ObservableList<Node> getUINodes() {
        return uiRoot.getChildrenUnmodifiable();
    }

    /**
     * Add a node to the UI overlay.
     *
     * @param node UI node to add
     */
    public void addUINode(Node node) {
        log.debug("Adding UI node: "+ node);<commit_msg>added gameToScreen(), closes #174<commit_after>/*
 * The MIT License (MIT)
 *
 * FXGL - JavaFX Game Library
 *
 * Copyright (c) 2015-2016 AlmasB (<EMAIL>)
 *
 * 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.almasb.fxgl.scene;

import com.almasb.ents.*;
import com.almasb.fxgl.app.FXGL;
import com.almasb.fxgl.app.GameApplication;
import com.almasb.fxgl.effect.ParticleControl;
import com.almasb.fxgl.entity.EntityView;
import com.almasb.fxgl.entity.RenderLayer;
import com.almasb.fxgl.entity.component.MainViewComponent;
import com.almasb.fxgl.event.UpdateEvent;
import com.almasb.fxgl.logging.Logger;
import com.almasb.fxgl.physics.PhysicsWorld;
import com.almasb.fxgl.time.UpdateEventListener;
import com.almasb.fxgl.ui.UIFactory;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import javafx.beans.value.ChangeListener;
import javafx.collections.ObservableList;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.effect.BlendMode;
import javafx.scene.text.Text;

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

/**
 * Represents the scene that shows game objects on the screen during "play" mode.
 * Contains 3 layers. From bottom to top:
 * <ol>
 *     <li>Entities and their render layers</li>
 *     <li>Particles</li>
 *     <li>UI Overlay</li>
 * </ol>
 *
 * @author <NAME> (AlmasB) (<EMAIL>)
 */
@Singleton
public final class GameScene extends FXGLScene implements EntityWorldListener,
        UpdateEventListener, ComponentListener, ControlListener {

    private static final Logger log = FXGL.getLogger("FXGL.GameScene");

    /**
     * Root for entity views, it is affected by viewport movement.
     */
    private Group gameRoot = new Group();

    /**
     * Canvas for particles to accelerate drawing.
     */
    private Canvas particlesCanvas = new Canvas();

    /**
     * Graphics context for drawing particles.
     */
    private GraphicsContext particlesGC = particlesCanvas.getGraphicsContext2D();

    private List<ParticleControl> particles = new ArrayList<>();

    /**
     * The overlay root above {@link #gameRoot}. Contains UI elements, native JavaFX nodes.
     * uiRoot isn't affected by viewport movement.
     */
    private Group uiRoot = new Group();

    @Inject
    protected GameScene(@Named("appWidth") double width,
                        @Named("appHeight") double height) {
        getRoot().getChildren().addAll(gameRoot, particlesCanvas, uiRoot);

        initParticlesCanvas(width, height);
        initViewport(width, height);
        initFPSText(height);

        log.debug("Game scene initialized: " + width + "x" + height);
    }

    private void initParticlesCanvas(double w, double h) {
        particlesCanvas.setWidth(w);
        particlesCanvas.setHeight(h);
        particlesCanvas.setMouseTransparent(true);
    }

    private Viewport viewport;

    /**
     * @return viewport
     */
    public Viewport getViewport() {
        return viewport;
    }

    private void initViewport(double w, double h) {
        viewport = new Viewport(w, h);
        gameRoot.layoutXProperty().bind(viewport.xProperty().negate());
        gameRoot.layoutYProperty().bind(viewport.yProperty().negate());
    }

    private Text fpsText;

    private void initFPSText(double height) {
        fpsText = UIFactory.newText("", 24);
        fpsText.setTranslateY(height - 40);
    }

    /**
     * Converts a point on screen to a point within game scene.
     *
     * @param screenPoint point in UI coordinates
     * @return point in game coordinates
     */
    public Point2D screenToGame(Point2D screenPoint) {
        return screenPoint
                .multiply(1.0 / FXGL.getDisplay().getScaleRatio())
                .add(viewport.getOrigin());
    }

    /**
     * Converts a point in game world to a point within screen (viewport).
     *
     * @param gamePoint point in game world coordinates
     * @return point in UI coordinates
     */
    public Point2D gameToScreen(Point2D gamePoint) {
        return gamePoint
                .subtract(viewport.getOrigin())
                .multiply(FXGL.getDisplay().getScaleRatio());
    }

    /**
     * @return unmodifiable list of UI nodes
     */
    public ObservableList<Node> getUINodes() {
        return uiRoot.getChildrenUnmodifiable();
    }

    /**
     * Add a node to the UI overlay.
     *
     * @param node UI node to add
     */
    public void addUINode(Node node) {
        log.debug("Adding UI node: "+ node);
{'fraction_non_alphanumeric': 0.09840863361990122, 'fraction_numerical': 0.00393268703127858, 'mean_word_length': 3.215497301464919, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '409527', 'n_tokens_mistral': 3192, 'n_tokens_neox': 3073, 'n_words': 980}