Android Open Source - gdx-vr Split Viewport






From Project

Back to project page gdx-vr.

License

The source code is released under:

Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUC...

If you think the Android project gdx-vr listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*******************************************************************************
 * Copyright 2011 See AUTHORS file.//from   ww  w  . ja  va 2s .c om
 * 
 * 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.vr;

import com.badlogic.gdx.graphics.Camera;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.math.collision.Ray;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.viewport.Viewport;

/**
 * This viewport can be used to split up the screen into different regions which
 * can be rendered each on their own. It actually consists of several other
 * viewports. It has one "root" viewport which is used to define the area that
 * can be used by the "sub" viewports. The "sub" viewports will split this area
 * into several areas. <br />
 * To render in a certain "sub" viewport, this viewport needs to be activated
 * first. This will result in a layouting of this viewport and its
 * {@link Viewport#update(int, int, boolean)} method being called to setup the
 * camera and the OpenGL viewport (glViewport) correctly.
 * 
 * @author Daniel Holderbaum
 */
public class SplitViewport extends Viewport {

  /** @author Daniel Holderbaum */
  public static class SizeInformation {
    /** Determines, how the size should be interpreted. */
    public SizeType sizeType;

    /**
     * The size to be used. Is ignored in case {@link SizeType} REST is
     * used.
     */
    public float size;

    public SizeInformation(SizeType sizeType, float size) {
      this.sizeType = sizeType;
      this.size = size;
    }
  }

  /**
   * An enum which determines how a size should be interpreted.
   * 
   * @author Daniel Holderbaum
   */
  public enum SizeType {
    /**
     * The size will be fixed and will have exactly the given size all the
     * time.
     */
    ABSOLUTE,

    /**
     * The given size needs to be in [0, 1]. It is relative to the "root"
     * viewport.
     */
    RELATIVE,

    /**
     * If this type is chosen, the given size will be ignored. Instead all
     * cells with this type will share the rest amount of the "root"
     * viewport that is still left after all other parts have been
     * subtracted.
     */
    REST
  }

  /**
   * A sub view for one cell of the {@link SplitViewport}.
   * 
   * @author Daniel Holderbaum
   */
  public static class SubView {
    /** The size information for this sub view. */
    public SizeInformation sizeInformation;

    /** The {@link Viewport} for this sub view. */
    public Viewport viewport;

    public SubView(SizeInformation sizeInformation, Viewport viewport) {
      this.sizeInformation = sizeInformation;
      this.viewport = viewport;
    }

  }

  private Viewport rootViewport;
  private Viewport activeViewport;

  private Array<SubView> rowSizeInformations = new Array<SubView>();
  private Array<Array<SubView>> subViews = new Array<Array<SubView>>();

  /**
   * Initializes the split viewport.
   * 
   * @param rootViewport
   *            The viewport to be used to determine the area which the sub
   *            viewports can use
   */
  public SplitViewport(Viewport rootViewport) {
    this.rootViewport = rootViewport;
  }

  /**
   * Adds another row to the split viewport. This has to be called at least
   * once prior to {@link #add(SubView)}.
   * 
   * @param sizeInformation
   *            The size information for the row.
   */
  public void row(SizeInformation sizeInformation) {
    if (sizeInformation.sizeType == SizeType.RELATIVE) {
      validateRelativeSize(sizeInformation.size);
    }

    // for rows we don't need a SubView with a viewport, but to not
    // duplicate some calculation methods, we just create a new
    // SubView
    rowSizeInformations.add(new SubView(sizeInformation, null));
    subViews.add(new Array<SubView>());
  }

  /**
   * Adds another sub view to the last added row.
   * 
   * @param subView
   *            The {@link SubView} with size and viewport. It can be changed
   *            externally. Those changes will be used as soon as the viewport
   *            is activated next time.
   */
  public void add(SubView subView) {
    if (subViews.size == 0) {
      throw new IllegalStateException("A row has to be added first.");
    }
    if (subView.sizeInformation.sizeType == SizeType.RELATIVE) {
      validateRelativeSize(subView.sizeInformation.size);
    }

    Array<SubView> rowViewports = subViews.peek();
    rowViewports.add(subView);
  }

