Back to project page DolphinOES.
The source code is released under:
Apache License
If you think the Android project DolphinOES listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
/******************************************************************************* Copyright 2014 See AUTHORS file. * //from w ww .ja v a 2s. c o m * 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 com.sidereal.dolphinoes.architecture; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.glutils.ShaderProgram; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.utils.GdxRuntimeException; import com.sidereal.dolphinoes.architecture.core.GameData.Settings; import com.sidereal.dolphinoes.behaviors.input.Clickable; import com.sidereal.dolphinoes.behaviors.triggers.Hoverable; import com.sidereal.dolphinoes.util.BooleanWrapper; /** An object used for handling multiple {@link GameObject} instances at the same time, rendering them using * {@link #camera} and {@link #spriteBatch}, with the possibility of adding a shader and sorting the objects, as well as * access to the mouse position translated to {@link #camera}'s coordinate system. * <p> * GameBatch objects are added in {@link GameScene#addGameBatch(GameBatch)} , and are iterated over in * {@link GameScene#render(float)}. * * @author Claudiu */ public class GameBatch { // region fields /** Area that the camera sees and outside of which images are not rendered. */ public Rectangle renderingArea; public enum ShaderType { Initialisation, Update, Resize }; /** Sprite batch on which to render all objects that are using the {@link GameBatch} that the {@link SpriteBatch} is * tied to. * <p> * The shader found in {@link #shaderProgram} will be applied to this rendering batch. */ public SpriteBatch spriteBatch; /** Shape renderer focused on the {@link GameBatch}'s camera. */ public ShapeRenderer shapeRenderer; /** Camera used for rendering objects tied to {@link #spriteBatch}. * <p> * The camera's position can be made to target a certain {@link GameObject} by assigning {@link #target}. */ public OrthographicCamera camera; /** Variable used for sorting the {@link GameBatch} rendering order in the scene. Is used in * {@link GameScene#gameBatchComparator}. */ public int priorityLevel; /** Name of the gamebatch. * <p> * Is set in the constructor and used in {@link GameObject#setGameBatch}. */ public String name; /** List of {@link GameObject} entries tied to the {@link GameBatch}. */ public List<GameObject> objects; /** Whether to translate the mouse position to the {@link #camera}'s projection matrix. This will make using certain * IO-related behaviors such as {@link Clickable} or {@link Hoverable} work in {@link GameObject} objects tied to * the {@link GameBatch} */ public boolean translateMousePosition; /** If not null, the {@link GameBatch} will be using the referencing batch's {@link #camera}, {@link #mousePosition}. * Will be set in {@link #GameBatch(GameScene, String, GameBatch)}. */ public GameBatch referencingBatch; /** Whether to sort the GameObjects in {@link #objects} before updating them or not. Set in {@link #setSort(boolean, Comparator)} */ private boolean sort; /** The sorting algorithm to run if {@link #sort} is true on {@link #objects} . Set in {@link #setSort(boolean, Comparator)} * <p> * By default, will first render objects at the top of the screen, with a lower level. */ private Comparator<GameObject> objectsComparator; /** Thread that updates the batch, calling {@link #doUpdate()} every frame. Is called in {@link #run()}. */ private Thread updateThread; /** The {@link GameScene} that the batch is found in. Set up in {@link #initialiseBatch(GameScene, String)}. */ private GameScene scene; /** Object used for translating the mouse position to the camera's coordinate system. After translating it, will be * used to set variables in {@link #mousePosition}. */ private Vector3 tempMousePosition; /** The position of the mouse, translated to the camera's coordinate system. */ public Vector2 mousePosition; /** Shader to run every frame on {@link #spriteBatch}. Is set in * {@link #setShader(ShaderProgram, AbstractEvent, ShaderType)}. */ private ShaderProgram shaderProgram; /** Event with the purpose of passing uniform values to the shader. Will be called based on {@link #shaderType}. */ private AbstractEvent shaderUniformValuesEvent; /** The type of shader. Affects when {@link #shaderUniformValuesEvent} runs. * <p> * If {@link #shaderType} is set to {@link ShaderType#Initialisation}, the event is running when set in * {@link #setShader(ShaderProgram, AbstractEvent, ShaderType)} only. * <p> * If {@link #shaderType} is set to {@link ShaderType#Resize}, the event is running whenever {@link #resize()} is * called. * <p> * If {@link #shaderType} is set to {@link ShaderType#Update}, the event runs every frame in {@link #doUpdate()}. */ private ShaderType shaderType; // endregion // region constructors /** Constructor for a GameBatch that calls {@link #initialiseBatch(GameScene, String)}, as well as set up the camera * and the mouse position as the batch does not reference anything. * * @param scene * The scene in which to add the game batch. * @param name * name of the gameBatch, used for retrieval of Batch using {@link GameScene#getGameBatch(String)}. */ public GameBatch(GameScene scene, String tag) { initialiseBatch(scene, tag); this.tempMousePosition = new Vector3(); this.mousePosition = new Vector2(); this.camera = new OrthographicCamera(); camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); this.translateMousePosition = false; this.renderingArea = new Rectangle(); } /** Constructor for a GameBatch that uses resources from the <code> * referencingBatch</code> parameter to keep consistency. * <p> * Throws a {@link GdxRuntimeException} if passed {@link GameBatch} is null. * * @param scene * The scene in which to add the game batch. * @param name * name of the gameBatch, used for retrieval of Batch using {@link GameScene#getGameBatch(String)}. * @param referencingBatch */ public GameBatch(GameScene scene, String tag, GameBatch referencingBatch) { initialiseBatch(scene, tag); if (referencingBatch == null) throw new GdxRuntimeException("Referencing batch in constructor for the " + tag + " batch was null. Use the constructor without a batch as a parameter if no referencing batch is " + "needed"); this.referencingBatch = referencingBatch; this.camera = referencingBatch.camera; this.mousePosition = referencingBatch.mousePosition; this.renderingArea = referencingBatch.renderingArea; } /** Common initialisation code between the two constructors of {@link GameBatch}, initialising variables in the * scene. * <p> * If the scene or the batch name are null, a {@link GdxRuntimeException} is thrown. * * @param scene * The scene in which to add the game batch. * @param name * name of the gameBatch, used for retrieval of Batch using {@link GameScene#getGameBatch(String)}. */ private final void initialiseBatch(GameScene scene, String name) { if (scene == null) throw new GdxRuntimeException("GameScene parameter passed to GameBatch is null"); if (name == null) throw new GdxRuntimeException("String parameter passed to GameBatch is null"); this.scene = scene; this.name = name; this.shapeRenderer = new ShapeRenderer(); this.shapeRenderer.setAutoShapeType(true); this.spriteBatch = new SpriteBatch(); this.objects = new ArrayList<GameObject>(); this.priorityLevel = 0; this.sort = true; this.objectsComparator = new Comparator<GameObject>() { @Override public int compare(GameObject o1, GameObject o2) { if (o1.pos.getZ() != o2.pos.getZ()) { return (int) (o1.pos.getZ() - o2.pos.getZ()); } else { return (int) o2.pos.getY() - (int) o1.pos.getY(); } } }; updateThread = new Thread(new Runnable() { @Override public void run() { doUpdate(); } }); } // endregion // region methods /** Updates the area within which objects will be drawn. */ private final void updateRenderingArea() { renderingArea.set(camera.position.x - ((camera.viewportWidth / 2f) * camera.zoom), camera.position.y - ((camera.viewportHeight / 2f) * camera.zoom), camera.viewportWidth * camera.zoom, camera.viewportHeight * camera.zoom); } /** Runs every frame, updating all game objects and the mouse position to the camera's location. Gets called from * {@link GameScene#render(float)} * * @param info * the game information */ final void run() { if (translateMousePosition) { tempMousePosition.set(Gdx.input.getX(), Gdx.input.getY(), 0); // translate the pixel to world camera.unproject(tempMousePosition); // updating mouse position. mousePosition.x = tempMousePosition.x; mousePosition.y = tempMousePosition.y; } if (((BooleanWrapper) DolphinOES.data.getSettings(Settings.MULTI_THREADED)).get()) updateThread.run(); else doUpdate(); } /** Handles setting the shader for the {@link #spriteBatch}. * * @param program * The shader to run every frame * @param uniformValuesEvent * the event for setting uniforms. * @param type * The type of shader, which affects when <code>uniformValuesEvent</code> gets called. */ public final void setShader(ShaderProgram program, AbstractEvent uniformValuesEvent, ShaderType type) { // not using shaders in the settings. if (!((BooleanWrapper) DolphinOES.data.getSettings(Settings.USE_SHADERS)).get()) return; // don't handle shader if it GLSL failed compilation if (!program.isCompiled()) { DolphinOES.debug.log(program.getLog()); return; } // handling null variables if (program == null || type == null) { this.shaderProgram = null; this.shaderUniformValuesEvent = null; this.spriteBatch.setShader(null); return; } ShaderProgram.pedantic = false; this.shaderProgram = program; this.shaderType = type; this.shaderUniformValuesEvent = uniformValuesEvent; spriteBatch.setShader(this.shaderProgram); DolphinOES.debug.log("Shader compiled successfully? " + this.shaderProgram.isCompiled()); // run initialisation or resize event if (this.shaderUniformValuesEvent != null && (shaderType.equals(ShaderType.Initialisation) || shaderType.equals(ShaderType.Resize)) && this.shaderProgram.isCompiled()) { shaderProgram.begin(); this.shaderUniformValuesEvent.run(shaderProgram); shaderProgram.end(); } } /** Resizes the GameBatch, updating the camera's size, as well as the objects that depend on it, such as * {@link #shaderProgram}, {@link #spriteBatch} or {@link #shapeRenderer}. * <p> * All of the objects tied to the GameBatch ( the ones in {@link #objects}) are being resized by calling * {@link GameObject#onResize(float, float, float, float)} on all of them. */ public final void resize() { float oldWidth = camera.viewportWidth; float oldHeight = camera.viewportHeight; // set up new width camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); // if camera has a target, set pos back to target camera.update(); spriteBatch.setProjectionMatrix(camera.combined); shapeRenderer.setProjectionMatrix(camera.combined); // run resize event if (this.shaderUniformValuesEvent != null && this.shaderType.equals(ShaderType.Resize) && this.shaderProgram.isCompiled()) { shaderProgram.begin(); this.shaderUniformValuesEvent.run(shaderProgram); shaderProgram.end(); } for (int i = 0; i < objects.size(); i++) { if (objects.get(i).isInScene()) objects.get(i).onResize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), oldWidth, oldHeight); } } /** Method that updates all objects in {@link #objects}. */ private final void doUpdate() { if (objects == null || scene == null) return; // batch's scene is not the same as the current scene. if (DolphinOES.getScene() != null && !this.scene.equals(DolphinOES.getScene())) { scene = null; return; } if (objects.size() == 0) return; if (sort) { try { Collections.sort(objects, objectsComparator); } catch (Exception e) { DolphinOES.debug.log("Caught exception " + e.getMessage() + e.toString()); e.printStackTrace(); } } updateRenderingArea(); if (shaderUniformValuesEvent != null && shaderType.equals(ShaderType.Update) && shaderProgram.isCompiled()) { shaderProgram.begin(); shaderUniformValuesEvent.run(shaderProgram); shaderProgram.end(); } spriteBatch.setProjectionMatrix(camera.combined); shapeRenderer.setProjectionMatrix(camera.combined); spriteBatch.begin(); shapeRenderer.begin(); // update objects if (objects != null) { for (int i = 0; i < objects.size(); i++) { objects.get(i).updateInternal(); if (objects == null) return; } if (DolphinOES.debug.isEnabled()) { for (int i = 0; i < objects.size(); i++) { objects.get(i).updateDebug(); } } } spriteBatch.end(); shapeRenderer.end(); } public void dispose() { spriteBatch.dispose(); } /** Sets whether or not sorting should be enabled, and maybe the comparator used in sorting * <p> * If the <code>enabled</code> parameter is set to true, the <code>comparator</code> can be null only * if the value of the internal comparator has been set before, either in the {@link GameBatch} comparator or using * {@link #setSort(boolean, Comparator)}. Passing a null <code>comparator</code> parameter will imply that you don't want the * comparator to change * * @param enabled Whether to enable sorting or not * @param comparator The Comparator to use, use null if already defined and you don't want to change it. */ public void setSort(boolean enabled, Comparator<GameObject> comparator) { if (!enabled) { sort = false; if(comparator != null) objectsComparator = comparator; return; } if(comparator == null && objectsComparator == null) throw new NullPointerException("Gamebatch.setsort parameter comparator of type Comparator<GameObject> is null, and you are trying to enable" + "the sorting without a predefined comparator"); sort = enabled; this.objectsComparator = comparator; } // endregion }