Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * @author kalle_h
- *
- */
- import com.badlogic.gdx.Gdx;
- import com.badlogic.gdx.graphics.Color;
- import com.badlogic.gdx.graphics.GL10;
- import com.badlogic.gdx.graphics.Mesh;
- 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.Fixture;
- import com.badlogic.gdx.physics.box2d.RayCastCallback;
- import com.badlogic.gdx.physics.box2d.World;
- import com.badlogic.gdx.utils.Array;
- public class RayHandler {
- private static final int MIN_RAYS = 3;
- private final int MAX_RAYS;
- private final GL10 gl;
- public Mesh box;
- public World world;
- /**
- * This option need frame buffer with alpha channel You also need create box
- * mesh by hand
- */
- public boolean shadows = false;
- public float ambientLight = 0;
- final public Array<Light> lightList = new Array<Light>(false, 16,
- Light.class);
- /**
- * Light is data container for all the light parameters You can create
- * instance of Light also with help of rayHandler addLight method
- */
- public final class Light {
- public boolean active = true;
- public boolean soft = true;
- public boolean xray = false;
- public boolean staticLight = false;
- private int rayNum;
- private int vertexNum;
- float distance;
- float coneDegree;
- float direction;
- final float sin[];
- final float cos[];
- Color color;
- final Vector2 start = new Vector2();
- final Vector2 end[];
- final Mesh lightMesh;
- final Mesh softShadowMesh;
- public Light(int rays) {
- this(rays, false, false);
- }
- public Light(int rays, boolean staticLight, boolean xray) {
- this.staticLight = staticLight;
- this.xray = xray;
- setRayNum(rays);
- sin = new float[rays];
- cos = new float[rays];
- end = new Vector2[rays];
- for (int i = 0; i < rays; i++)
- end[i] = new Vector2();
- lightMesh = new Mesh(staticLight, vertexNum, 0,
- new VertexAttribute(Usage.Position, 2, "vertex_positions"),
- new VertexAttribute(Usage.ColorPacked, 4, "quad_colors"));
- softShadowMesh = new Mesh(staticLight, vertexNum * 2, 0,
- new VertexAttribute(Usage.Position, 2, "vertex_positions"),
- new VertexAttribute(Usage.ColorPacked, 4, "quad_colors"));
- lightList.add(this);
- }
- final public void setRayNum(int rays) {
- if (rays > MAX_RAYS) {
- rays = MAX_RAYS;
- }
- if (rays < MIN_RAYS) {
- rays = MIN_RAYS;
- }
- rayNum = rays;
- vertexNum = rays + 1;
- }
- final public void setRotation(float direction) {
- setPosAndRotation(start.x, start.y, direction);
- }
- final public void setPos(float x, float y) {
- setPosAndRotation(x, y, direction);
- }
- /**
- * set the starting point and direction, call this if you need to change
- * noth positon and rotation for slightly better perfirmance
- */
- final public void setPosAndRotation(float x, float y, float direction) {
- start.x = x;
- start.y = y;
- this.direction = direction;
- for (int i = 0; i < rayNum; i++) {
- float angle = direction + coneDegree - 2f * coneDegree
- * (float) i / ((float) rayNum - 1f);
- final float s = sin[i] = MathUtils.sinDeg(angle);
- final float c = cos[i] = MathUtils.cosDeg(angle);
- end[i].set(x + distance * s, y + distance * c);
- }
- if (staticLight)
- updateLight(this);
- }
- final public void remove() {
- lightMesh.dispose();
- lightList.removeValue(this, true);
- }
- }
- static final int defaultMaximum = 1023;
- public RayHandler(World world) {
- this(world, defaultMaximum);
- }
- public RayHandler(World world, int maxRayCount) {
- this.world = world;
- MAX_RAYS = maxRayCount;
- gl = Gdx.graphics.getGL10();
- m_segments = new float[maxRayCount * 6];
- m_x = new float[maxRayCount];
- m_y = new float[maxRayCount];
- m_f = new float[maxRayCount];
- box = new Mesh(false, 12, 0, new VertexAttribute(Usage.Position, 2,
- "vertex_positions"), new VertexAttribute(Usage.ColorPacked, 4,
- "quad_colors"));
- setShadowBox();
- }
- /**
- * addLight
- *
- */
- public final Light addLight(float x, float y, float directionDegree,
- float coneDegree, float distance, int rays, Color color,
- boolean staticLight, boolean xray) {
- final Light light = new Light(rays, staticLight, xray);
- light.distance = distance;
- light.coneDegree = coneDegree;
- light.color = color;
- light.setPosAndRotation(x, y, directionDegree);
- return light;
- }
- /**
- * REMEMBER CALL updateRays(World world) BEFORE render. Don't call this
- * inside of any begin/end statements. Call this method after you have
- * rendered background but before UI Box2d bodies can be rendered before or
- * after depending how you want x-ray light interact with bodies
- */
- public void render() {
- if (shadows) {
- // clearing the alpha channel
- gl.glClearColor(0f, 0f, 0f, ambientLight);
- gl.glColorMask(false, false, false, true);
- gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
- gl.glColorMask(true, true, true, true);
- gl.glClearColor(0f, 0f, 0f, 1f);
- }
- // light rays
- gl.glEnable(GL10.GL_BLEND);
- gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE);
- final int size = lightList.size;
- for (int i = 0; i < size; i++) {
- Light light = lightList.items[i];
- if (light.active) {
- light.lightMesh
- .render(GL10.GL_TRIANGLE_FAN, 0, light.vertexNum);
- if (light.soft && !light.xray) {
- light.softShadowMesh.render(GL10.GL_TRIANGLE_STRIP, 0,
- (light.vertexNum - 1) * 2);
- }
- }
- }
- if (shadows) {
- // rendering shadow box over screen
- gl.glBlendFunc(GL10.GL_ONE, GL10.GL_DST_ALPHA);
- box.render(GL10.GL_TRIANGLE_FAN, 0, 4);
- }
- gl.glDisable(GL10.GL_BLEND);
- }
- private final void updateLightMesh(Light light) {
- final float r = light.color.r;
- final float g = light.color.g;
- final float b = light.color.b;
- final float a = light.color.a;
- // ray starting point
- int size = 0;
- m_segments[size++] = light.start.x;
- m_segments[size++] = light.start.y;
- m_segments[size++] = Color.toFloatBits(r, g, b, a);
- // rays ending points.
- final int arraySize = light.rayNum;
- for (int i = 0; i < arraySize; i++) {
- m_segments[size++] = m_x[i];
- m_segments[size++] = m_y[i];
- final float s = 1f - m_f[i];
- m_segments[size++] = Color.toFloatBits(light.color.r * s,
- light.color.g * s, light.color.b * s, a * s);
- }
- light.lightMesh.setVertices(m_segments, 0, size);
- if (!light.soft || light.xray)
- return;
- size = 0;
- // rays ending points.
- final float zero = Color.toFloatBits(0, 0, 0, 0);
- for (int i = 0; i < arraySize; i++) {
- m_segments[size++] = m_x[i];
- m_segments[size++] = m_y[i];
- final float s = 1f - m_f[i];
- m_segments[size++] = Color.toFloatBits(light.color.r * s,
- light.color.g * s, light.color.b * s, a * s);
- m_segments[size++] = m_x[i] + 5 * light.sin[i];
- m_segments[size++] = m_y[i] + 5 * light.cos[i];
- m_segments[size++] = zero;
- }
- light.softShadowMesh.setVertices(m_segments, 0, size);
- }
- public void dispose() {
- final int size = lightList.size;
- for (int i = 0; i < size; i++) {
- lightList.items[i].lightMesh.dispose();
- }
- }
- /**
- * Don't call this inside of any begin/end statements. Call this method
- * after you have rendered background but before UI Box2d bodies can be
- * rendered before or after depending how you want x-ray light interact with
- * bodies
- */
- public final void updateAndRender() {
- updateRays();
- render();
- }
- // Rays
- public final void updateRays() {
- final int size = lightList.size;
- for (int j = 0; j < size; j++) {
- final Light light = lightList.items[j];
- if (light.active && !light.staticLight) {
- updateLight(light);
- }
- }
- }
- public final void updateLight(Light light) {
- for (int i = 0; i < light.rayNum; i++) {
- m_index = i;
- m_f[i] = 1f;
- m_x[i] = light.end[i].x;
- m_y[i] = light.end[i].y;
- if (!light.xray)
- world.rayCast(ray, light.start, light.end[i]);
- }
- updateLightMesh(light);
- }
- final private float m_segments[];
- final private float[] m_x;
- final private float[] m_y;
- final private float[] m_f;
- private int m_index = 0;
- final private RayCastCallback ray = new RayCastCallback() {
- @Override
- public float reportRayFixture(Fixture fixture, Vector2 point,
- Vector2 normal, float fraction) {
- m_x[m_index] = point.x;
- m_y[m_index] = point.y;
- m_f[m_index] = fraction;
- return fraction;
- }
- };
- private void setShadowBox() {
- int i = 0;
- // This need some work, maybe camera matrix would needed
- float c = Color.toFloatBits(0, 0, 0, 1);
- m_segments[i++] = -8f;
- m_segments[i++] = 0f;
- m_segments[i++] = c;
- m_segments[i++] = -8f;
- m_segments[i++] = 27f;
- m_segments[i++] = c;
- m_segments[i++] = 8f;
- m_segments[i++] = 27f;
- m_segments[i++] = c;
- m_segments[i++] = 8f;
- m_segments[i++] = 0f;
- m_segments[i++] = c;
- box.setVertices(m_segments, 0, i);
- }
- }
Add Comment
Please, Sign In to add comment