  private final Rectangle subViewportArea = new Rectangle();

  /**
   * Updates the viewport at (row, column) and sets it as the currently active
   * one. The top left sub viewport is (0, 0).
   * 
   * @param row
   *            The index of the row with the viewport to be activated. Starts
   *            at 0.
   * @param column
   *            The index of the column with the viewport to be activated.
   *            Starts at 0.
   * @param centerCamera
   *            Whether the subView should center the camera or not.
   */
  public void activateSubViewport(int row, int column, boolean centerCamera) {
    validateCoordinates(row, column);

    Array<SubView> rowMap = subViews.get(row);
    Viewport viewport = rowMap.get(column).viewport;

    // update the viewport simulating a smaller sub view
    calculateSubViewportArea(row, column, subViewportArea);
    viewport.update((int) subViewportArea.width, (int) subViewportArea.height, centerCamera);

    // store the current world size so we can restore it in case it gets
    // changed now
    float originalWorldWidth = viewport.getWorldWidth();
    float originalWorldHeight = viewport.getWorldHeight();

    // some scaling strategies will scale the viewport bigger than the
    // allowed sub view, so we need to limit it
    if (viewport.getScreenWidth() > subViewportArea.width) {
      float offcutWidth = viewport.getScreenWidth() - subViewportArea.width;
      viewport.setScreenWidth((int) subViewportArea.width);
      viewport.setWorldWidth(viewport.getWorldWidth() - offcutWidth);
      viewport.setScreenX((int) (viewport.getScreenX() + offcutWidth / 2));
    }
    if (viewport.getScreenHeight() > subViewportArea.height) {
      float offcutHeight = viewport.getScreenHeight() - subViewportArea.height;
      viewport.setScreenHeight((int) subViewportArea.height);
      viewport.setWorldHeight(viewport.getWorldHeight() - offcutHeight);
      viewport.setScreenY((int) (viewport.getScreenY() + offcutHeight / 2));
    }

    // now shift it to the correct place
    viewport.setScreenX((int) (viewport.getScreenX() + subViewportArea.x));
    viewport.setScreenY((int) (viewport.getScreenY() + subViewportArea.y));

    // we changed the viewport parameters, now we need to update once more
    // to correct the glViewport
    viewport.apply();

    // restore the original world width after the glViewport has been set
    viewport.setWorldWidth(originalWorldWidth);
    viewport.setWorldHeight(originalWorldHeight);

    activeViewport = viewport;
  }

  public Viewport getRootViewport() {
    return rootViewport;
  }

  public void setRootViewport(Viewport rootViewport) {
    this.rootViewport = rootViewport;
  }

  // ############################################################
  // The following methods all just delegate to the root viewport
  // ############################################################

  @Override
  public void update(int screenWidth, int screenHeight, boolean centerCamera) {
    rootViewport.update(screenWidth, screenHeight, centerCamera);
  }

  @Override
  public Vector2 unproject(Vector2 screenCoords) {
    return rootViewport.unproject(screenCoords);
  }

  @Override
  public Vector2 project(Vector2 worldCoords) {
    return rootViewport.project(worldCoords);
  }

  @Override
  public Vector3 unproject(Vector3 screenCoords) {
    return rootViewport.unproject(screenCoords);
  }

  @Override
  public Vector3 project(Vector3 worldCoords) {
    return rootViewport.project(worldCoords);
  }

  @Override
  public Ray getPickRay(float screenX, float screenY) {
    return rootViewport.getPickRay(screenX, screenY);
  }

  @Override
  public void calculateScissors(Matrix4 batchTransform, Rectangle area, Rectangle scissor) {
    rootViewport.calculateScissors(batchTransform, area, scissor);
  }

