DrawableObject.java :  » Game » rokon » com » stickycoding » rokon » Android Open Source

Android Open Source » Game » rokon 
rokon » com » stickycoding » rokon » DrawableObject.java
package com.stickycoding.rokon;

import javax.microedition.khronos.opengles.GL10;

import com.stickycoding.rokon.device.Graphics;

/**
 * @author Richard
 *
 */
public class DrawableObject extends BasicGameObject implements Drawable, Updateable {

  protected boolean killNextUpdate = false;
  
  protected int z = 0;
  protected BlendFunction blendFunction;
  protected int forceDrawType = DrawPriority.DEFAULT;
  protected float red = 1, green = 1, blue = 1, alpha = 1;
  protected BufferObject buffer;
  protected Texture texture;
  protected int textureTile = 0;
  
  protected boolean invisible;
  
  protected boolean isFading;
  protected int fadeTime, fadeType;
  protected long fadeStartTime;
  protected float fadeTo, fadeStart;
  protected boolean fadeUp;
  
  protected boolean animated, hasCustomAnimation, animationReturnToStart;
  protected int animationStartTile, animationEndTile, animationLoops, animationCustomPosition;
  protected int[] customAnimationSequence;
  private long animationFrameTicks, animationLastTicks;
  
  protected float lineWidth = -1;
  protected boolean fill = true;
  protected float borderRed = 0, borderGreen = 0, borderBlue = 0, borderAlpha = 1;
  
  protected boolean border;
  
  protected boolean freezeAnimation;
  
  
  protected ColourBuffer colourBuffer;
  
  /**
   * Removes the border
   */
  public void noBorder() {
    fill = false;
  }
  
  /**
   * Determines whether the DrawableObject is fading through fade()
   * 
   * @return TRUE if fading, FALSE otherwise
   */
  public boolean isFading() {
    return isFading;
  }
  
  /**
   * Determines whether this DrawableObject is using VBOs
   * 
   * @return TRUE if using VBO, FALSE otherwise
   */
  public boolean isVBO() {
    return forceDrawType == DrawPriority.VBO || DrawPriority.drawPriority == DrawPriority.PRIORITY_VBO;
  }
  
  /**
   * Draws a border around the object
   * This only applied to untextured objects
   * 
   * @param red
   * @param green
   * @param blue
   * @param alpha
   */
  public void setBorder(float red, float green, float blue, float alpha) {
    border = true;
    borderRed = red;
    borderGreen = green;
    borderBlue = blue;
    borderAlpha = alpha;
  }
  
  /**
   * Sets the line width for this object, if not set the default line width set in Scene will be used
   *  
   * @param lineWidth float
   */
  public void setLineWidth(float lineWidth) {
    this.lineWidth = lineWidth;
  }
  
  /**
   * Fetches the line width for this object, if a custom line width is being used
   * 
   * @return custom line width, -1 if not set
   */
  public float getLineWidth() {
    return lineWidth;
  }
  
  /**
   * Removes the custom line width for this object, and goes back to using the default
   */
  public void useDefaultLineWidth() {
    lineWidth = -1;
  }
  
  /**
   * Sets whether or not to show a border
   * 
   * @param border TRUE if border in use, FALSE otherwise
   */
  public void setBorder(boolean border) {
    this.border = border;
  }
  
  /**
   * Prevents this DrawableObject from being rendered 
   */
  public void hide() {
    invisible = true;
  }
  
  /**
   * Shows this DrawableObject, only needs to be called after hide()
   */
  public void show() {
    invisible = false;
  }
  
  /**
   * Determines whether ot not the DrawableObject has been told to hide
   * 
   * @return TRUE if visible, FALSE if hide() has been called 
   */
  public boolean isVisible() {
    return !invisible;
  }
  
  /**
   * Fades this DrawableObject to a given alpha value over time
   * 
   * @param alpha target alpha value, between 0f and 1f
   * @param time the time (in milliseconds) to take while fading
   * @param movementType valid movement type, see constants in Movement
   */
  public void fade(float alpha, int time, int movementType) {
    fade(this.alpha, alpha, time, movementType);
  }
  
  /**
   * Fades this DrawableObject to a given alpha value over time, using a linear movement type
   * 
   * @param alpha target alpha value, between 0f and 1f
   * @param time the time (in milliseconds) to take while fading
   */
  public void fade(float alpha, int time) {
    fade(this.alpha, alpha, time, Movement.LINEAR);
  }
  
