Package com.badlogic.gdx.graphics.g3d.particles.batches

Source Code of com.badlogic.gdx.graphics.g3d.particles.batches.BillboardParticleBatch$Config

package com.badlogic.gdx.graphics.g3d.particles.batches;

import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.VertexAttributes;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.g3d.Material;
import com.badlogic.gdx.graphics.g3d.Renderable;
import com.badlogic.gdx.graphics.g3d.Shader;
import com.badlogic.gdx.graphics.g3d.attributes.BlendingAttribute;
import com.badlogic.gdx.graphics.g3d.attributes.DepthTestAttribute;
import com.badlogic.gdx.graphics.g3d.attributes.TextureAttribute;
import com.badlogic.gdx.graphics.g3d.particles.ParallelArray.FloatChannel;
import com.badlogic.gdx.graphics.g3d.particles.ParticleChannels;
import com.badlogic.gdx.graphics.g3d.particles.ParticleShader;
import com.badlogic.gdx.graphics.g3d.particles.ParticleShader.AlignMode;
import com.badlogic.gdx.graphics.g3d.particles.ResourceData;
import com.badlogic.gdx.graphics.g3d.particles.ResourceData.SaveData;
import com.badlogic.gdx.graphics.g3d.particles.renderers.BillboardControllerRenderData;
import com.badlogic.gdx.graphics.g3d.shaders.DefaultShader;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Matrix3;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Pool;