  @Override
  public Vector2 toScreenCoordinates(Vector2 worldCoords, Matrix4 transformMatrix) {
    return rootViewport.toScreenCoordinates(worldCoords, transformMatrix);
  }

  @Override
  public Camera getCamera() {
    return rootViewport.getCamera();
  }

  @Override
  public void setCamera(Camera camera) {
    rootViewport.setCamera(camera);
  }

  @Override
  public void setWorldSize(float worldWidth, float worldHeight) {
    rootViewport.setWorldSize(worldWidth, worldHeight);
  }

  @Override
  public float getWorldWidth() {
    return rootViewport.getWorldWidth();
  }

  @Override
  public void setWorldWidth(float worldWidth) {
    rootViewport.setWorldWidth(worldWidth);
  }

  @Override
  public float getWorldHeight() {
    return rootViewport.getWorldHeight();
  }

  @Override
  public void setWorldHeight(float worldHeight) {
    rootViewport.setWorldHeight(worldHeight);
  }

  @Override
  public int getScreenX() {
    return rootViewport.getScreenX();
  }

  @Override
  public int getScreenY() {
    return rootViewport.getScreenY();
  }

  @Override
  public int getScreenWidth() {
    return rootViewport.getScreenWidth();
  }

  @Override
  public int getScreenHeight() {
    return rootViewport.getScreenHeight();
  }

  @Override
  public int getLeftGutterWidth() {
    return rootViewport.getLeftGutterWidth();
  }

  @Override
  public int getRightGutterX() {
    return rootViewport.getRightGutterX();
  }

  @Override
  public int getRightGutterWidth() {
    return rootViewport.getRightGutterWidth();
  }

  @Override
  public int getBottomGutterHeight() {
    return rootViewport.getBottomGutterHeight();
  }

  @Override
  public int getTopGutterY() {
    return rootViewport.getTopGutterY();
  }

  @Override
  public int getTopGutterHeight() {
    return rootViewport.getTopGutterHeight();
  }

  // #################################################################
  // Private utility methods to help with calculations and validations
  // #################################################################

  private Rectangle calculateSubViewportArea(int row, int col, Rectangle subViewportArea) {
    subViewportArea.x = calculateWidthOffset(subViews.get(row), col);
    subViewportArea.y = calculateHeightOffset(rowSizeInformations, row);
    subViewportArea.width = calculateSize(subViews.get(row), col, getScreenWidth());
    subViewportArea.height = calculateSize(rowSizeInformations, row, getScreenHeight());

    return subViewportArea;
  }

  private float calculateHeightOffset(Array<SubView> subViews, int index) {
    // the glViewport offset is y-up, but the first row is the top most one
    // that's why we start at the top and subtract the row heights
    float heightOffset = getScreenHeight();
    for (int i = 0; i <= index; i++) {
      heightOffset -= calculateSize(subViews, i, getScreenHeight());
    }

    // add the root offset
    heightOffset += getScreenY();

    return heightOffset;
  }

  private float calculateWidthOffset(Array<SubView> sizeInformations, int index) {
    float widthOffset = 0;
    for (int i = 0; i < index; i++) {
      widthOffset += calculateSize(sizeInformations, i, getScreenWidth());
    }

    // add the root offset
    widthOffset += getScreenX();

    return widthOffset;
  }

  /**
   * Used to calculate either the width or height.
   * 
   * @param subViews
   *            The row informations or column informations of a certain row.
   * @param index
   *            The index of the element to be calculated.
   * @param totalSize
   *            The total size, either the viewport width or height.
   */
  private float calculateSize(Array<SubView> subViews, int index, float totalSize) {
    SubView subView = subViews.get(index);
    switch (subView.sizeInformation.sizeType) {
    case ABSOLUTE:
      return subView.sizeInformation.size;
    case RELATIVE:
      return subView.sizeInformation.size * totalSize;
    case REST:
      int rests = countRest(subViews);
      float usedSize = calculateUsedSize(subViews, totalSize);
      return (totalSize - usedSize) / rests;
    default:
      throw new IllegalArgumentException(subView.sizeInformation.sizeType + " could not be handled.");
    }
  }