  /**
   * Fades this DrawableObject to a given alpha value over time, starting at a specific alpha
   * 
   * @param startAlpha start alpha value, between 0f and 1f
   * @param alpha target alpha value, between 0f and 1f
   * @param time the time (in milliseconds) to take while fading
   * @param movementType valid movement type, see constants in Movement
   */
  public void fade(float startAlpha, float alpha, int time, int movementType) {
    if(alpha == startAlpha) return;
    this.alpha = startAlpha;
    fadeType = movementType; 
    isFading = true;
    fadeTime = time;
    fadeStartTime = Time.loopTicks;
    fadeTo = alpha;
    fadeStart = this.alpha;
    fadeUp = alpha > startAlpha;
    
  }
  
  protected void updateFadeTo() {
    if(!isFading) return;
    float position = (float)(Time.loopTicks - fadeStartTime) / (float)fadeTime;
    float factor = Movement.getPosition(position, fadeType);
    if(position >= 1) {
      this.alpha = fadeTo;
      isFading = false;
      parentScene.onFadeEnd(this);
      return;
    }
    if(fadeUp) {
      setAlpha(fadeStart + ((fadeTo - fadeStart) * factor));
    } else {
      setAlpha(fadeStart - ((fadeStart - fadeTo) * factor));
    }
  }
  
  public DrawableObject(float x, float y, float width, float height) {
    super(x, y, width, height);
    doBuffer();
  }
  
  public DrawableObject(float x, float y, float width, float height, Texture texture) {
    super(x, y, width, height);
    setTexture(texture);
    doBuffer();
  }
  
  protected void doBuffer() {
    if(isVBO()) {
      
    } else {
      buffer = Rokon.triangleStripBoxBuffer;
    }
  }
  
  /**
   * Uses a Texture rather than a blank square
   * 
   * @param texture valid Texture object
   */
  public void setTexture(Texture texture) {
    this.texture = texture;
  }
  
  /**
   * Uses a Texture rather than a blank square
   * 
   * @param texture valid Texture object
   * @param tile the tile index to use
   */
  public void setTextureTile(Texture texture, int tileIndex) {
    setTexture(texture);
    textureTile = tileIndex;
  }
  
  /**
   * Sets a specific BlendFunction to be applied to this DrawableObject
   * If no BlendFunction is passed, the default will be used
   * 
   * @param blendFunction a valid BlendFunction
   */
  public void setBlendFunction(BlendFunction blendFunction) {
    this.blendFunction = blendFunction;
  }
  
  /**
   * Returns the specific BlendFunction associated with this DrawableObject
   * 
   * @return NULL if no specific BlendFunction has been given
   */
  public BlendFunction getBlendFunction() {
    return blendFunction;
  }

  /**
   * Forces this DrawableObject to use a specific DrawType
   * 
   * @param drawType valid draw type, see constants in DrawPriority
   */
  public void forceDrawType(int drawType) {
    if(drawType == DrawPriority.VBO) {
      if(!Graphics.isSupportsVBO()) {
        Debug.warning("Tried forcing DrawableObject to VBO, device does not support it");
        drawType = DrawPriority.NORMAL;
      }
    }
    forceDrawType = drawType;
  }
  
  /**
   * Sets the red value
   * 
   * @param red floating point, 0 to 1f
   */
  public void setRed(float red) {
    this.red = red;
  }
  
  /**
   * @return current red value
   */
  public float getRed() {
    return red;
  }
  
  /**
   * Sets the green value
   * 
   * @param green float, 0 to 1
   */
  public void setGreen(float green) {
    this.green = green;
  }
  
  /**
   * @return current green value
   */
  public float getGreen() {
    return green;
  }
  
  /**
   * Sets the blue value
   * 
   * @param blue float, 0 to 1
   */
  public void setBlue(float blue) {
    this.blue = blue;
  }
  
  /**
   * @return blue value
   */
  public float getBlue() {
    return blue;
  }
  
  /**
   * Sets the alpha value
   * 
   * @param alpha float, 0 to 1
   */
  public void setAlpha(float alpha) {
    this.alpha = alpha;
  }
  
  /**
   * @return alpha value
   */
  public float getAlpha() {
    return alpha;
  }
  
