Advertisement
Guest User

Untitled

a guest
Nov 3rd, 2013
632
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 19.12 KB | None | 0 0
  1. /* Copyright 2011 See AUTHORS file.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. *   http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. ******************************************************************************/
  15.  
  16. package com.esotericsoftware.spine;
  17.  
  18. import com.badlogic.gdx.Gdx;
  19. import com.badlogic.gdx.graphics.Color;
  20. import com.badlogic.gdx.graphics.GL10;
  21. import com.badlogic.gdx.graphics.GL11;
  22. import com.badlogic.gdx.graphics.GL20;
  23. import com.badlogic.gdx.graphics.GLCommon;
  24. import com.badlogic.gdx.graphics.Mesh;
  25. import com.badlogic.gdx.graphics.Mesh.VertexDataType;
  26. import com.badlogic.gdx.graphics.Texture;
  27. import com.badlogic.gdx.graphics.VertexAttribute;
  28. import com.badlogic.gdx.graphics.VertexAttributes.Usage;
  29. import com.badlogic.gdx.graphics.glutils.ShaderProgram;
  30. import com.badlogic.gdx.math.Matrix4;
  31. import com.badlogic.gdx.utils.Disposable;
  32.  
  33. /** <p>
  34. * A SpineSpriteBatch is used to draw 2D rectangles that reference a texture (region). The class will batch the drawing commands and
  35. * optimize them for processing by the GPU.
  36. * </p>
  37. *
  38. * <p>
  39. * To draw something with a SpineSpriteBatch one has to first call the {@link SpineSpriteBatch#begin()} method which will setup appropriate
  40. * render states. When you are done with drawing you have to call {@link SpineSpriteBatch#end()} which will actually draw the things
  41. * you specified.
  42. * </p>
  43. *
  44. * <p>
  45. * All drawing commands of the SpineSpriteBatch operate in screen coordinates. The screen coordinate system has an x-axis pointing to
  46. * the right, an y-axis pointing upwards and the origin is in the lower left corner of the screen. You can also provide your own
  47. * transformation and projection matrices if you so wish.
  48. * </p>
  49. *
  50. * <p>
  51. * A SpineSpriteBatch is managed. In case the OpenGL context is lost all OpenGL resources a SpineSpriteBatch uses internally get
  52. * invalidated. A context is lost when a user switches to another application or receives an incoming call on Android. A
  53. * SpineSpriteBatch will be automatically reloaded after the OpenGL context is restored.
  54. * </p>
  55. *
  56. * <p>
  57. * A SpineSpriteBatch is a pretty heavy object so you should only ever have one in your program.
  58. * </p>
  59. *
  60. * <p>
  61. * A SpineSpriteBatch works with OpenGL ES 1.x and 2.0. In the case of a 2.0 context it will use its own custom shader to draw all
  62. * provided sprites. You can set your own custom shader via {@link #setShader(ShaderProgram)}.
  63. * </p>
  64. *
  65. * <p>
  66. * A SpineSpriteBatch has to be disposed if it is no longer used.
  67. * </p>
  68. *
  69. * @author mzechner */
  70. public class SpineSpriteBatch implements Disposable {
  71.     private Mesh mesh;
  72.     private Mesh[] buffers;
  73.  
  74.     private Texture lastTexture = null;
  75.     private int idx = 0;
  76.     private int currBufferIdx = 0;
  77.     private final float[] vertices;
  78.  
  79.     private final Matrix4 transformMatrix = new Matrix4();
  80.     private final Matrix4 projectionMatrix = new Matrix4();
  81.     private final Matrix4 combinedMatrix = new Matrix4();
  82.  
  83.     private boolean drawing = false;
  84.  
  85.     private boolean blendingDisabled = false;
  86.     private int blendSrcFunc = GL11.GL_SRC_ALPHA;
  87.     private int blendDstFunc = GL11.GL_ONE_MINUS_SRC_ALPHA;
  88.  
  89.     private final ShaderProgram shader;
  90.     private boolean ownsShader;
  91.  
  92.     float color = Color.WHITE.toFloatBits();
  93.     /** number of render calls since last {@link #begin()} **/
  94.     public int renderCalls = 0;
  95.  
  96.     /** number of rendering calls ever, will not be reset, unless it's done manually **/
  97.     public int totalRenderCalls = 0;
  98.  
  99.     /** the maximum number of sprites rendered in one batch so far **/
  100.     public int maxSpritesInBatch = 0;
  101.     private ShaderProgram customShader = null;
  102.  
  103.     /** Constructs a new SpineSpriteBatch. Sets the projection matrix to an orthographic projection with y-axis point upwards, x-axis
  104.      * point to the right and the origin being in the bottom left corner of the screen. The projection will be pixel perfect with
  105.      * respect to the screen resolution. */
  106.     public SpineSpriteBatch () {
  107.         this(1000);
  108.     }
  109.  
  110.     /** Constructs a SpineSpineSpriteBatch with the specified size and (if GL2) the default shader. See
  111.      * {@link #SpineSpineSpriteBatch(int, ShaderProgram)}. */
  112.     public SpineSpriteBatch (int size) {
  113.         this(size, null);
  114.     }
  115.  
  116.     /** <p>
  117.      * Constructs a new SpineSpineSpriteBatch. Sets the projection matrix to an orthographic projection with y-axis point upwards, x-axis
  118.      * point to the right and the origin being in the bottom left corner of the screen. The projection will be pixel perfect with
  119.      * respect to the screen resolution.
  120.      * </p>
  121.      *
  122.      * <p>
  123.      * The size parameter specifies the maximum size of a single batch in number of sprites
  124.      * </p>
  125.      *
  126.      * <p>
  127.      * The defaultShader specifies the shader to use. Note that the names for uniforms for this default shader are different than
  128.      * the ones expect for shaders set with {@link #setShader(ShaderProgram)}. See the {@link #createDefaultShader()} method.
  129.      * </p>
  130.      *
  131.      * @param size the batch size in number of sprites
  132.      * @param defaultShader the default shader to use. This is not owned by the SpineSpineSpriteBatch and must be disposed separately. */
  133.     public SpineSpriteBatch (int size, ShaderProgram defaultShader) {
  134.         this(size, 1, defaultShader);
  135.     }
  136.  
  137.     /** Constructs a SpineSpineSpriteBatch with the specified size and number of buffers and (if GL2) the default shader. See
  138.      * {@link #SpineSpineSpriteBatch(int, int, ShaderProgram)}. */
  139.     public SpineSpriteBatch (int size, int buffers) {
  140.         this(size, buffers, null);
  141.     }
  142.  
  143.     /** <p>
  144.      * Constructs a new SpineSpriteBatch. Sets the projection matrix to an orthographic projection with y-axis point upwards, x-axis
  145.      * point to the right and the origin being in the bottom left corner of the screen. The projection will be pixel perfect with
  146.      * respect to the screen resolution.
  147.      * </p>
  148.      *
  149.      * <p>
  150.      * The size parameter specifies the maximum size of a single batch in number of sprites
  151.      * </p>
  152.      *
  153.      * <p>
  154.      * The defaultShader specifies the shader to use. Note that the names for uniforms for this default shader are different than
  155.      * the ones expect for shaders set with {@link #setShader(ShaderProgram)}. See the {@link #createDefaultShader()} method.
  156.      * </p>
  157.      *
  158.      * @param size the batch size in number of sprites
  159.      * @param buffers the number of buffers to use. only makes sense with VBOs. This is an expert function.
  160.      * @param defaultShader the default shader to use. This is not owned by the SpineSpriteBatch and must be disposed separately. */
  161.     public SpineSpriteBatch (int size, int buffers, ShaderProgram defaultShader) {
  162.         this.buffers = new Mesh[buffers];
  163.  
  164.         for (int i = 0; i < buffers; i++) {
  165.             this.buffers[i] = new Mesh(VertexDataType.VertexArray, false, size * 4, size * 6, new VertexAttribute(Usage.Position, 2,
  166.                 ShaderProgram.POSITION_ATTRIBUTE), new VertexAttribute(Usage.ColorPacked, 4, ShaderProgram.COLOR_ATTRIBUTE),
  167.                 new VertexAttribute(Usage.TextureCoordinates, 2, ShaderProgram.TEXCOORD_ATTRIBUTE + "0"),
  168.                 new VertexAttribute(Usage.Generic, 1, "a_rot"));
  169.         }
  170.  
  171.         projectionMatrix.setToOrtho2D(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
  172.  
  173.         vertices = new float[size * 24];
  174.  
  175.         int len = size * 6;
  176.         short[] indices = new short[len];
  177.         short j = 0;
  178.         for (int i = 0; i < len; i += 6, j += 4) {
  179.             indices[i + 0] = (short)(j + 0);
  180.             indices[i + 1] = (short)(j + 1);
  181.             indices[i + 2] = (short)(j + 2);
  182.             indices[i + 3] = (short)(j + 2);
  183.             indices[i + 4] = (short)(j + 3);
  184.             indices[i + 5] = (short)(j + 0);
  185.         }
  186.         for (int i = 0; i < buffers; i++) {
  187.             this.buffers[i].setIndices(indices);
  188.         }
  189.         mesh = this.buffers[0];
  190.  
  191.         if (Gdx.graphics.isGL20Available() && defaultShader == null) {
  192.             shader = createDefaultShader();
  193.             ownsShader = true;
  194.         } else
  195.             shader = defaultShader;
  196.     }
  197.  
  198.     /** Returns a new instance of the default shader used by SpineSpriteBatch for GL2 when no shader is specified. */
  199.     static public ShaderProgram createDefaultShader () {
  200.         String vertexShader = "attribute vec4 " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" //
  201.             + "attribute vec4 " + ShaderProgram.COLOR_ATTRIBUTE + ";\n" //
  202.             + "attribute vec2 " + ShaderProgram.TEXCOORD_ATTRIBUTE + "0;\n" //
  203.             + "attribute float a_rot;\n" //
  204.             + "uniform mat4 u_projTrans;\n" //
  205.             + "varying vec4 v_color;\n" //
  206.             + "varying vec2 v_texCoords;\n" //
  207.             + "varying vec3 v_lightDir;\n" //
  208.             + "const vec3 lightDir = normalize(vec3(-0.0, -1.0, 0.2));\n" //
  209.             + "\n" //
  210.             + "void main()\n" //
  211.             + "{\n" //
  212.             + "   v_color = " + ShaderProgram.COLOR_ATTRIBUTE + ";\n" //
  213.             + "   vec2 rad = vec2(-sin(a_rot), cos(a_rot));\n" //
  214.             + "   v_lightDir = vec3(mat2(rad.y, -rad.x, rad.x, rad.y) * lightDir.xy,lightDir.z);\n" //
  215.             + "   v_texCoords = " + ShaderProgram.TEXCOORD_ATTRIBUTE + "0;\n" //
  216.             + "   gl_Position =  u_projTrans * " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" //
  217.             + "}\n";
  218.         String fragmentShader = "#ifdef GL_ES\n" //
  219.             + "#define LOWP lowp\n" //
  220.             + "precision mediump float;\n" //
  221.             + "#else\n" //
  222.             + "#define LOWP \n" //
  223.             + "#endif\n" //
  224.             + "varying LOWP vec4 v_color;\n" //
  225.             + "varying vec2 v_texCoords;\n" //
  226.             + "varying vec3 v_lightDir;\n" //
  227.             + "uniform sampler2D u_texture;\n" //
  228.             + "uniform sampler2D u_texture2;\n" //
  229.             + "void main()\n"//
  230.             + "{\n" //
  231.             + "   vec4 albedo = texture2D(u_texture, v_texCoords);\n" //
  232.             + "   vec3 normal = texture2D(u_texture2, v_texCoords).xyz * 2.0 - 1.0;\n" //
  233.             + "   float light = clamp(dot(normalize(v_lightDir), normal), 0.0, 1.0) ;\n" //
  234.             + "  gl_FragColor = v_color * vec4((light*light * albedo.rgb), albedo.a);\n" //
  235.             + "}";
  236.  
  237.         ShaderProgram shader = new ShaderProgram(vertexShader, fragmentShader);
  238.         if (shader.isCompiled() == false) throw new IllegalArgumentException("couldn't compile shader: " + shader.getLog());
  239.         return shader;
  240.     }
  241.  
  242.     /** Sets up the SpineSpriteBatch for drawing. This will disable depth buffer writting. It enables blending and texturing. If you have
  243.      * more texture units enabled than the first one you have to disable them before calling this. Uses a screen coordinate system
  244.      * by default where everything is given in pixels. You can specify your own projection and modelview matrices via
  245.      * {@link #setProjectionMatrix(Matrix4)} and {@link #setTransformMatrix(Matrix4)}. */
  246.     public void begin () {
  247.         if (drawing) throw new IllegalStateException("you have to call SpineSpriteBatch.end() first");
  248.         renderCalls = 0;
  249.  
  250.         Gdx.gl.glDepthMask(false);
  251.         if (Gdx.graphics.isGL20Available()) {
  252.             if (customShader != null)
  253.                 customShader.begin();
  254.             else
  255.                 shader.begin();
  256.         } else {
  257.             Gdx.gl.glEnable(GL10.GL_TEXTURE_2D);
  258.         }
  259.         setupMatrices();
  260.  
  261.         idx = 0;
  262.         lastTexture = null;
  263.         drawing = true;
  264.     }
  265.  
  266.     /** Finishes off rendering. Enables depth writes, disables blending and texturing. Must always be called after a call to
  267.      * {@link #begin()} */
  268.     public void end () {
  269.         if (!drawing) throw new IllegalStateException("SpineSpriteBatch.begin must be called before end.");
  270.         if (idx > 0) renderMesh();
  271.         lastTexture = null;
  272.         idx = 0;
  273.         drawing = false;
  274.  
  275.         GLCommon gl = Gdx.gl;
  276.         gl.glDepthMask(true);
  277.         if (isBlendingEnabled()) gl.glDisable(GL10.GL_BLEND);
  278.  
  279.         if (Gdx.graphics.isGL20Available()) {
  280.             if (customShader != null)
  281.                 customShader.end();
  282.             else
  283.                 shader.end();
  284.         } else {
  285.             gl.glDisable(GL10.GL_TEXTURE_2D);
  286.         }
  287.     }
  288.    
  289.     /** Sets the color used to tint images when they are added to the SpineSpriteBatch. Default is {@link Color#WHITE}. */
  290.     public void setColor (Color tint) {
  291.         color = tint.toFloatBits();
  292.     }
  293.  
  294.  
  295.     /** Draws a rectangle using the given vertices. There must be 4 vertices, each made up of 5 elements in this order: x, y, color,
  296.      * u, v. The {@link #getColor()} from the SpineSpriteBatch is not applied. */
  297.     public void draw (Texture texture, float[] spriteVertices, int offset, int length) {
  298.         if (!drawing) throw new IllegalStateException("SpineSpriteBatch.begin must be called before draw.");
  299.  
  300.         if (texture != lastTexture) {
  301.             switchTexture(texture);
  302.         }
  303.  
  304.         int remainingVertices = vertices.length - idx;
  305.         if (remainingVertices == 0) {
  306.             renderMesh();
  307.             remainingVertices = vertices.length;
  308.         }
  309.         int vertexCount = Math.min(remainingVertices, length - offset);
  310.         System.arraycopy(spriteVertices, offset, vertices, idx, vertexCount);
  311.         offset += vertexCount;
  312.         idx += vertexCount;
  313.  
  314.         while (offset < length) {
  315.             renderMesh();
  316.             vertexCount = Math.min(vertices.length, length - offset);
  317.             System.arraycopy(spriteVertices, offset, vertices, 0, vertexCount);
  318.             offset += vertexCount;
  319.             idx += vertexCount;
  320.         }
  321.     }
  322.  
  323.  
  324.     /** Causes any pending sprites to be rendered, without ending the SpineSpriteBatch. */
  325.     public void flush () {
  326.         renderMesh();
  327.     }
  328.  
  329.     private void renderMesh () {
  330.         if (idx == 0) return;
  331.  
  332.         renderCalls++;
  333.         totalRenderCalls++;
  334.         int spritesInBatch = idx / 20;
  335.         if (spritesInBatch > maxSpritesInBatch) maxSpritesInBatch = spritesInBatch;
  336.  
  337.         lastTexture.bind();
  338.         mesh.setVertices(vertices, 0, idx);
  339.         mesh.getIndicesBuffer().position(0);
  340.         mesh.getIndicesBuffer().limit(spritesInBatch * 6);
  341.  
  342.         if (blendingDisabled) {
  343.             Gdx.gl.glDisable(GL20.GL_BLEND);
  344.         } else {
  345.             Gdx.gl.glEnable(GL20.GL_BLEND);
  346.             if (blendSrcFunc != -1) Gdx.gl.glBlendFunc(blendSrcFunc, blendDstFunc);
  347.         }
  348.  
  349.         if (Gdx.graphics.isGL20Available()) {
  350.             if (customShader != null)
  351.                 mesh.render(customShader, GL10.GL_TRIANGLES, 0, spritesInBatch * 6);
  352.             else
  353.                 mesh.render(shader, GL10.GL_TRIANGLES, 0, spritesInBatch * 6);
  354.         } else {
  355.             mesh.render(GL10.GL_TRIANGLES, 0, spritesInBatch * 6);
  356.         }
  357.  
  358.         idx = 0;
  359.         currBufferIdx++;
  360.         if (currBufferIdx == buffers.length) currBufferIdx = 0;
  361.         mesh = buffers[currBufferIdx];
  362.     }
  363.  
  364.     /** Disables blending for drawing sprites. */
  365.     public void disableBlending () {
  366.         if (blendingDisabled) return;
  367.         renderMesh();
  368.         blendingDisabled = true;
  369.     }
  370.  
  371.     /** Enables blending for sprites */
  372.     public void enableBlending () {
  373.         if (!blendingDisabled) return;
  374.         renderMesh();
  375.         blendingDisabled = false;
  376.     }
  377.  
  378.     /** Sets the blending function to be used when rendering sprites.
  379.      *
  380.      * @param srcFunc the source function, e.g. GL11.GL_SRC_ALPHA. If set to -1, SpineSpriteBatch won't change the blending function.
  381.      * @param dstFunc the destination function, e.g. GL11.GL_ONE_MINUS_SRC_ALPHA */
  382.     public void setBlendFunction (int srcFunc, int dstFunc) {
  383.         renderMesh();
  384.         blendSrcFunc = srcFunc;
  385.         blendDstFunc = dstFunc;
  386.     }
  387.  
  388.     /** Disposes all resources associated with this SpineSpriteBatch */
  389.     public void dispose () {
  390.         for (int i = 0; i < buffers.length; i++)
  391.             buffers[i].dispose();
  392.         if (ownsShader && shader != null) shader.dispose();
  393.     }
  394.  
  395.     /** Returns the current projection matrix. Changing this will result in undefined behaviour.
  396.      *
  397.      * @return the currently set projection matrix */
  398.     public Matrix4 getProjectionMatrix () {
  399.         return projectionMatrix;
  400.     }
  401.  
  402.     /** Returns the current transform matrix. Changing this will result in undefined behaviour.
  403.      *
  404.      * @return the currently set transform matrix */
  405.     public Matrix4 getTransformMatrix () {
  406.         return transformMatrix;
  407.     }
  408.  
  409.     /** Sets the projection matrix to be used by this SpineSpriteBatch. If this is called inside a {@link #begin()}/{@link #end()} block.
  410.      * the current batch is flushed to the gpu.
  411.      *
  412.      * @param projection the projection matrix */
  413.     public void setProjectionMatrix (Matrix4 projection) {
  414.         if (drawing) flush();
  415.         projectionMatrix.set(projection);
  416.         if (drawing) setupMatrices();
  417.     }
  418.  
  419.     /** Sets the transform matrix to be used by this SpineSpriteBatch. If this is called inside a {@link #begin()}/{@link #end()} block.
  420.      * the current batch is flushed to the gpu.
  421.      *
  422.      * @param transform the transform matrix */
  423.     public void setTransformMatrix (Matrix4 transform) {
  424.         if (drawing) flush();
  425.         transformMatrix.set(transform);
  426.         if (drawing) setupMatrices();
  427.     }
  428.  
  429.     private void setupMatrices () {
  430.         if (!Gdx.graphics.isGL20Available()) {
  431.             GL10 gl = Gdx.gl10;
  432.             gl.glMatrixMode(GL10.GL_PROJECTION);
  433.             gl.glLoadMatrixf(projectionMatrix.val, 0);
  434.             gl.glMatrixMode(GL10.GL_MODELVIEW);
  435.             gl.glLoadMatrixf(transformMatrix.val, 0);
  436.         } else {
  437.             combinedMatrix.set(projectionMatrix).mul(transformMatrix);
  438.             if (customShader != null) {
  439.                 customShader.setUniformMatrix("u_projTrans", combinedMatrix);
  440.                 customShader.setUniformi("u_texture", 0);
  441.                 customShader.setUniformi("u_texture2", 1);
  442.             } else {
  443.                 shader.setUniformMatrix("u_projTrans", combinedMatrix);
  444.                 shader.setUniformi("u_texture", 0);
  445.                 shader.setUniformi("u_texture2", 1);
  446.             }
  447.         }
  448.     }
  449.  
  450.     private void switchTexture (Texture texture) {
  451.         renderMesh();
  452.         lastTexture = texture;
  453.     }
  454.  
  455.     /** Sets the shader to be used in a GLES 2.0 environment. Vertex position attribute is called "a_position", the texture
  456.      * coordinates attribute is called called "a_texCoord0", the color attribute is called "a_color". See
  457.      * {@link ShaderProgram#POSITION_ATTRIBUTE}, {@link ShaderProgram#COLOR_ATTRIBUTE} and {@link ShaderProgram#TEXCOORD_ATTRIBUTE}
  458.      * which gets "0" appened to indicate the use of the first texture unit. The combined transform and projection matrx is is
  459.      * uploaded via a mat4 uniform called "u_projTrans". The texture sampler is passed via a uniform called "u_texture".</p>
  460.      *
  461.      * Call this method with a null argument to use the default shader.</p>
  462.      *
  463.      * This method will flush the batch before setting the new shader, you can call it in between {@link #begin()} and
  464.      * {@link #end()}.
  465.      *
  466.      * @param shader the {@link ShaderProgram} or null to use the default shader. */
  467.     public void setShader (ShaderProgram shader) {
  468.         if (drawing) {
  469.             flush();
  470.             if (customShader != null)
  471.                 customShader.end();
  472.             else
  473.                 this.shader.end();
  474.         }
  475.         customShader = shader;
  476.         if (drawing) {
  477.             if (customShader != null)
  478.                 customShader.begin();
  479.             else
  480.                 this.shader.begin();
  481.             setupMatrices();
  482.         }
  483.     }
  484.  
  485.     /** @return whether blending for sprites is enabled */
  486.     public boolean isBlendingEnabled () {
  487.         return !blendingDisabled;
  488.     }
  489.  
  490.     static public final int X1 = 0;
  491.     static public final int Y1 = 1;
  492.     static public final int C1 = 2;
  493.     static public final int U1 = 3;
  494.     static public final int V1 = 4;
  495.     static public final int R1 = 5;
  496.    
  497.     static public final int X2 = 6;
  498.     static public final int Y2 = 7;
  499.     static public final int C2 = 8;
  500.     static public final int U2 = 9;
  501.     static public final int V2 = 10;
  502.     static public final int R2 = 11;
  503.    
  504.     static public final int X3 = 12;
  505.     static public final int Y3 = 13;
  506.     static public final int C3 = 14;
  507.     static public final int U3 = 15;
  508.     static public final int V3 = 16;
  509.     static public final int R3 = 17;
  510.    
  511.     static public final int X4 = 18;
  512.     static public final int Y4 = 19;
  513.     static public final int C4 = 20;
  514.     static public final int U4 = 21;
  515.     static public final int V4 = 22;
  516.     static public final int R4 = 23;
  517. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement