package com.jme3.audio;
+/**
+ * Used for managing AL (Audio Library) objects.
+ *
+ * @author Kirill Vainer
+ */
public abstract class ALObject {
protected int id = -1;
/**
* An <code>AudioBuffer</code> is an implementation of AudioData
* where the audio is buffered (stored in memory). All parts of it
- * are accessable at any time. <br/>
+ * are accessible at any time. <br/>
* AudioBuffers are useful for short sounds, like effects, etc.
*
- * @author Kirill
+ * @author Kirill Vainer
*/
public class AudioBuffer extends AudioData {
* are to be stored entirely in memory, while long audio files (music) is
* streamed from the hard drive as it is played.
*
- * @author Kirill
+ * @author Kirill Vainer
*/
public abstract class AudioData extends ALObject {
/**
* <code>AudioKey</code> is extending AssetKey by holding stream flag.
*
- * @author Kirill
+ * @author Kirill Vainer
*/
public class AudioKey extends AssetKey<AudioData> {
private boolean stream;
+ private boolean streamCache;
/**
+ * Create a new AudioKey.
+ *
+ * @param name Name of the asset
+ * @param stream If true, the audio will be streamed from harddrive,
+ * otherwise it will be buffered entirely and then played.
+ * @param streamCache If stream is true, then this specifies if
+ * the stream cache is used. When enabled, the audio stream will
+ * be read entirely but not decoded, allowing features such as
+ * seeking, determining duration and looping.
+ */
+ public AudioKey(String name, boolean stream, boolean streamCache){
+ this(name, stream);
+ this.streamCache = streamCache;
+ }
+
+ /**
* Create a new AudioKey
*
* @param name Name of the asset
@Override
public String toString(){
- return name + (stream ? "/S" : "");
+ return name + (stream ?
+ (streamCache ?
+ " (Stream/Cache)" :
+ " (Stream)") :
+ " (Buffer)");
}
+ /**
+ * @return True if the loaded audio should be a {@link AudioStream} or
+ * false if it should be a {@link AudioBuffer}.
+ */
public boolean isStream() {
return stream;
}
+
+ /**
+ * Specifies if the stream cache is used.
+ *
+ * When enabled, the audio stream will
+ * be read entirely but not decoded, allowing features such as
+ * seeking, looping and determining duration.
+ */
+ public boolean useStreamCache(){
+ return streamCache;
+ }
+ @Override
public boolean shouldCache(){
- return !stream;
+ return !stream && !streamCache;
}
@Override
super.write(ex);
OutputCapsule oc = ex.getCapsule(this);
oc.write(stream, "do_stream", false);
+ oc.write(streamCache, "use_stream_cache", false);
}
@Override
super.read(im);
InputCapsule ic = im.getCapsule(this);
stream = ic.readBoolean("do_stream", false);
+ streamCache = ic.readBoolean("use_stream_cache", false);
}
}
* @see AudioNode#setDryFilter(com.jme3.audio.Filter)
*/
public void setReverbFilter(Filter reverbFilter) {
- if (this.reverbFilter != null) {
- throw new IllegalStateException("Filter already set");
- }
-
this.reverbFilter = reverbFilter;
if (channel >= 0)
renderer.updateSourceParam(this, AudioParam.ReverbFilter);
public class AudioStream extends AudioData implements Closeable{
protected InputStream in;
- private float duration = -1f;
- private boolean open = false;
- private int[] ids;
+ protected float duration = -1f;
+ protected boolean open = false;
+ protected int[] ids;
public AudioStream(){
}
throw new RuntimeException("Don't use getId() on streams");
}
+ @Override
public void setId(int id){
throw new RuntimeException("Don't use setId() on streams");
}
names.add(mapping);\r
mapping.triggers.add(hash);\r
} else {\r
- logger.log(Level.WARNING, "Attempted to add mapping '{0}' twice to trigger.", mappingName);\r
+ logger.log(Level.WARNING, "Attempted to add mapping \"{0}\" twice to trigger.", mappingName);\r
}\r
}\r
}\r
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.VertexBuffer.*;
+import com.jme3.scene.mesh.VirtualIndexBuffer;
+import com.jme3.scene.mesh.WrappedIndexBuffer;
import com.jme3.util.BufferUtils;
import com.jme3.util.IntMap;
import com.jme3.util.IntMap.Entry;
public void getTriangle(int index, Vector3f v1, Vector3f v2, Vector3f v3){
VertexBuffer pb = getBuffer(Type.Position);
- VertexBuffer ib = getBuffer(Type.Index);
+ IndexBuffer ib = getIndexBuffer();
+ if (ib == null){
+ ib = new VirtualIndexBuffer(vertCount, mode);
+ }else if (mode != Mode.Triangles){
+ ib = new WrappedIndexBuffer(this);
+ }
+
if (pb.getFormat() == Format.Float){
FloatBuffer fpb = (FloatBuffer) pb.getData();
- if (ib.getFormat() == Format.UnsignedShort){
- // accepted format for buffers
- ShortBuffer sib = (ShortBuffer) ib.getData();
-
- // aquire triangle's vertex indices
- int vertIndex = index * 3;
- int vert1 = sib.get(vertIndex);
- int vert2 = sib.get(vertIndex+1);
- int vert3 = sib.get(vertIndex+2);
+ // aquire triangle's vertex indices
+ int vertIndex = index * 3;
+ int vert1 = ib.get(vertIndex);
+ int vert2 = ib.get(vertIndex+1);
+ int vert3 = ib.get(vertIndex+2);
- BufferUtils.populateFromBuffer(v1, fpb, vert1);
- BufferUtils.populateFromBuffer(v2, fpb, vert2);
- BufferUtils.populateFromBuffer(v3, fpb, vert3);
- }
+ BufferUtils.populateFromBuffer(v1, fpb, vert1);
+ BufferUtils.populateFromBuffer(v2, fpb, vert2);
+ BufferUtils.populateFromBuffer(v3, fpb, vert3);
+
}
}
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
+/**
+ * <code>WrappedIndexBuffer</code> converts from one representation of mesh
+ * data to another. For example it can be used to read TriangleStrip data
+ * as if it was in Triangle format.
+ *
+ * @author Kirill Vainer
+ */
public class WrappedIndexBuffer extends VirtualIndexBuffer {
private final IndexBuffer ib;