  private float calculateUsedSize(Array<SubView> subViews, float totalSize) {
    float usedSize = 0;

    for (SubView subView : subViews) {
      switch (subView.sizeInformation.sizeType) {
      case ABSOLUTE:
        usedSize += subView.sizeInformation.size;
        break;
      case RELATIVE:
        usedSize += subView.sizeInformation.size * totalSize;
        break;
      }
    }

    return usedSize;
  }

  private int countRest(Array<SubView> subViews) {
    int rests = 0;

    for (SubView subView : subViews) {
      if (subView.sizeInformation.sizeType == SizeType.REST) {
        rests++;
      }
    }

    return rests;
  }

  private void validateCoordinates(int row, int col) {
    if (row >= subViews.size) {
      throw new IllegalArgumentException("There is no row with ID " + row);
    }

    Array<SubView> rowSubViews = subViews.get(row);
    if (col >= rowSubViews.size) {
      throw new IllegalArgumentException("There is no column with ID " + col);
    }
  }

  private void validateRelativeSize(float size) {
    if (size < 0 || size > 1) {
      throw new IllegalArgumentException(size + " does not fulfill the constraint of 0 <= size <= 1.");
    }
  }
}




Java Source Code List

com.badlogic.gdx.vr.Body.java
com.badlogic.gdx.vr.CardboardDistortionRenderer.java
com.badlogic.gdx.vr.CardboardDistortion.java
com.badlogic.gdx.vr.CardboardHMD.java
com.badlogic.gdx.vr.CardboardImplementation.java
com.badlogic.gdx.vr.CardboardMetaInformation.java
com.badlogic.gdx.vr.CardboardOpticsInformation.java
com.badlogic.gdx.vr.CardboardScreenInformation.java
com.badlogic.gdx.vr.DeviceMetaInformation.java
com.badlogic.gdx.vr.DeviceOpticsInformation.java
com.badlogic.gdx.vr.DeviceScreenInformation.java
com.badlogic.gdx.vr.DistortionRenderer.java
com.badlogic.gdx.vr.Distortion.java
com.badlogic.gdx.vr.HeadMountedDisplay.java
com.badlogic.gdx.vr.Head.java
com.badlogic.gdx.vr.MeshBuilder.java
com.badlogic.gdx.vr.OculusDistortionRenderer.java
com.badlogic.gdx.vr.OculusHMD.java
com.badlogic.gdx.vr.OculusImplementation.java
com.badlogic.gdx.vr.OculusMetaInformation.java
com.badlogic.gdx.vr.OculusOpticsInformation.java
com.badlogic.gdx.vr.OculusScreenInformation.java
com.badlogic.gdx.vr.SoftwareAntiDistortionRenderer.java
com.badlogic.gdx.vr.SplitViewport.java
com.badlogic.gdx.vr.Stage3D.java
com.badlogic.gdx.vr.TypeTransformer.java
com.badlogic.gdx.vr.TypeTransformer.java
com.badlogic.gdx.vr.VirtualRealityDeviceListener.java
com.badlogic.gdx.vr.VirtualRealityImplementation.java
com.badlogic.gdx.vr.VirtualRealityRenderListener.java
com.badlogic.gdx.vr.VirtualRealityRenderer.java
com.badlogic.gdx.vr.VirtualReality.java
com.badlogic.gdx.vr.simpleroom.IOSLauncher.java
com.badlogic.gdx.vr.simpleroom.SimpleRoom.java
com.badlogic.gdx.vr.simpleroom.android.AndroidLauncher.java
com.badlogic.gdx.vr.simpleroom.desktop.DesktopLauncher.java