  /**
   * Sets the red, green and blue values
   * 
   * @param red float, 0 to 1f
   * @param green float, 0 to 1f
   * @param blue float, 0 to 1f
   */
  public void setRGB(float red, float green, float blue) {
    this.red = red;
    this.green = green;
    this.blue = blue;
  }
  
  /**
   * Sets the red, green, blue and alpha values
   * 
   * @param red float, 0 to 1f
   * @param green float, 0 to 1f
   * @param blue float, 0 to 1f
   * @param alpha float, 0 to 1f
   */
  public void setRGBA(float red, float green, float blue, float alpha) {
    this.red = red;
    this.green = green;
    this.blue = blue;
    this.alpha = alpha;
  }
  
  public void onDraw(GL10 gl) {
    if(invisible) return;
    switch(forceDrawType) {
      case DrawPriority.DEFAULT:
        switch(DrawPriority.drawPriority) {
          case DrawPriority.PRIORITY_VBO:
            if(Graphics.isSupportsVBO()) {
              onDrawVBO(gl);
              return;
            }
            onDrawNormal(gl);
            return;
          case DrawPriority.PRIORITY_NORMAL:
            onDrawNormal(gl);
            return;
          default:
            Debug.warning("DrawableObject.onDraw", "Invalid draw priority on DrawableObject");
            return;
        }
      case DrawPriority.NORMAL:
        onDrawNormal(gl);
        return;
      case DrawPriority.VBO:
        onDrawVBO(gl);
        return;
      default:
        Debug.warning("DrawableObject.onDraw", "Invalid forced draw priority");
        return;
    }
  }
  
  protected void onDrawNormal(GL10 gl) {
    GLHelper.drawNormal(fill, red, green, blue, alpha, blendFunction, buffer, GL10.GL_TRIANGLE_STRIP, getX(), getY(), width, height, rotation, rotateAboutPoint, rotationPivotX, rotationPivotY, border, Rokon.lineLoopBoxBuffer, borderRed, borderGreen, borderBlue, borderAlpha, lineWidth, texture != null, texture, textureTile, colourBuffer);
  }
  
  protected void onDrawVBO(GL10 gl) {
    GLHelper.drawVBO(fill, red, green, blue, alpha, blendFunction, Rokon.arrayVBO, GL10.GL_TRIANGLE_STRIP, getX(), getY(), width, height, rotation, rotateAboutPoint, rotationPivotX, rotationPivotY, border, Rokon.boxArrayVBO, borderRed, borderGreen, borderBlue, borderAlpha, lineWidth, texture != null, texture, textureTile, colourBuffer);
  }
  
  private boolean isOnScreen = false;
  private long lastOnScreen = 0;
  
  /**
   * Determines whether this object is actually visible on screen
   * 
   * @return TRUE if on screen, FALSE otherwise
   */
  public boolean isOnScreen() {
    if(Time.drawTicks <= lastOnScreen) return isOnScreen;
    lastOnScreen = Time.drawTicks;
    if(invisible) {
      isOnScreen = false;
      return false;
    }
    float maxSize = width > height ? width : height;
    if(parentLayer == null || parentScene == null) {
      isOnScreen = false;
      return false;
    }
    if(parentLayer.ignoreWindow || parentScene.window == null) {
      if (getX() - (maxSize / 2) < RokonActivity.gameWidth && getX() + maxSize + (maxSize / 2) > 0 && getY() - (maxSize / 2) < RokonActivity.gameHeight && getY() + maxSize + (maxSize / 2) > 0) {
        isOnScreen = true;
      }
    } else {
      boolean validY = false;
      boolean validX = false;
      if(parentScene.window.height < 0) {
        if(getY() - (maxSize / 2) < parentScene.window.getY() && getY() + maxSize + (maxSize / 2) > parentScene.window.height + parentScene.window.getY()) {
          validY = true;
        }
      } else {
        if(getY() - (maxSize / 2) < parentScene.window.height + parentScene.window.getY() && getY() + maxSize + (maxSize / 2) > parentScene.window.getY()) {
          validY = true;
        }
      }
      if(parentScene.window.width < 0) {
        if(getX() - (maxSize / 2) < parentScene.window.getX() && getX() + maxSize + (maxSize / 2) > parentScene.window.width + parentScene.window.getX()) {
          validX = true;
        }
      } else {
        if(getX() - (maxSize / 2) < parentScene.window.getX() + parentScene.window.width && getX() + maxSize + (maxSize / 2) > parentScene.window.getX()) {
          validX = true;
        }
      }
      isOnScreen = validX && validY;
    }
    return isOnScreen;
  }
  
