Package box2dLight

Source Code of box2dLight.PositionalLight

package box2dLight;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.Mesh.VertexDataType;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;

public abstract class PositionalLight extends Light {

  private Body body;
  private float bodyOffsetX;
  private float bodyOffsetY;
  final float sin[];
  final float cos[];

  final Vector2 start = new Vector2();
  final float endX[];
  final float endY[];

  /** attach positional light to automatically follow body. Position is fixed to given offset. */
  @Override
  public void attachToBody (Body body, float offsetX, float offSetY) {
    this.body = body;
    bodyOffsetX = offsetX;
    bodyOffsetY = offSetY;
    if (staticLight) staticUpdate();
  }

  @Override
  public Vector2 getPosition () {
    tmpPosition.x = start.x;
    tmpPosition.y = start.y;
    return tmpPosition;
  }

  public Body getBody () {
    return body;
  }

  /** horizontal starting position of light in world coordinates. */
  @Override
  public float getX () {
    return start.x;
  }

  /** vertical starting position of light in world coordinates. */
  @Override
  public float getY () {
    return start.y;
  }

  private final Vector2 tmpEnd = new Vector2();

  @Override
  public void setPosition (float x, float y) {
    start.x = x;
    start.y = y;
    if (staticLight) staticUpdate();
  }

  @Override
  public void setPosition (Vector2 position) {
    start.x = position.x;
    start.y = position.y;
    if (staticLight) staticUpdate();
  }

  @Override
  void update () {
    if (body != null && !staticLight) {
      final Vector2 vec = body.getPosition();
      float angle = body.getAngle();
      final float cos = MathUtils.cos(angle);
      final float sin = MathUtils.sin(angle);
      final float dX = bodyOffsetX * cos - bodyOffsetY * sin;
      final float dY = bodyOffsetX * sin + bodyOffsetY * cos;
      start.x = vec.x + dX;
      start.y = vec.y + dY;
      setDirection(angle * MathUtils.radiansToDegrees);
    }

    if (rayHandler.culling) {
      culled = ((!rayHandler.intersect(start.x, start.y, distance + softShadowLenght)));
      if (culled) return;
    }

    if (staticLight) return;

    for (int i = 0; i < rayNum; i++) {
      m_index = i;
      f[i] = 1f;
      tmpEnd.x = endX[i] + start.x;
      mx[i] = tmpEnd.x;
      tmpEnd.y = endY[i] + start.y;
      my[i] = tmpEnd.y;
      if (rayHandler.world != null && !xray) {
        rayHandler.world.rayCast(ray, start, tmpEnd);
      }
    }
    setMesh();
  }

  void setMesh () {
    // ray starting point
    int size = 0;

    segments[size++] = start.x;
    segments[size++] = start.y;
    segments[size++] = colorF;
    segments[size++] = 1;
    // rays ending points.
    for (int i = 0; i < rayNum; i++) {
      segments[size++] = mx[i];
      segments[size++] = my[i];
      segments[size++] = colorF;
      segments[size++] = 1 - f[i];
    }
    lightMesh.setVertices(segments, 0, size);

    if (!soft || xray) return;

    size = 0;
    // rays ending points.

    for (int i = 0; i < rayNum; i++) {
      segments[size++] = mx[i];
      segments[size++] = my[i];
      segments[size++] = colorF;
      final float s = (1 - f[i]);
      segments[size++] = s;
      segments[size++] = mx[i] + s * softShadowLenght * cos[i];
      segments[size++] = my[i] + s * softShadowLenght * sin[i];
      segments[size++] = zero;
      segments[size++] = 0f;
    }
    softShadowMesh.setVertices(segments, 0, size);
  }

  @Override
  void render () {
    if (rayHandler.culling && culled) return;

    rayHandler.lightRenderedLastFrame++;
    lightMesh.render(rayHandler.lightShader, GL20.GL_TRIANGLE_FAN, 0, vertexNum);
    if (soft && !xray) {
      softShadowMesh.render(rayHandler.lightShader, GL20.GL_TRIANGLE_STRIP, 0, (vertexNum - 1) * 2);
    }
  }

  public PositionalLight (RayHandler rayHandler, int rays, Color color, float distance, float x, float y, float directionDegree) {
    super(rayHandler, rays, color, directionDegree, distance);
    start.x = x;
    start.y = y;
    sin = new float[rays];
    cos = new float[rays];
    endX = new float[rays];
    endY = new float[rays];

    lightMesh = new Mesh(VertexDataType.VertexArray, false, vertexNum, 0, new VertexAttribute(Usage.Position, 2,
      "vertex_positions"), new VertexAttribute(Usage.ColorPacked, 4, "quad_colors"),
      new VertexAttribute(Usage.Generic, 1, "s"));
    softShadowMesh = new Mesh(VertexDataType.VertexArray, false, vertexNum * 2, 0, new VertexAttribute(Usage.Position, 2,
      "vertex_positions"), new VertexAttribute(Usage.ColorPacked, 4, "quad_colors"),
      new VertexAttribute(Usage.Generic, 1, "s"));
    setMesh();
  }

  @Override
  public boolean contains (float x, float y) {

    // fast fail
    final float x_d = start.x - x;
    final float y_d = start.y - y;
    final float dst2 = x_d * x_d + y_d * y_d;
    if (distance * distance <= dst2) return false;

    // actual check

    boolean oddNodes = false;
    float x2 = mx[rayNum] = start.x;
    float y2 = my[rayNum] = start.y;
    float x1, y1;
    for (int i = 0; i <= rayNum; x2 = x1, y2 = y1, ++i) {
      x1 = mx[i];
      y1 = my[i];
      if (((y1 < y) && (y2 >= y)) || (y1 >= y) && (y2 < y)) {
        if ((y - y1) / (y2 - y1) * (x2 - x1) < (x - x1)) oddNodes = !oddNodes;
      }
    }
    return oddNodes;

  }
}
TOP

Related Classes of box2dLight.PositionalLight

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.