/******************************************************************************* * 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 sink.scene3d; import sink.core.Sink; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.InputAdapter; import com.badlogic.gdx.graphics.Camera; import com.badlogic.gdx.graphics.PerspectiveCamera; import com.badlogic.gdx.graphics.g3d.Environment; import com.badlogic.gdx.graphics.g3d.ModelBatch; import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute; import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight; import com.badlogic.gdx.scenes.scene2d.EventListener; import com.badlogic.gdx.scenes.scene2d.Group; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Disposable; public class Stage3d extends InputAdapter implements Disposable{ private float viewportX, viewportY, viewportWidth, viewportHeight; private float width, height; private float gutterWidth, gutterHeight; private final ModelBatch modelBatch; private final Environment environment; private PerspectiveCamera camera; private final Group3d root; private Actor3d scrollFocus; private Actor3d keyboardFocus; /** Creates a stage with a {@link #setViewport(float, float, boolean) viewport} equal to the device screen resolution. The stage * will use its own {@link SpriteBatch}. */ public Stage3d () { this(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false); } /** Creates a stage with the specified {@link #setViewport(float, float, boolean) viewport} that doesn't keep the aspect ratio. * The stage will use its own {@link SpriteBatch}, which will be disposed when the stage is disposed. */ public Stage3d (float width, float height) { this(width, height, false); } /** Creates a stage with the specified {@link #setViewport(float, float, boolean) viewport}. The stage will use its own * {@link SpriteBatch}, which will be disposed when the stage is disposed. */ public Stage3d (float width, float height, boolean keepAspectRatio) { this.width = width; this.height = height; root = new Group3d(); root.setStage3d(this); modelBatch = new ModelBatch(); camera = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); camera.position.set(10f, 10f, 10f); camera.lookAt(0,0,0); camera.near = 0.1f; camera.far = 300f; camera.update(); environment = new Environment(); environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f)); environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f)); setViewport(width, height, keepAspectRatio); } /** Sets up the stage size using a viewport that fills the entire screen without keeping the aspect ratio. * @see #setViewport(float, float, boolean, float, float, float, float) */ public void setViewport (float width, float height) { setViewport(width, height, false, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); } /** Sets up the stage size using a viewport that fills the entire screen. * @see #setViewport(float, float, boolean, float, float, float, float) */ public void setViewport (float width, float height, boolean keepAspectRatio) { setViewport(width, height, keepAspectRatio, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); } /** Sets up the stage size and viewport. The viewport is the glViewport position and size, which is the portion of the screen * used by the stage. The stage size determines the units used within the stage, depending on keepAspectRatio: * <p> * If keepAspectRatio is false, the stage is stretched to fill the viewport, which may distort the aspect ratio. * <p> * If keepAspectRatio is true, the stage is first scaled to fit the viewport in the longest dimension. Next the shorter * dimension is lengthened to fill the viewport, which keeps the aspect ratio from changing. The {@link #getGutterWidth()} and * {@link #getGutterHeight()} provide access to the amount that was lengthened. * @param viewportX The top left corner of the viewport in glViewport coordinates (the origin is bottom left). * @param viewportY The top left corner of the viewport in glViewport coordinates (the origin is bottom left). * @param viewportWidth The width of the viewport in pixels. * @param viewportHeight The height of the viewport in pixels. */ public void setViewport (float stageWidth, float stageHeight, boolean keepAspectRatio, float viewportX, float viewportY, float viewportWidth, float viewportHeight) { this.viewportX = viewportX; this.viewportY = viewportY; this.viewportWidth = viewportWidth; this.viewportHeight = viewportHeight; if (keepAspectRatio) { if (viewportHeight / viewportWidth < stageHeight / stageWidth) { float toViewportSpace = viewportHeight / stageHeight; float toStageSpace = stageHeight / viewportHeight; float deviceWidth = stageWidth * toViewportSpace; float lengthen = (viewportWidth - deviceWidth) * toStageSpace; this.width = stageWidth + lengthen; this.height = stageHeight; gutterWidth = lengthen / 2; gutterHeight = 0; } else { float toViewportSpace = viewportWidth / stageWidth; float toStageSpace = stageWidth / viewportWidth; float deviceHeight = stageHeight * toViewportSpace; float lengthen = (viewportHeight - deviceHeight) * toStageSpace; this.height = stageHeight + lengthen; this.width = stageWidth; gutterWidth = 0; gutterHeight = lengthen / 2; } } else { this.width = stageWidth; this.height = stageHeight; gutterWidth = 0; gutterHeight = 0; } camera.viewportWidth = this.width; camera.viewportHeight = this.height; } public void draw(){ camera.update(); if (!root.isVisible()) return; modelBatch.begin(camera); root.drawChildren(modelBatch, environment); modelBatch.end(); } /** Calls {@link #act(float)} with {@link Graphics#getDeltaTime()}. */ public void act () { act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f)); } /** Calls the {@link Actor#act(float)} method on each actor in the stage. Typically called each frame. This method also fires * enter and exit events. * @param delta Time in seconds since the last frame. */ public void act(float delta) { root.act(delta); } /** Adds an actor to the root of the stage. * @see Group#addActor(Actor) * @see Actor#remove() */ public void addActor3d(Actor3d actor) { root.addActor(actor); } /** Adds an action to the root of the stage. * @see Group#addAction3d(Action) */ public void addAction3d(Action3d action) { root.addAction3d(action); } /** Returns the root's child actors. * @see Group#getChildren() */ public Array<Actor3d> getActors3d() { return root.getChildren(); } /** Adds a listener to the root. * @see Actor#addListener(EventListener) */ public boolean addListener (EventListener listener) { return root.addListener(listener); } /** Removes a listener from the root. * @see Actor#removeListener(EventListener) */ public boolean removeListener (EventListener listener) { return root.removeListener(listener); } /** Removes the root's children, actions, and listeners. */ public void clear () { unfocusAll(); root.clear(); } /** Removes the touch, keyboard, and scroll focused actors. */ public void unfocusAll () { scrollFocus = null; keyboardFocus = null; //cancelTouchFocus(); } /** Removes the touch, keyboard, and scroll focus for the specified actor and any descendants. */ public void unfocus(Actor3d actor) { if (scrollFocus != null && scrollFocus.isDescendantOf(actor)) scrollFocus = null; if (keyboardFocus != null && keyboardFocus.isDescendantOf(actor)) keyboardFocus = null; } /** Sets the actor that will receive key events. * @param actor May be null. */ public void setKeyboardFocus (Actor3d actor) { if (keyboardFocus == actor) return; } /** Gets the actor that will receive key events. * @return May be null. */ public Actor3d getKeyboardFocus () { return keyboardFocus; } /** Sets the actor that will receive scroll events. * @param actor May be null. */ public void setScrollFocus(Actor3d actor) { if (scrollFocus == actor) return; } /** Gets the actor that will receive scroll events. * @return May be null. */ public Actor3d getScrollFocus () { return scrollFocus; } public ModelBatch getModelBatch () { return modelBatch; } public PerspectiveCamera getCamera () { return camera; } /** Sets the stage's camera. The camera must be configured properly or {@link #setViewport(float, float, boolean)} can be called * after the camera is set. {@link Sink#draw()} will call {@link Camera#update()} and use the {@link Camera#combined} matrix * for the SpriteBatch {@link SpriteBatch#setProjectionMatrix(com.badlogic.gdx.math.Matrix4) projection matrix}. */ public void setCamera (PerspectiveCamera camera) { this.camera = camera; } /** Returns the root group which holds all actors in the stage. */ public Group3d getRoot () { return root; } public Environment getEnvironment(){ return environment; } @Override public void dispose() { clear(); modelBatch.dispose(); } }