  /**
   * Sets the tile inside the Texture that this DrawableObject should use
   * 
   * @param tileIndex integer, starting at 0
   */
  public void setTextureTile(int tileIndex) {
    textureTile = tileIndex;
  }
  
  /**
   * Sets the tile inside the Texture that this DrawableObject should use
   * based on columsn and rows, not the index
   * 
   * @param column integer, starting at 0
   * @param row integer, starting at 0
   */
  public void setTextureTile(int column, int row) {
    textureTile = (row * texture.columns) + column;
  }
  
  /**
   * Returns the current tile which the Texture is using
   * 
   * @return 0 as default
   */
  public int getTextureTile() {
    return textureTile;
  }
  
  /**
   * Returns the current Texture
   * 
   * @return NULL if not set
   */
  public Texture getTexture() {
    return texture;
  }
  
  /**
   * Returns the current row of the Texture which this DrawableObject is using
   * 
   * @return positive integer
   */
  public int getTextureTileRow() {
    float col = textureTile % texture.columns;
    return (int)((textureTile - col) / texture.columns);
  }
  
  /**
   * Returns the current row of the Texture which this DrawableObject is using
   * 
   * @return positive integer
   */
  public int getTextureTileColumn() {
    return textureTile % texture.columns;
  }

  /* (non-Javadoc)
   * @see com.stickycoding.rokon.RotationalObject#onUpdate()
   */
  public void onUpdate() {
    super.onUpdate();
    updateFadeTo();
    updateAnimation();
  }

  /* (non-Javadoc)
   * @see com.stickycoding.rokon.Drawable#onAdd(com.stickycoding.rokon.Layer)
   */
  public void onAdd(Layer layer) {
    parentLayer = layer;
        killNextUpdate = false;
  }

  /* (non-Javadoc)
   * @see com.stickycoding.rokon.Drawable#onRemove()
   */
  public void onRemove() { }

  /**
   * Removes this DrawableObject from the Scene
   */
  public void remove() {
    killNextUpdate = true;
    parentLayer = null;
  }
  
  /* (non-Javadoc)
   * @see com.stickycoding.rokon.Drawable#isAlive()
   */
  public boolean isAlive() {
    if(killNextUpdate) {
      onRemove();
      return false;
    } else {
      return true;
    }
  }
  
  /**
   * Animates the Textures tile index, between minimum and maximum
   * 
   * @param startTile first tile index to animate from
   * @param endTile the final tile index
   * @param frameTime length of time to show one frame (in ms)
   * @param loops number of animation loops before stopping
   * @param returnToStart TRUE if the animation should return to the start after finished
   */
  public void animate(int startTile, int endTile, long frameTime, int loops, boolean returnToStart) {
    animationStartTile = startTile;
    animationEndTile = endTile;
    animationFrameTicks = frameTime;
    animationLoops = loops;
    animationLastTicks = Time.loopTicks;
    textureTile = startTile;
    hasCustomAnimation = false;
    animationReturnToStart = returnToStart;
    animated = true;
    freezeAnimation = false;
  }
  
  /**
   * Animates the Textures tile index, beween minimum and maximum
   * 
   * @param startTile first tile index to animate from
   * @param endTile the final tile index
   * @param frameTime length of time to show one frame (in ms)
   */
  public void animate(int startTile, int endTile, long frameTime) {
    animate(startTile, endTile, frameTime, -1, false);
  }
  
  /**
   * Animates the Texture tile index, through a custom array
   * 
   * @param animationTiles int array of texture tile indices
   * @param frameTime length of time to show one frame (in ms)
   * @param loops number of animation loops before stopping
   * @param returnToStart TRUE if the animation should return to the start after finished
   */
  public void animate(int[] animationTiles, long frameTime, int loops, boolean returnToStart) {
    hasCustomAnimation = true;
    textureTile = animationTiles[0];
    animationReturnToStart = returnToStart;
    animationLoops = loops;
    animationLastTicks = Time.loopTicks;
    animationFrameTicks = frameTime;
    customAnimationSequence = animationTiles;
    animationCustomPosition = -1;
    animated = true;
    freezeAnimation = false;
  }
  
  public boolean isAnimation() {
    return animated;
  }
  
  public boolean isFreezeAnimation() {
    return freezeAnimation;
  }
  
