/******************************************************************************* * Copyright 2011 See AUTHORS file. * * 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.badlogic.gdx.tests; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.ui.Image; import com.badlogic.gdx.scenes.scene2d.utils.Cullable; import com.badlogic.gdx.tests.utils.GdxTest; import com.badlogic.gdx.tests.utils.OrthoCamController; import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Scaling; /** This is a simple demonstration of how to perform VERY basic culling on hierarchies of stage actors that do not scale or rotate. * It is not a general solution as it assumes that actors and groups are only translated (moved, change their x/y coordinates). * NOTE: This has been obsoleted by {@link Cullable}. * * @author mzechner */ public class SimpleStageCullingTest extends GdxTest { /** We need to extend a base actor class so we can add the culling in the render method. We also add a method to get the stage * coordinates of the actor so we can cull it against the camera's view volume. * * @author mzechner */ private class CullableActor extends Image { /** the camera to test against **/ final OrthographicCamera camera; /** whether we are visible or not, used for counting visible actors **/ boolean visible = false; public CullableActor (String name, Texture texture, OrthographicCamera camera) { super(new TextureRegion(texture)); setAlign(Align.center); setScaling(Scaling.none); this.camera = camera; } public void draw (Batch batch, float parentAlpha) { // if this actor is not within the view of the camera we don't draw it. if (isCulled()) return; // otherwise we draw via the super class method super.draw(batch, parentAlpha); } /** static helper Rectangles **/ Rectangle actorRect = new Rectangle(); Rectangle camRect = new Rectangle(); private boolean isCulled () { // we start by setting the stage coordinates to this // actors coordinates which are relative to its parent // Group. float stageX = getX(); float stageY = getY(); // now we go up the hierarchy and add all the parents' // coordinates to this actors coordinates. Note that // this assumes that neither this actor nor any of its // parents are rotated or scaled! Actor parent = this.getParent(); while (parent != null) { stageX += parent.getX(); stageY += parent.getY(); parent = parent.getParent(); } // now we check if the rectangle of this actor in screen // coordinates is in the rectangle spanned by the camera's // view. This assumes that the camera has no zoom and is // not rotated! actorRect.set(stageX, stageY, getWidth(), getHeight()); camRect.set(camera.position.x - camera.viewportWidth / 2.0f, camera.position.y - camera.viewportHeight / 2.0f, camera.viewportWidth, camera.viewportHeight); visible = camRect.overlaps(actorRect); return !visible; } } OrthoCamController camController; Stage stage; Texture texture; SpriteBatch batch; BitmapFont font; @Override public void create () { // create a stage and a camera controller so we can pan the view. stage = new Stage();; camController = new OrthoCamController((OrthographicCamera)stage.getCamera()); // we know it's an ortho cam at this point! Gdx.input.setInputProcessor(camController); // load a dummy texture texture = new Texture(Gdx.files.internal("data/badlogicsmall.jpg")); // populate the stage with some actors and groups. for (int i = 0; i < 5000; i++) { Actor img = new CullableActor("img" + i, texture, (OrthographicCamera)stage.getCamera()); img.setX((float)Math.random() * 480 * 10); img.setY((float)Math.random() * 320 * 10); stage.addActor(img); } // we also want to output the number of visible actors, so we need a SpriteBatch and a BitmapFont batch = new SpriteBatch(); font = new BitmapFont(Gdx.files.internal("data/arial-15.fnt"), false); } public void render () { Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); stage.draw(); // check how many actors are visible. Array<Actor> actors = stage.getActors(); int numVisible = 0; for (int i = 0; i < actors.size; i++) { numVisible += ((CullableActor)actors.get(i)).visible ? 1 : 0; } batch.begin(); font.draw(batch, "Visible: " + numVisible + ", fps: " + Gdx.graphics.getFramesPerSecond(), 20, 30); batch.end(); } @Override public void dispose () { stage.dispose(); texture.dispose(); batch.dispose(); font.dispose(); } }