Guest User

Untitled

a guest
Jan 23rd, 2018
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 8.93 KB | None | 0 0
  1. /**
  2.  * @author kalle_h
  3.  *
  4.  */
  5. import com.badlogic.gdx.Gdx;
  6. import com.badlogic.gdx.graphics.Color;
  7. import com.badlogic.gdx.graphics.GL10;
  8. import com.badlogic.gdx.graphics.Mesh;
  9. import com.badlogic.gdx.graphics.VertexAttribute;
  10. import com.badlogic.gdx.graphics.VertexAttributes.Usage;
  11. import com.badlogic.gdx.math.MathUtils;
  12. import com.badlogic.gdx.math.Vector2;
  13. import com.badlogic.gdx.physics.box2d.Fixture;
  14. import com.badlogic.gdx.physics.box2d.RayCastCallback;
  15. import com.badlogic.gdx.physics.box2d.World;
  16. import com.badlogic.gdx.utils.Array;
  17.  
  18. public class RayHandler {
  19.  
  20.     private static final int MIN_RAYS = 3;
  21.     private final int MAX_RAYS;
  22.     private final GL10 gl;
  23.     public Mesh box;
  24.     public World world;
  25.  
  26.     /**
  27.      * This option need frame buffer with alpha channel You also need create box
  28.      * mesh by hand
  29.      */
  30.     public boolean shadows = false;
  31.     public float ambientLight = 0;
  32.  
  33.     final public Array<Light> lightList = new Array<Light>(false, 16,
  34.             Light.class);
  35.  
  36.     /**
  37.      * Light is data container for all the light parameters You can create
  38.      * instance of Light also with help of rayHandler addLight method
  39.      */
  40.     public final class Light {
  41.         public boolean active = true;
  42.         public boolean soft = true;
  43.         public boolean xray = false;
  44.         public boolean staticLight = false;
  45.         private int rayNum;
  46.         private int vertexNum;
  47.         float distance;
  48.         float coneDegree;
  49.         float direction;
  50.         final float sin[];
  51.         final float cos[];
  52.         Color color;
  53.         final Vector2 start = new Vector2();
  54.         final Vector2 end[];
  55.         final Mesh lightMesh;
  56.         final Mesh softShadowMesh;
  57.  
  58.         public Light(int rays) {
  59.             this(rays, false, false);
  60.         }
  61.  
  62.         public Light(int rays, boolean staticLight, boolean xray) {
  63.             this.staticLight = staticLight;
  64.             this.xray = xray;
  65.             setRayNum(rays);
  66.             sin = new float[rays];
  67.             cos = new float[rays];
  68.             end = new Vector2[rays];
  69.             for (int i = 0; i < rays; i++)
  70.                 end[i] = new Vector2();
  71.  
  72.             lightMesh = new Mesh(staticLight, vertexNum, 0,
  73.                     new VertexAttribute(Usage.Position, 2, "vertex_positions"),
  74.                     new VertexAttribute(Usage.ColorPacked, 4, "quad_colors"));
  75.             softShadowMesh = new Mesh(staticLight, vertexNum * 2, 0,
  76.                     new VertexAttribute(Usage.Position, 2, "vertex_positions"),
  77.                     new VertexAttribute(Usage.ColorPacked, 4, "quad_colors"));
  78.             lightList.add(this);
  79.         }
  80.  
  81.         final public void setRayNum(int rays) {
  82.             if (rays > MAX_RAYS) {
  83.                 rays = MAX_RAYS;
  84.             }
  85.             if (rays < MIN_RAYS) {
  86.                 rays = MIN_RAYS;
  87.             }
  88.             rayNum = rays;
  89.             vertexNum = rays + 1;
  90.  
  91.         }
  92.  
  93.         final public void setRotation(float direction) {
  94.             setPosAndRotation(start.x, start.y, direction);
  95.         }
  96.  
  97.         final public void setPos(float x, float y) {
  98.             setPosAndRotation(x, y, direction);
  99.         }
  100.  
  101.         /**
  102.          * set the starting point and direction, call this if you need to change
  103.          * noth positon and rotation for slightly better perfirmance
  104.          */
  105.         final public void setPosAndRotation(float x, float y, float direction) {
  106.             start.x = x;
  107.             start.y = y;
  108.             this.direction = direction;
  109.             for (int i = 0; i < rayNum; i++) {
  110.                 float angle = direction + coneDegree - 2f * coneDegree
  111.                         * (float) i / ((float) rayNum - 1f);
  112.                 final float s = sin[i] = MathUtils.sinDeg(angle);
  113.                 final float c = cos[i] = MathUtils.cosDeg(angle);
  114.                 end[i].set(x + distance * s, y + distance * c);
  115.             }
  116.             if (staticLight)
  117.                 updateLight(this);
  118.         }
  119.  
  120.         final public void remove() {
  121.             lightMesh.dispose();
  122.             lightList.removeValue(this, true);
  123.         }
  124.     }
  125.  
  126.     static final int defaultMaximum = 1023;
  127.  
  128.     public RayHandler(World world) {
  129.         this(world, defaultMaximum);
  130.     }
  131.  
  132.     public RayHandler(World world, int maxRayCount) {
  133.         this.world = world;
  134.         MAX_RAYS = maxRayCount;
  135.         gl = Gdx.graphics.getGL10();   
  136.         m_segments = new float[maxRayCount * 6];
  137.         m_x = new float[maxRayCount];
  138.         m_y = new float[maxRayCount];
  139.         m_f = new float[maxRayCount];
  140.         box = new Mesh(false, 12, 0, new VertexAttribute(Usage.Position, 2,
  141.                 "vertex_positions"), new VertexAttribute(Usage.ColorPacked, 4,
  142.                 "quad_colors"));
  143.         setShadowBox();
  144.     }
  145.  
  146.     /**
  147.      * addLight
  148.      *
  149.      */
  150.     public final Light addLight(float x, float y, float directionDegree,
  151.             float coneDegree, float distance, int rays, Color color,
  152.             boolean staticLight, boolean xray) {
  153.         final Light light = new Light(rays, staticLight, xray);
  154.         light.distance = distance;
  155.         light.coneDegree = coneDegree;
  156.         light.color = color;
  157.         light.setPosAndRotation(x, y, directionDegree);
  158.         return light;
  159.     }
  160.  
  161.     /**
  162.      * REMEMBER CALL updateRays(World world) BEFORE render. Don't call this
  163.      * inside of any begin/end statements. Call this method after you have
  164.      * rendered background but before UI Box2d bodies can be rendered before or
  165.      * after depending how you want x-ray light interact with bodies
  166.      */
  167.     public void render() {
  168.  
  169.         if (shadows) {
  170.             // clearing the alpha channel
  171.             gl.glClearColor(0f, 0f, 0f, ambientLight);
  172.             gl.glColorMask(false, false, false, true);
  173.             gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
  174.             gl.glColorMask(true, true, true, true);
  175.             gl.glClearColor(0f, 0f, 0f, 1f);
  176.         }
  177.         // light rays
  178.         gl.glEnable(GL10.GL_BLEND);
  179.         gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE);
  180.         final int size = lightList.size;
  181.         for (int i = 0; i < size; i++) {
  182.             Light light = lightList.items[i];
  183.             if (light.active) {
  184.                 light.lightMesh
  185.                         .render(GL10.GL_TRIANGLE_FAN, 0, light.vertexNum);
  186.                 if (light.soft && !light.xray) {
  187.                     light.softShadowMesh.render(GL10.GL_TRIANGLE_STRIP, 0,
  188.                             (light.vertexNum - 1) * 2);
  189.                 }
  190.             }
  191.         }
  192.  
  193.         if (shadows) {
  194.             // rendering shadow box over screen
  195.             gl.glBlendFunc(GL10.GL_ONE, GL10.GL_DST_ALPHA);
  196.             box.render(GL10.GL_TRIANGLE_FAN, 0, 4);
  197.         }
  198.         gl.glDisable(GL10.GL_BLEND);
  199.     }
  200.  
  201.     private final void updateLightMesh(Light light) {
  202.  
  203.         final float r = light.color.r;
  204.         final float g = light.color.g;
  205.         final float b = light.color.b;
  206.         final float a = light.color.a;
  207.         // ray starting point
  208.         int size = 0;
  209.         m_segments[size++] = light.start.x;
  210.         m_segments[size++] = light.start.y;
  211.         m_segments[size++] = Color.toFloatBits(r, g, b, a);
  212.         // rays ending points.
  213.         final int arraySize = light.rayNum;
  214.         for (int i = 0; i < arraySize; i++) {
  215.             m_segments[size++] = m_x[i];
  216.             m_segments[size++] = m_y[i];
  217.             final float s = 1f - m_f[i];
  218.             m_segments[size++] = Color.toFloatBits(light.color.r * s,
  219.                     light.color.g * s, light.color.b * s, a * s);
  220.         }
  221.         light.lightMesh.setVertices(m_segments, 0, size);
  222.  
  223.         if (!light.soft || light.xray)
  224.             return;
  225.  
  226.         size = 0;
  227.         // rays ending points.
  228.         final float zero = Color.toFloatBits(0, 0, 0, 0);
  229.         for (int i = 0; i < arraySize; i++) {
  230.             m_segments[size++] = m_x[i];
  231.             m_segments[size++] = m_y[i];
  232.             final float s = 1f - m_f[i];
  233.             m_segments[size++] = Color.toFloatBits(light.color.r * s,
  234.                     light.color.g * s, light.color.b * s, a * s);
  235.             m_segments[size++] = m_x[i] + 5 * light.sin[i];
  236.             m_segments[size++] = m_y[i] + 5 * light.cos[i];
  237.             m_segments[size++] = zero;
  238.         }
  239.         light.softShadowMesh.setVertices(m_segments, 0, size);
  240.  
  241.     }
  242.  
  243.     public void dispose() {
  244.         final int size = lightList.size;
  245.         for (int i = 0; i < size; i++) {
  246.             lightList.items[i].lightMesh.dispose();
  247.         }
  248.     }
  249.  
  250.     /**
  251.      * Don't call this inside of any begin/end statements. Call this method
  252.      * after you have rendered background but before UI Box2d bodies can be
  253.      * rendered before or after depending how you want x-ray light interact with
  254.      * bodies
  255.      */
  256.     public final void updateAndRender() {
  257.         updateRays();
  258.         render();
  259.     }
  260.  
  261.     // Rays
  262.     public final void updateRays() {
  263.         final int size = lightList.size;
  264.         for (int j = 0; j < size; j++) {
  265.             final Light light = lightList.items[j];
  266.             if (light.active && !light.staticLight) {
  267.                 updateLight(light);
  268.             }
  269.         }
  270.     }
  271.  
  272.     public final void updateLight(Light light) {
  273.  
  274.         for (int i = 0; i < light.rayNum; i++) {
  275.             m_index = i;
  276.             m_f[i] = 1f;
  277.             m_x[i] = light.end[i].x;
  278.             m_y[i] = light.end[i].y;
  279.             if (!light.xray)
  280.                 world.rayCast(ray, light.start, light.end[i]);
  281.         }
  282.         updateLightMesh(light);
  283.  
  284.     }
  285.  
  286.     final private float m_segments[];
  287.     final private float[] m_x;
  288.     final private float[] m_y;
  289.     final private float[] m_f;
  290.     private int m_index = 0;
  291.     final private RayCastCallback ray = new RayCastCallback() {
  292.         @Override
  293.         public float reportRayFixture(Fixture fixture, Vector2 point,
  294.                 Vector2 normal, float fraction) {          
  295.             m_x[m_index] = point.x;
  296.             m_y[m_index] = point.y;
  297.             m_f[m_index] = fraction;
  298.             return fraction;
  299.         }
  300.     };
  301.  
  302.     private void setShadowBox() {
  303.         int i = 0;
  304.         // This need some work, maybe camera matrix would needed
  305.         float c = Color.toFloatBits(0, 0, 0, 1);
  306.         m_segments[i++] = -8f;
  307.         m_segments[i++] = 0f;
  308.         m_segments[i++] = c;
  309.         m_segments[i++] = -8f;
  310.         m_segments[i++] = 27f;
  311.         m_segments[i++] = c;
  312.         m_segments[i++] = 8f;
  313.         m_segments[i++] = 27f;
  314.         m_segments[i++] = c;
  315.         m_segments[i++] = 8f;
  316.         m_segments[i++] = 0f;
  317.         m_segments[i++] = c;
  318.         box.setVertices(m_segments, 0, i);
  319.  
  320.     }
  321. }
Add Comment
Please, Sign In to add comment