  /**
   * Animates the Texture tile index, through a custom array
   * 
   * @param animationTiles int array of texture tile indices
   * @param frameTime length of time to show one frame (in ms)
   */  
  public void animate(int[] animationTiles, long frameTime) {
    animate(animationTiles, frameTime, -1, false);
  }
  
  protected void updateAnimation() {
    if(!animated || freezeAnimation) return;
    long tickDifference = Time.loopTicks - animationLastTicks - animationFrameTicks;
    if(tickDifference > 0) {
      int frameSkip = 0;
      while(tickDifference > 0) {
        tickDifference -= animationFrameTicks;
        frameSkip++;
      }
      if(hasCustomAnimation) {
        while(frameSkip > 0) {
          animationCustomPosition++;
          if(animationCustomPosition >= customAnimationSequence.length) {
            animationCustomPosition = 0;
            if(animationLoops > 0) {
              animationLoops--;
              if(animationLoops == 0) {
                if(animationReturnToStart) {
                  textureTile = animationStartTile;
                  animated = false;
                  parentScene.onAnimationEnd(this);
                } else {
                  animationCustomPosition--;
                  animated = false;
                  parentScene.onAnimationEnd(this);
                  break;
                }
              }
            }
          }
          textureTile = customAnimationSequence[animationCustomPosition];
          frameSkip--;
        }
      } else {
        while(frameSkip > 0) {
          textureTile++;
          if(textureTile > animationEndTile) {
            if(animationLoops > 0) {
              animationLoops--;
              if(animationLoops == 0) {
                if(animationReturnToStart) {
                  textureTile = animationStartTile;
                  animated = false;
                  parentScene.onAnimationEnd(this);
                } else {
                  textureTile--;
                  animated = false;
                  parentScene.onAnimationEnd(this);
                  break;
                }
              }
            }
            textureTile = animationStartTile;
          }
          frameSkip--;
        }
      }
      animationLastTicks -= tickDifference;
    }
  }

  /* (non-Javadoc)
   * @see com.stickycoding.rokon.Drawable#isTouchable()
   */
  public boolean isTouchable() {
    return false;
  }

  public void onTouchDown(float x, float y, int action, int pointerCount, int pointerId) { }

  public void onTouchUp(float x, float y, int action, int pointerCount, int pointerId) { }

  public void onTouch(float x, float y, int action, int pointerCount, int pointerId) { }

  public void onTouchMove(float x, float y, int action, int pointerCount, int pointerId) { }
  
  /**
   * Returns the current Layer to which this DrawableObject is included
   * 
   * @return NULL if not set
   */
  public Layer getParentLayer() {
    return parentLayer;
  }

  /* (non-Javadoc)
   * @see com.stickycoding.rokon.Drawable#getZ()
   */
  public int getZ() {
    return z;
  }
  
  /**
   * Sets the (relative) Z position of this object. It will only take affect if setDrawOrder is DrawOrder.Z_ORDER
   * 
   * @param z integer
   */
  public void setZ(int z) {
    this.z = z;
  }
  
  /**
   * Stops any fading animation
   */
  public void stopFade() {
    isFading = false;
  }
  
  /**
   * Stops any animation
   */
  public void stopAnimation() {
    animated = false;
  }
  
  /**
   * Stops any animation, and jumps to a given tile
   * 
   * @param index tile index
   */
  public void stopAnimation(int index) {
    animated = false;
    setTextureTile(index);
  }
  
  /**
   * Sets a ColourBuffer object to this DrawableObject
   * 
   * @param colourBuffer valid ColourBuffer
   */
  public void setColourBuffer(ColourBuffer colourBuffer) {
    this.colourBuffer = colourBuffer;
  }
  
  /**
   * Returns the current ColourBuffer object
   * 
   * @return NULL if not set, ColourBuffer otherwise
   */
  public ColourBuffer getColourBuffer() {
    return colourBuffer;
  }
  
  /**
   * Determines whether the ColourBuffer is being used
   * 
   * @return TRUE if ColourBuffer is being used, FALSE otherwise
   */
  public boolean hasColourBuffer() {
    return colourBuffer != null;
  }
  
  /**
   * Removes the ColourBuffer object from this DrawableObject
   */
  public void removeColourBuffer() {
    colourBuffer = null;
  }
  
  public void freezeAnimation() {
    freezeAnimation = true;
  }
  
  public void unfreezeAnimation() {
    freezeAnimation = false;
  }
  
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.