/** This class is used to render billboard particles.
* @author Inferno */
public class BillboardParticleBatch extends BufferedParticleBatch<BillboardControllerRenderData> {
  protected static final Vector3 TMP_V1 = new Vector3(),
     TMP_V2 = new Vector3(),
     TMP_V3 = new Vector3(),
     TMP_V4 = new Vector3(),
     TMP_V5 = new Vector3(),
     TMP_V6 = new Vector3();
  protected static final Matrix3 TMP_M3 = new Matrix3();
  //Attributes 
  protected static final int sizeAndRotationUsage = 1 << 9, directionUsage = 1 << 10;
  private static final VertexAttributes
    GPU_ATTRIBUTES = new VertexAttributes(new VertexAttribute(Usage.Position, 3, ShaderProgram.POSITION_ATTRIBUTE),
                              new VertexAttribute(Usage.TextureCoordinates, 2, ShaderProgram.TEXCOORD_ATTRIBUTE+"0"),
                              new VertexAttribute(Usage.Color, 4, ShaderProgram.COLOR_ATTRIBUTE),
                              new VertexAttribute(sizeAndRotationUsage, 4, "a_sizeAndRotation")),
                              /*
    GPU_EXT_ATTRIBUTES = new VertexAttributes(new VertexAttribute(Usage.Position, 3, ShaderProgram.POSITION_ATTRIBUTE),
                  new VertexAttribute(Usage.TextureCoordinates, 2, ShaderProgram.TEXCOORD_ATTRIBUTE+"0"),
                  new VertexAttribute(Usage.Color, 4, ShaderProgram.COLOR_ATTRIBUTE),
                  new VertexAttribute(sizeAndRotationUsage, 4, "a_sizeAndRotation"),
                  new VertexAttribute(directionUsage, 3, "a_direction")),
                  */
    CPU_ATTRIBUTES = new VertexAttributesnew VertexAttribute(Usage.Position, 3, ShaderProgram.POSITION_ATTRIBUTE),
                              new VertexAttribute(Usage.TextureCoordinates, 2, ShaderProgram.TEXCOORD_ATTRIBUTE+"0"),
                              new VertexAttribute(Usage.Color, 4, ShaderProgram.COLOR_ATTRIBUTE) );
 
  //Offsets
  private static final int   GPU_POSITION_OFFSET = (short)(GPU_ATTRIBUTES.findByUsage(Usage.Position).offset/4),
                    GPU_UV_OFFSET = (short)(GPU_ATTRIBUTES.findByUsage(Usage.TextureCoordinates).offset/4),
                    GPU_SIZE_ROTATION_OFFSET = (short)(GPU_ATTRIBUTES.findByUsage(sizeAndRotationUsage).offset/4),
                    GPU_COLOR_OFFSET = (short)(GPU_ATTRIBUTES.findByUsage(Usage.Color).offset/4),
                    GPU_VERTEX_SIZE = GPU_ATTRIBUTES.vertexSize/4,

                    //Ext
                    /*
                    GPU_EXT_POSITION_OFFSET = (short)(GPU_EXT_ATTRIBUTES.findByUsage(Usage.Position).offset/4),
                    GPU_EXT_UV_OFFSET = (short)(GPU_EXT_ATTRIBUTES.findByUsage(Usage.TextureCoordinates).offset/4),
                    GPU_EXT_SIZE_ROTATION_OFFSET = (short)(GPU_EXT_ATTRIBUTES.findByUsage(sizeAndRotationUsage).offset/4),
                    GPU_EXT_COLOR_OFFSET = (short)(GPU_EXT_ATTRIBUTES.findByUsage(Usage.Color).offset/4),
                    GPU_EXT_DIRECTION_OFFSET = (short)(GPU_EXT_ATTRIBUTES.findByUsage(directionUsage).offset/4),
                    GPU_EXT_VERTEX_SIZE = GPU_EXT_ATTRIBUTES.vertexSize/4,
                    */
                   
                    //Cpu
                    CPU_POSITION_OFFSET = (short)(CPU_ATTRIBUTES.findByUsage(Usage.Position).offset/4),
                    CPU_UV_OFFSET = (short)(CPU_ATTRIBUTES.findByUsage(Usage.TextureCoordinates).offset/4),
                    CPU_COLOR_OFFSET = (short)(CPU_ATTRIBUTES.findByUsage(Usage.Color).offset/4),
                    CPU_VERTEX_SIZE= CPU_ATTRIBUTES.vertexSize/4;
  private final static int   MAX_PARTICLES_PER_MESH = Short.MAX_VALUE/4,
                    MAX_VERTICES_PER_MESH = MAX_PARTICLES_PER_MESH*4;
 
  private class RenderablePool extends Pool<Renderable>{
    public RenderablePool () {}

    @Override
    public Renderable newObject () {
      return allocRenderable();
   
  }
 
  public static class Config{
    public Config(){}
    public Config (boolean useGPU, AlignMode mode) {
      this.useGPU = useGPU;
      this.mode = mode;
    }
    boolean useGPU;
    AlignMode mode;
  }
 
  private RenderablePool renderablePool;
  private Array<Renderable> renderables;
  private float[] vertices;
  private short[] indices;
  private int currentVertexSize = 0;
  private VertexAttributes currentAttributes;
  protected boolean useGPU = false;
  protected AlignMode mode = AlignMode.Screen;
  protected Texture texture;
  Shader shader;
 
  public BillboardParticleBatch(AlignMode mode, boolean useGPU, int capacity){
    super(BillboardControllerRenderData.class);
    renderables = new Array<Renderable>();
    renderablePool = new RenderablePool();
    allocIndices();
    initRenderData();
    ensureCapacity(capacity);
    setUseGpu(useGPU);
    setAlignMode(mode);
  }

  public BillboardParticleBatch () {
    this(AlignMode.Screen, false, 100);
  }
 
  public BillboardParticleBatch (int capacity) {
    this(AlignMode.Screen, false, capacity);
  }

  @Override
  public void allocParticlesData(int capacity){
    vertices = new float[currentVertexSize*4*capacity];
    allocRenderables(capacity);
  }

  protected Renderable allocRenderable(){
    Renderable renderable = new Renderable();
    renderable.primitiveType = GL20.GL_TRIANGLES;
    renderable.meshPartOffset = 0;
    renderable.material = new Materialnew BlendingAttribute(GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA, 1f),
      new DepthTestAttribute(GL20.GL_LEQUAL, false),
      TextureAttribute.createDiffuse(texture));
    renderable.mesh = new Mesh(false, MAX_VERTICES_PER_MESH, MAX_PARTICLES_PER_MESH*6, currentAttributes);
    renderable.mesh.setIndices(indices);
    renderable.shader = shader;
    return renderable;
  }
 
  private void allocIndices(){
    int indicesCount = MAX_PARTICLES_PER_MESH * 6;
    indices = new short[indicesCount];
    for(int i=0, vertex = 0; i < indicesCount; i+=6, vertex+=4){
      indices[i] = (short)vertex;
      indices[i+1] = (short)(vertex+1);
      indices[i+2] = (short)(vertex+2);
      indices[i+3] = (short)(vertex+2);
      indices[i+4] = (short)(vertex+3);
      indices[i+5] = (short)vertex;
    }
  }
 
  private void allocRenderables(int capacity){     
    //Free old meshes
    int   meshCount = MathUtils.ceil( capacity/MAX_PARTICLES_PER_MESH),
        free = renderablePool.getFree();
    if(free < meshCount){
      for(int i=0, left = meshCount - free; i < left;++i)
        renderablePool.free(renderablePool.newObject());
    }
  }
 
  private Shader getShader (Renderable renderable) {
    Shader shader = useGPU   ?   new ParticleShader(renderable, new ParticleShader.Config(mode)) :
                new DefaultShader(renderable);
    shader.init();
    return shader;
  }
 
  private void allocShader () {
    Renderable newRenderable = allocRenderable();
    shader = newRenderable.shader = getShader(newRenderable);
    renderablePool.free(newRenderable);
  }
 
  private void clearRenderablesPool(){
    renderablePool.freeAll(renderables);
    for(int i=0, free = renderablePool.getFree(); i < free; ++i){
      Renderable renderable = renderablePool.obtain();
      renderable.mesh.dispose();
    }
    renderables.clear();
  }
 
  /** Sets vertex attributes and size */
  public void setVertexData(){
    if(useGPU){
      currentAttributes = GPU_ATTRIBUTES;
      currentVertexSize = GPU_VERTEX_SIZE;
      /*
      if(mode == AlignMode.ParticleDirection){
        currentAttributes = GPU_EXT_ATTRIBUTES;
        currentVertexSize = GPU_EXT_VERTEX_SIZE;
      }
      else{
        currentAttributes = GPU_ATTRIBUTES;
        currentVertexSize = GPU_VERTEX_SIZE;
      }
      */
    }
    else {
      currentAttributes = CPU_ATTRIBUTES;
      currentVertexSize = CPU_VERTEX_SIZE;
    }
  }
 
  /** Allocates all the require rendering resources like Renderables,Shaders,Meshes
   *  according to the current batch configuration.*/
  private void initRenderData () {
    setVertexData();
    clearRenderablesPool();
    allocShader();
    resetCapacity();
  }
 
  /** Sets the current align mode.
   *  It will reallocate internal data, use only when necessary. */
  public void setAlignMode(AlignMode mode){
    if(mode != this.mode){
      this.mode = mode;
      if(useGPU){
        initRenderData();
        allocRenderables(bufferedParticlesCount);
      }
    }
  }
 
  public AlignMode getAlignMode(){
    return mode;
  }
 
  /** Sets the current align mode.
  *  It will reallocate internal data, use only when necessary. */
  public void setUseGpu(boolean useGPU){
    if(this.useGPU != useGPU){
      this.useGPU = useGPU;
      initRenderData();
      allocRenderables(bufferedParticlesCount);
    }
  }

  public boolean isUseGPU(){
    return useGPU;
  }
 
  public void setTexture(Texture texture){
    renderablePool.freeAll(renderables);
    renderables.clear();
    for(int i=0, free = renderablePool.getFree(); i < free; ++i){
      Renderable renderable = renderablePool.obtain();
      TextureAttribute attribute = (TextureAttribute) renderable.material.get(TextureAttribute.Diffuse);
      attribute.textureDescription.texture = texture;
    }
    this.texture = texture;
  }
 
  public Texture getTexture () {
    return texture;
  }
 
  @Override
  public void begin () {
    super.begin();
    renderablePool.freeAll(renderables);
    renderables.clear();
  }
 
  //GPU
  //Required + Color + Rotation
  private static void putVertex( float[] vertices,  int offset, float x, float y, float z, float u, float v, float scaleX, float scaleY,  float cosRotation, float sinRotation, float r, float g, float b, float a) {
    //Position
    vertices[offset + GPU_POSITION_OFFSET] = x;
    vertices[offset + GPU_POSITION_OFFSET+1] = y;
    vertices[offset + GPU_POSITION_OFFSET+2] = z;
    //UV
    vertices[offset + GPU_UV_OFFSET] = u;
    vertices[offset + GPU_UV_OFFSET+1] = v;
    //Scale
    vertices[offset + GPU_SIZE_ROTATION_OFFSET] = scaleX;
    vertices[offset + GPU_SIZE_ROTATION_OFFSET+1] = scaleY;
    vertices[offset + GPU_SIZE_ROTATION_OFFSET+2] = cosRotation;
    vertices[offset + GPU_SIZE_ROTATION_OFFSET+3] = sinRotation;
    //Color
    vertices[offset + GPU_COLOR_OFFSET] = r;
    vertices[offset + GPU_COLOR_OFFSET+1] = g;
    vertices[offset + GPU_COLOR_OFFSET+2] = b;
    vertices[offset + GPU_COLOR_OFFSET+3] = a;
  }

  /*
  //Required + Color + Rotation + Direction
  private static void putVertex( float[] vertices,  int offset, float x, float y, float z, float u, float v, float scaleX, float scaleY,  float cosRotation, float sinRotation, float r, float g, float b, float a, Vector3 direction) {
    //Position
    vertices[offset + GPU_EXT_POSITION_OFFSET] = x;
    vertices[offset + GPU_EXT_POSITION_OFFSET+1] = y;
    vertices[offset + GPU_EXT_POSITION_OFFSET+2] = z;
    //UV
    vertices[offset + GPU_EXT_UV_OFFSET] = u;
    vertices[offset + GPU_EXT_UV_OFFSET+1] = v;
    //Scale
    vertices[offset + GPU_EXT_SIZE_ROTATION_OFFSET] = scaleX;
    vertices[offset + GPU_EXT_SIZE_ROTATION_OFFSET+1] = scaleY;
    vertices[offset + GPU_EXT_SIZE_ROTATION_OFFSET+2] = cosRotation;
    vertices[offset + GPU_EXT_SIZE_ROTATION_OFFSET+3] = sinRotation;
    //Color
    vertices[offset + GPU_EXT_COLOR_OFFSET] = r;
    vertices[offset + GPU_EXT_COLOR_OFFSET+1] = g;
    vertices[offset + GPU_EXT_COLOR_OFFSET+2] = b;
    vertices[offset + GPU_EXT_COLOR_OFFSET+3] = a;
    //Direction
    vertices[offset + GPU_EXT_DIRECTION_OFFSET] = direction.x;
    vertices[offset + GPU_EXT_DIRECTION_OFFSET +1] = direction.y;
    vertices[offset + GPU_EXT_DIRECTION_OFFSET +2] = direction.z;
  }
  */
 
 
  //CPU
  //Required
  private static void putVertex(float[] vertices, int offset, Vector3 p, float u, float v, float r, float g, float b, float a) {
    //Position
    vertices[offset + CPU_POSITION_OFFSET] = p.x;
    vertices[offset + CPU_POSITION_OFFSET+1] = p.y;
    vertices[offset + CPU_POSITION_OFFSET+2] = p.z;
    //UV
    vertices[offset + CPU_UV_OFFSET] = u;
    vertices[offset + CPU_UV_OFFSET+1] = v;
    //Color
    vertices[offset + CPU_COLOR_OFFSET] = r;
    vertices[offset + CPU_COLOR_OFFSET+1] = g;
    vertices[offset + CPU_COLOR_OFFSET+2] = b;
    vertices[offset + CPU_COLOR_OFFSET+3] = a;
  }

  private void fillVerticesGPU (int[] particlesOffset) {
    int tp=0;
    for(BillboardControllerRenderData data : renderData){
      FloatChannel scaleChannel = data.scaleChannel;
      FloatChannel regionChannel = data.regionChannel;
      FloatChannel positionChannel = data.positionChannel;
      FloatChannel colorChannel = data.colorChannel;
      FloatChannel rotationChannel = data.rotationChannel;
      for(int p=0, c = data.controller.particles.size; p < c; ++p, ++tp){
        int baseOffset = particlesOffset[tp]*currentVertexSize*4;
        float scale = scaleChannel.data[p* scaleChannel.strideSize];
        int regionOffset = p*regionChannel.strideSize;
        int positionOffset = p*positionChannel.strideSize;
        int colorOffset = p*colorChannel.strideSize;
        int rotationOffset = p*rotationChannel.strideSize;
        float   px = positionChannel.data[positionOffset + ParticleChannels.XOffset],
          py = positionChannel.data[positionOffset + ParticleChannels.YOffset],
          pz = positionChannel.data[positionOffset + ParticleChannels.ZOffset];
        float u = regionChannel.data[regionOffset +ParticleChannels.UOffset];
        float v = regionChannel.data[regionOffset +ParticleChannels.VOffset];
        float u2 = regionChannel.data[regionOffset +ParticleChannels.U2Offset];
        float v2 = regionChannel.data[regionOffset +ParticleChannels.V2Offset];
        float   sx = regionChannel.data[regionOffset +ParticleChannels.HalfWidthOffset] * scale,
              sy = regionChannel.data[regionOffset+ParticleChannels.HalfHeightOffset* scale;
        float r = colorChannel.data[colorOffset +ParticleChannels.RedOffset];
        float g = colorChannel.data[colorOffset +ParticleChannels.GreenOffset];
        float b = colorChannel.data[colorOffset +ParticleChannels.BlueOffset];
        float a = colorChannel.data[colorOffset +ParticleChannels.AlphaOffset];
        float cosRotation = rotationChannel.data[rotationOffset +ParticleChannels.CosineOffset];
        float sinRotation = rotationChannel.data[rotationOffset +ParticleChannels.SineOffset];

        //bottom left, bottom right, top right, top left
        putVertex(vertices, baseOffset, px, py, pz, u, v2, -sx, -sy, cosRotation, sinRotation, r, g, b, a);
        baseOffset += currentVertexSize;
        putVertex(vertices, baseOffset, px, py, pz, u2, v2, sx, -sy, cosRotation, sinRotation, r, g, b, a);
        baseOffset += currentVertexSize;
        putVertex(vertices, baseOffset, px, py, pz, u2, v, sx, sy, cosRotation, sinRotation, r, g, b, a);
        baseOffset += currentVertexSize;
        putVertex(vertices, baseOffset, px, py, pz, u, v, -sx, sy, cosRotation, sinRotation, r, g, b, a);
        baseOffset += currentVertexSize;
      }
    }
  }

  /*
  private void fillVerticesToParticleDirectionGPU (int[] particlesOffset) {
    int tp=0;
    for(BillboardControllerRenderData data : renderData){
      FloatChannel scaleChannel = data.scaleChannel;
      FloatChannel regionChannel = data.regionChannel;
      FloatChannel positionChannel = data.positionChannel;
      FloatChannel colorChannel = data.colorChannel;
      FloatChannel rotationChannel = data.rotationChannel;

      for(int p=0, c = data.controller.particles.size; p < c; ++p, ++tp){
        int baseOffset = particlesOffset[tp]*currentVertexSize*4;
        float scale = scaleChannel.data[p* scaleChannel.strideSize];
        int regionOffset = p*regionChannel.strideSize;
        int positionOffset = p*positionChannel.strideSize;
        int colorOffset = p*colorChannel.strideSize;
        int rotationOffset = p*rotationChannel.strideSize;
        int velocityOffset = p* velocityChannel.strideSize;
        float   px = positionChannel.data[positionOffset + ParticleChannels.XOffset],
          py = positionChannel.data[positionOffset + ParticleChannels.YOffset],
          pz = positionChannel.data[positionOffset + ParticleChannels.ZOffset];
        float u = regionChannel.data[regionOffset +ParticleChannels.UOffset];
        float v = regionChannel.data[regionOffset +ParticleChannels.VOffset];
        float u2 = regionChannel.data[regionOffset +ParticleChannels.U2Offset];
        float v2 = regionChannel.data[regionOffset +ParticleChannels.V2Offset];
        float   sx = regionChannel.data[regionOffset +ParticleChannels.HalfWidthOffset] * scale,
              sy = regionChannel.data[regionOffset+ParticleChannels.HalfHeightOffset]  * scale;
        float r = colorChannel.data[colorOffset +ParticleChannels.RedOffset];
        float g = colorChannel.data[colorOffset +ParticleChannels.GreenOffset];
        float b = colorChannel.data[colorOffset +ParticleChannels.BlueOffset];
        float a = colorChannel.data[colorOffset +ParticleChannels.AlphaOffset];
        float cosRotation = rotationChannel.data[rotationOffset +ParticleChannels.CosineOffset];
        float sinRotation = rotationChannel.data[rotationOffset +ParticleChannels.SineOffset];
        float   vx = velocityChannel.data[velocityOffset + ParticleChannels.XOffset],
              vy = velocityChannel.data[velocityOffset + ParticleChannels.YOffset],
              vz = velocityChannel.data[velocityOffset + ParticleChannels.ZOffset];
       
        //bottom left, bottom right, top right, top left
        TMP_V1.set(vx, vy, vz).nor();
        putVertex(vertices, baseOffset, px, py, pz, u, v2, -sx, -sy, cosRotation, sinRotation, r, g, b, a, TMP_V1);
        baseOffset += currentVertexSize;
        putVertex(vertices, baseOffset, px, py, pz, u2, v2, sx, -sy, cosRotation, sinRotation, r, g, b, a, TMP_V1);
        baseOffset += currentVertexSize;
        putVertex(vertices, baseOffset, px, py, pz, u2, v, sx, sy, cosRotation, sinRotation, r, g, b, a, TMP_V1);
        baseOffset += currentVertexSize;
        putVertex(vertices, baseOffset, px, py, pz, u, v, -sx, sy, cosRotation, sinRotation, r, g, b, a, TMP_V1);
      }
    }
  }
 
  private void fillVerticesToParticleDirectionCPU (int[] particlesOffset) {
    int tp=0;
    for(ParticleController controller : renderData){
      FloatChannel scaleChannel = controller.particles.getChannel(ParticleChannels.Scale);
      FloatChannel regionChannel = controller.particles.getChannel(ParticleChannels.TextureRegion);
      FloatChannel positionChannel = controller.particles.getChannel(ParticleChannels.Position);
      FloatChannel colorChannel = controller.particles.getChannel(ParticleChannels.Color);
      FloatChannel rotationChannel = controller.particles.getChannel(ParticleChannels.Rotation2D);
      FloatChannel velocityChannel = controller.particles.getChannel(ParticleChannels.Accelleration);

      for(int p=0, c = controller.particles.size; p < c; ++p, ++tp){
        int baseOffset = particlesOffset[tp]*currentVertexSize*4;
        float scale = scaleChannel.data[p* scaleChannel.strideSize];
        int regionOffset = p*regionChannel.strideSize;
        int positionOffset = p*positionChannel.strideSize;
        int colorOffset = p*colorChannel.strideSize;
        int rotationOffset = p*rotationChannel.strideSize;
        int velocityOffset = p* velocityChannel.strideSize;
        float   px = positionChannel.data[positionOffset + ParticleChannels.XOffset],
          py = positionChannel.data[positionOffset + ParticleChannels.YOffset],
          pz = positionChannel.data[positionOffset + ParticleChannels.ZOffset];
        float u = regionChannel.data[regionOffset +ParticleChannels.UOffset];
        float v = regionChannel.data[regionOffset +ParticleChannels.VOffset];
        float u2 = regionChannel.data[regionOffset +ParticleChannels.U2Offset];
        float v2 = regionChannel.data[regionOffset +ParticleChannels.V2Offset];
        float   sx = regionChannel.data[regionOffset +ParticleChannels.HalfWidthOffset] * scale,
              sy = regionChannel.data[regionOffset+ParticleChannels.HalfHeightOffset]  * scale;
        float r = colorChannel.data[colorOffset +ParticleChannels.RedOffset];
        float g = colorChannel.data[colorOffset +ParticleChannels.GreenOffset];
        float b = colorChannel.data[colorOffset +ParticleChannels.BlueOffset];
        float a = colorChannel.data[colorOffset +ParticleChannels.AlphaOffset];
        float cosRotation = rotationChannel.data[rotationOffset +ParticleChannels.CosineOffset];
        float sinRotation = rotationChannel.data[rotationOffset +ParticleChannels.SineOffset];
        float   vx = velocityChannel.data[velocityOffset + ParticleChannels.XOffset],
              vy = velocityChannel.data[velocityOffset + ParticleChannels.YOffset],
              vz = velocityChannel.data[velocityOffset + ParticleChannels.ZOffset];
        Vector3 up = TMP_V1.set(vx,vy,vz).nor(),   
                look = TMP_V3.set(camera.position).sub(px,py,pz).nor(), //normal
                right = TMP_V2.set(up).crs(look).nor(); //tangent
        look.set(right).crs(up).nor();
        right.scl(sx);
        up.scl(sy);

        if(cosRotation != 1){
          TMP_M3.setToRotation(look, cosRotation, sinRotation);
          putVertex(vertices, baseOffset, TMP_V6.set(-TMP_V1.x-TMP_V2.x, -TMP_V1.y-TMP_V2.y, -TMP_V1.z-TMP_V2.z).mul(TMP_M3).add(px, py, pz), u, v2, r, g, b, a);
          baseOffset += currentVertexSize;
          putVertex(vertices, baseOffset,TMP_V6.set(TMP_V1.x-TMP_V2.x, TMP_V1.y-TMP_V2.y, TMP_V1.z-TMP_V2.z).mul(TMP_M3).add(px, py, pz), u2, v2, r, g, b, a);
          baseOffset += currentVertexSize;
          putVertex(vertices, baseOffset,TMP_V6.set(TMP_V1.x+TMP_V2.x, TMP_V1.y+TMP_V2.y, TMP_V1.z+TMP_V2.z).mul(TMP_M3).add(px, py, pz), u2, v, r, g, b, a);
          baseOffset += currentVertexSize;
          putVertex(vertices, baseOffset, TMP_V6.set(-TMP_V1.x+TMP_V2.x, -TMP_V1.y+TMP_V2.y, -TMP_V1.z+TMP_V2.z).mul(TMP_M3).add(px, py, pz), u, v, r, g, b, a);
        }
        else {
          putVertex(vertices, baseOffset,TMP_V6.set(-TMP_V1.x-TMP_V2.x+px, -TMP_V1.y-TMP_V2.y+py, -TMP_V1.z-TMP_V2.z+pz), u, v2, r, g, b, a);
          baseOffset += currentVertexSize;
          putVertex(vertices, baseOffset,TMP_V6.set(TMP_V1.x-TMP_V2.x+px, TMP_V1.y-TMP_V2.y+py, TMP_V1.z-TMP_V2.z+pz), u2, v2, r, g, b, a);
          baseOffset += currentVertexSize;
          putVertex(vertices, baseOffset,TMP_V6.set(TMP_V1.x+TMP_V2.x+px, TMP_V1.y+TMP_V2.y+py, TMP_V1.z+TMP_V2.z+pz), u2, v, r, g, b, a);
          baseOffset += currentVertexSize;
          putVertex(vertices, baseOffset, TMP_V6.set(-TMP_V1.x+TMP_V2.x+px, -TMP_V1.y+TMP_V2.y+py, -TMP_V1.z+TMP_V2.z+pz), u, v, r, g, b, a);
        }
      }
    }
  }
  */

  private void fillVerticesToViewPointCPU (int[] particlesOffset) {
    int tp=0;
    for(BillboardControllerRenderData data : renderData){
      FloatChannel scaleChannel = data.scaleChannel;
      FloatChannel regionChannel = data.regionChannel;
      FloatChannel positionChannel = data.positionChannel;
      FloatChannel colorChannel = data.colorChannel;
      FloatChannel rotationChannel = data.rotationChannel;

      for(int p=0, c = data.controller.particles.size; p < c; ++p, ++tp){
        int baseOffset = particlesOffset[tp]*currentVertexSize*4;
        float scale = scaleChannel.data[p* scaleChannel.strideSize];
        int regionOffset = p*regionChannel.strideSize;
        int positionOffset = p*positionChannel.strideSize;
        int colorOffset = p*colorChannel.strideSize;
        int rotationOffset = p*rotationChannel.strideSize;
        float   px = positionChannel.data[positionOffset + ParticleChannels.XOffset],
          py = positionChannel.data[positionOffset + ParticleChannels.YOffset],
          pz = positionChannel.data[positionOffset + ParticleChannels.ZOffset];
        float u = regionChannel.data[regionOffset +ParticleChannels.UOffset];
        float v = regionChannel.data[regionOffset +ParticleChannels.VOffset];
        float u2 = regionChannel.data[regionOffset +ParticleChannels.U2Offset];
        float v2 = regionChannel.data[regionOffset +ParticleChannels.V2Offset];
        float   sx = regionChannel.data[regionOffset +ParticleChannels.HalfWidthOffset] * scale,
              sy = regionChannel.data[regionOffset+ParticleChannels.HalfHeightOffset* scale;
        float r = colorChannel.data[colorOffset +ParticleChannels.RedOffset];
        float g = colorChannel.data[colorOffset +ParticleChannels.GreenOffset];
        float b = colorChannel.data[colorOffset +ParticleChannels.BlueOffset];
        float a = colorChannel.data[colorOffset +ParticleChannels.AlphaOffset];
        float cosRotation = rotationChannel.data[rotationOffset +ParticleChannels.CosineOffset];
        float sinRotation = rotationChannel.data[rotationOffset +ParticleChannels.SineOffset];
        Vector3 look = TMP_V3.set(camera.position).sub(px, py, pz).nor(), //normal
                right = TMP_V1.set(camera.up).crs(look).nor(), //tangent
                up = TMP_V2.set(look).crs(right);
        right.scl(sx);
        up.scl(sy);

        if(cosRotation != 1){
          TMP_M3.setToRotation(look, cosRotation, sinRotation);
          putVertex(vertices, baseOffset, TMP_V6.set(-TMP_V1.x-TMP_V2.x, -TMP_V1.y-TMP_V2.y, -TMP_V1.z-TMP_V2.z).mul(TMP_M3).add(px, py, pz), u, v2, r, g, b, a);
          baseOffset += currentVertexSize;
          putVertex(vertices, baseOffset, TMP_V6.set(TMP_V1.x-TMP_V2.x, TMP_V1.y-TMP_V2.y, TMP_V1.z-TMP_V2.z).mul(TMP_M3).add(px, py, pz), u2, v2, r, g, b, a);
          baseOffset += currentVertexSize;
          putVertex(vertices, baseOffset, TMP_V6.set(TMP_V1.x+TMP_V2.x, TMP_V1.y+TMP_V2.y, TMP_V1.z+TMP_V2.z).mul(TMP_M3).add(px, py, pz), u2, v, r, g, b, a);
          baseOffset += currentVertexSize;
          putVertex(vertices, baseOffset, TMP_V6.set(-TMP_V1.x+TMP_V2.x, -TMP_V1.y+TMP_V2.y, -TMP_V1.z+TMP_V2.z).mul(TMP_M3).add(px, py, pz), u, v, r, g, b, a);
        }
        else {
          putVertex(vertices, baseOffset, TMP_V6.set(-TMP_V1.x-TMP_V2.x+px, -TMP_V1.y-TMP_V2.y+py, -TMP_V1.z-TMP_V2.z+pz), u, v2, r, g, b, a);
          baseOffset += currentVertexSize;
          putVertex(vertices, baseOffset, TMP_V6.set(TMP_V1.x-TMP_V2.x+px, TMP_V1.y-TMP_V2.y+py, TMP_V1.z-TMP_V2.z+pz), u2, v2, r, g, b, a);
          baseOffset += currentVertexSize;
          putVertex(vertices, baseOffset, TMP_V6.set(TMP_V1.x+TMP_V2.x+px, TMP_V1.y+TMP_V2.y+py, TMP_V1.z+TMP_V2.z+pz), u2, v, r, g, b, a);
          baseOffset += currentVertexSize;
          putVertex(vertices, baseOffset, TMP_V6.set(-TMP_V1.x+TMP_V2.x+px, -TMP_V1.y+TMP_V2.y+py, -TMP_V1.z+TMP_V2.z+pz), u, v, r, g, b, a);
        }
      }
    }
  }

  private void fillVerticesToScreenCPU (int[] particlesOffset) {
    Vector3 look = TMP_V3.set(camera.direction).scl(-1)//normal
      right = TMP_V4.set(camera.up).crs(look).nor(), //tangent
      up = camera.up;

    int tp=0;
    for(BillboardControllerRenderData data : renderData){
      FloatChannel scaleChannel = data.scaleChannel;
      FloatChannel regionChannel = data.regionChannel;
      FloatChannel positionChannel = data.positionChannel;
      FloatChannel colorChannel = data.colorChannel;
      FloatChannel rotationChannel = data.rotationChannel;

      for(int p=0, c = data.controller.particles.size; p < c; ++p, ++tp){
        int baseOffset = particlesOffset[tp]*currentVertexSize*4;
        float scale = scaleChannel.data[p* scaleChannel.strideSize];
        int regionOffset = p*regionChannel.strideSize;
        int positionOffset = p*positionChannel.strideSize;
        int colorOffset = p*colorChannel.strideSize;
        int rotationOffset = p*rotationChannel.strideSize;
        float   px = positionChannel.data[positionOffset + ParticleChannels.XOffset],
          py = positionChannel.data[positionOffset + ParticleChannels.YOffset],
          pz = positionChannel.data[positionOffset + ParticleChannels.ZOffset];
        float u = regionChannel.data[regionOffset +ParticleChannels.UOffset];
        float v = regionChannel.data[regionOffset +ParticleChannels.VOffset];
        float u2 = regionChannel.data[regionOffset +ParticleChannels.U2Offset];
        float v2 = regionChannel.data[regionOffset +ParticleChannels.V2Offset];
        float   sx = regionChannel.data[regionOffset +ParticleChannels.HalfWidthOffset] * scale,
              sy = regionChannel.data[regionOffset+ParticleChannels.HalfHeightOffset* scale;
        float r = colorChannel.data[colorOffset +ParticleChannels.RedOffset];
        float g = colorChannel.data[colorOffset +ParticleChannels.GreenOffset];
        float b = colorChannel.data[colorOffset +ParticleChannels.BlueOffset];
        float a = colorChannel.data[colorOffset +ParticleChannels.AlphaOffset];
        float cosRotation = rotationChannel.data[rotationOffset +ParticleChannels.CosineOffset];
        float sinRotation = rotationChannel.data[rotationOffset +ParticleChannels.SineOffset];
        TMP_V1.set(right).scl(sx);
        TMP_V2.set(up).scl(sy);

        if(cosRotation != 1){
          TMP_M3.setToRotation(look, cosRotation, sinRotation);
          putVertex( vertices, baseOffset, TMP_V6.set(-TMP_V1.x-TMP_V2.x, -TMP_V1.y-TMP_V2.y, -TMP_V1.z-TMP_V2.z).mul(TMP_M3).add(px, py, pz), u, v2, r, g, b, a);
          baseOffset += currentVertexSize;
          putVertex(vertices, baseOffset, TMP_V6.set(TMP_V1.x-TMP_V2.x, TMP_V1.y-TMP_V2.y, TMP_V1.z-TMP_V2.z).mul(TMP_M3).add(px, py, pz), u2, v2, r, g, b, a);
          baseOffset += currentVertexSize;
          putVertex(vertices, baseOffset, TMP_V6.set(TMP_V1.x+TMP_V2.x, TMP_V1.y+TMP_V2.y, TMP_V1.z+TMP_V2.z).mul(TMP_M3).add(px, py, pz), u2, v, r, g, b, a);
          baseOffset += currentVertexSize;
          putVertex(vertices, baseOffset, TMP_V6.set(-TMP_V1.x+TMP_V2.x, -TMP_V1.y+TMP_V2.y, -TMP_V1.z+TMP_V2.z).mul(TMP_M3).add(px, py, pz), u, v, r, g, b, a);
        }
        else {
          putVertex(vertices, baseOffset, TMP_V6.set(-TMP_V1.x-TMP_V2.x+px, -TMP_V1.y-TMP_V2.y+py, -TMP_V1.z-TMP_V2.z+pz), u, v2, r, g, b, a);
          baseOffset += currentVertexSize;
          putVertex(vertices, baseOffset, TMP_V6.set(TMP_V1.x-TMP_V2.x+px, TMP_V1.y-TMP_V2.y+py, TMP_V1.z-TMP_V2.z+pz), u2, v2, r, g, b, a);
          baseOffset += currentVertexSize;
          putVertex(vertices, baseOffset, TMP_V6.set(TMP_V1.x+TMP_V2.x+px, TMP_V1.y+TMP_V2.y+py, TMP_V1.z+TMP_V2.z+pz), u2, v, r, g, b, a);
          baseOffset += currentVertexSize;
          putVertex(vertices, baseOffset, TMP_V6.set(-TMP_V1.x+TMP_V2.x+px, -TMP_V1.y+TMP_V2.y+py, -TMP_V1.z+TMP_V2.z+pz), u, v, r, g, b, a);
        }
      }
    }
  }
 
  @Override
  protected void flush(int[] offsets){
   
    //fill vertices
    if(useGPU){
      //if(mode != AlignMode.ParticleDirection)
        fillVerticesGPU(offsets);
      //else
        //fillVerticesToParticleDirectionGPU(offsets);
    }
    else {
      if(mode == AlignMode.Screen)
        fillVerticesToScreenCPU(offsets);
      else if(mode == AlignMode.ViewPoint)
        fillVerticesToViewPointCPU(offsets);
      //else
        //fillVerticesToParticleDirectionCPU(offsets);
    }
     
    //send vertices to meshes
    int addedVertexCount = 0;
    int vCount = bufferedParticlesCount*4;
    for(int v = 0; v < vCount; v += addedVertexCount){
      addedVertexCount = Math.min(vCount-v, MAX_VERTICES_PER_MESH);
      Renderable renderable = renderablePool.obtain();
      renderable.meshPartSize = (addedVertexCount/4)*6;
      renderable.mesh.setVertices(vertices, currentVertexSize *v, currentVertexSize * addedVertexCount);
      renderables.add(renderable);
    }
  }

  @Override
  public void getRenderables (Array<Renderable> renderables, Pool<Renderable> pool) {
      for(Renderable renderable : this.renderables)
        renderables.add(pool.obtain().set(renderable));
  }

  @Override
  public void save (AssetManager manager, ResourceData resources) {
    SaveData data = resources.createSaveData("billboardBatch");
    data.save("cfg", new Config(useGPU, mode));
    data.saveAsset(manager.getAssetFileName(texture), Texture.class);
  }

  @Override
  public void load (AssetManager manager, ResourceData resources) {
    SaveData data = resources.getSaveData("billboardBatch");
    if(data != null){
      setTexture((Texture)manager.get(data.loadAsset()));
      Config cfg = (Config)data.load("cfg");
      setUseGpu(cfg.useGPU);
      setAlignMode(cfg.mode);
    }
  }
}
TOP

Related Classes of com.badlogic.gdx.graphics.g3d.particles.batches.BillboardParticleBatch$Config

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.