All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.badlogic.gdx.graphics.g3d.decals.DecalBatch Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright 2011 See AUTHORS file.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/

package com.badlogic.gdx.graphics.g3d.decals;

import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.VertexAttributes;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Disposable;
import com.badlogic.gdx.utils.Pool;
import com.badlogic.gdx.utils.SortedIntList;

/** 

* Renderer for {@link Decal} objects. *

*

* New objects are added using {@link DecalBatch#add(Decal)}, there is no limit on how many decals can be added.
* Once all the decals have been submitted a call to {@link DecalBatch#flush()} will batch them together and send big chunks of * geometry to the GL. *

*

* The size of the batch specifies the maximum number of decals that can be batched together before they have to be submitted to * the graphics pipeline. The default size is {@link DecalBatch#DEFAULT_SIZE}. If it is known before hand that not as many will be * needed on average the batch can be downsized to save memory. If the game is basically 3d based and decals will only be needed * for an orthogonal HUD it makes sense to tune the size down. *

*

* The way the batch handles things depends on the {@link GroupStrategy}. Different strategies can be used to customize shaders, * states, culling etc. for more details see the {@link GroupStrategy} java doc.
* While it shouldn't be necessary to change strategies, if you have to do so, do it before calling {@link #add(Decal)}, and if * you already did, call {@link #flush()} first. *

*/ public class DecalBatch implements Disposable { private static final int DEFAULT_SIZE = 1000; private float[] vertices; private Mesh mesh; private final SortedIntList> groupList = new SortedIntList>(); private GroupStrategy groupStrategy; private final Pool> groupPool = new Pool>(16) { @Override protected Array newObject () { return new Array(false, 100); } }; private final Array> usedGroups = new Array>(16); /** Creates a new batch using the {@link DefaultGroupStrategy} */ public DecalBatch () { this(DEFAULT_SIZE, new DefaultGroupStrategy()); } public DecalBatch (GroupStrategy groupStrategy) { this(DEFAULT_SIZE, groupStrategy); } public DecalBatch (int size, GroupStrategy groupStrategy) { initialize(size); setGroupStrategy(groupStrategy); } /** Sets the {@link GroupStrategy} used * @param groupStrategy Group strategy to use */ public void setGroupStrategy (GroupStrategy groupStrategy) { this.groupStrategy = groupStrategy; } /** Initializes the batch with the given amount of decal objects the buffer is able to hold when full. * * @param size Maximum size of decal objects to hold in memory */ public void initialize (int size) { vertices = new float[size * Decal.SIZE]; mesh = new Mesh(Mesh.VertexDataType.VertexArray, false, size * 4, size * 6, new VertexAttribute( VertexAttributes.Usage.Position, 3, ShaderProgram.POSITION_ATTRIBUTE), new VertexAttribute( VertexAttributes.Usage.ColorPacked, 4, ShaderProgram.COLOR_ATTRIBUTE), new VertexAttribute( VertexAttributes.Usage.TextureCoordinates, 2, ShaderProgram.TEXCOORD_ATTRIBUTE + "0")); short[] indices = new short[size * 6]; int v = 0; for (int i = 0; i < indices.length; i += 6, v += 4) { indices[i] = (short)(v); indices[i + 1] = (short)(v + 2); indices[i + 2] = (short)(v + 1); indices[i + 3] = (short)(v + 1); indices[i + 4] = (short)(v + 2); indices[i + 5] = (short)(v + 3); } mesh.setIndices(indices); } /** @return maximum amount of decal objects this buffer can hold in memory */ public int getSize () { return vertices.length / Decal.SIZE; } /** Add a decal to the batch, marking it for later rendering * * @param decal Decal to add for rendering */ public void add (Decal decal) { DecalMaterial material = decal.getMaterial(); int groupIndex = groupStrategy.decideGroup(decal); Array targetGroup = groupList.get(groupIndex); if (targetGroup == null) { targetGroup = groupPool.obtain(); targetGroup.clear(); usedGroups.add(targetGroup); groupList.insert(groupIndex, targetGroup); } targetGroup.add(decal); } /** Flush this batch sending all contained decals to GL. After flushing the batch is empty once again. */ public void flush () { render(); clear(); } /** Renders all decals to the buffer and flushes the buffer to the GL when full/done */ protected void render () { groupStrategy.beforeGroups(); for (SortedIntList.Node> group : groupList) { groupStrategy.beforeGroup(group.index, group.value); ShaderProgram shader = groupStrategy.getGroupShader(group.index); render(shader, group.value); groupStrategy.afterGroup(group.index); } groupStrategy.afterGroups(); } /** Renders a group of vertices to the buffer, flushing them to GL when done/full * * @param decals Decals to render */ private void render (ShaderProgram shader, Array decals) { // batch vertices DecalMaterial lastMaterial = null; int idx = 0; for (Decal decal : decals) { if (lastMaterial == null || !lastMaterial.equals(decal.getMaterial())) { if (idx > 0) { flush(shader, idx); idx = 0; } decal.material.set(); lastMaterial = decal.material; } decal.update(); System.arraycopy(decal.vertices, 0, vertices, idx, decal.vertices.length); idx += decal.vertices.length; // if our batch is full we have to flush it if (idx == vertices.length) { flush(shader, idx); idx = 0; } } // at the end if there is stuff left in the batch we render that if (idx > 0) { flush(shader, idx); } } /** Flushes vertices[0,verticesPosition[ to GL verticesPosition % Decal.SIZE must equal 0 * * @param verticesPosition Amount of elements from the vertices array to flush */ protected void flush (ShaderProgram shader, int verticesPosition) { mesh.setVertices(vertices, 0, verticesPosition); if (shader != null) { mesh.render(shader, GL10.GL_TRIANGLES, 0, verticesPosition / 4); } else { mesh.render(GL10.GL_TRIANGLES, 0, verticesPosition / 4); } } /** Remove all decals from batch */ protected void clear () { groupList.clear(); groupPool.free(usedGroups); usedGroups.clear(); } /** Frees up memory by dropping the buffer and underlying resources. If the batch is needed again after disposing it can be * {@link #initialize(int) initialized} again. */ public void dispose () { clear(); vertices = null; mesh.dispose(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy