1 /* 2 * Copyright (c) 2009-2010 jMonkeyEngine 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 package com.jme3.effect; 34 35 import com.jme3.math.FastMath; 36 import com.jme3.math.Matrix3f; 37 import com.jme3.math.Vector3f; 38 import com.jme3.renderer.Camera; 39 import com.jme3.scene.VertexBuffer; 40 import com.jme3.scene.VertexBuffer.Format; 41 import com.jme3.scene.VertexBuffer.Usage; 42 import com.jme3.util.BufferUtils; 43 import com.jme3.util.SortUtil; 44 import java.nio.ByteBuffer; 45 import java.nio.FloatBuffer; 46 import java.nio.ShortBuffer; 47 48 public class ParticleTriMesh extends ParticleMesh { 49 50 private int imagesX = 1; 51 private int imagesY = 1; 52 private boolean uniqueTexCoords = false; 53 private ParticleComparator comparator = new ParticleComparator(); 54 private ParticleEmitter emitter; 55 private Particle[] particlesCopy; 56 57 @Override 58 public void initParticleData(ParticleEmitter emitter, int numParticles) { 59 setMode(Mode.Triangles); 60 61 this.emitter = emitter; 62 63 particlesCopy = new Particle[numParticles]; 64 65 // set positions 66 FloatBuffer pb = BufferUtils.createVector3Buffer(numParticles * 4); 67 VertexBuffer pvb = new VertexBuffer(VertexBuffer.Type.Position); 68 pvb.setupData(Usage.Stream, 3, Format.Float, pb); 69 70 //if the buffer is already set only update the data 71 VertexBuffer buf = getBuffer(VertexBuffer.Type.Position); 72 if (buf != null) { 73 buf.updateData(pb); 74 } else { 75 setBuffer(pvb); 76 } 77 78 // set colors 79 ByteBuffer cb = BufferUtils.createByteBuffer(numParticles * 4 * 4); 80 VertexBuffer cvb = new VertexBuffer(VertexBuffer.Type.Color); 81 cvb.setupData(Usage.Stream, 4, Format.UnsignedByte, cb); 82 cvb.setNormalized(true); 83 84 buf = getBuffer(VertexBuffer.Type.Color); 85 if (buf != null) { 86 buf.updateData(cb); 87 } else { 88 setBuffer(cvb); 89 } 90 91 // set texcoords 92 VertexBuffer tvb = new VertexBuffer(VertexBuffer.Type.TexCoord); 93 FloatBuffer tb = BufferUtils.createVector2Buffer(numParticles * 4); 94 95 uniqueTexCoords = false; 96 for (int i = 0; i < numParticles; i++){ 97 tb.put(0f).put(1f); 98 tb.put(1f).put(1f); 99 tb.put(0f).put(0f); 100 tb.put(1f).put(0f); 101 } 102 tb.flip(); 103 tvb.setupData(Usage.Static, 2, Format.Float, tb); 104 105 buf = getBuffer(VertexBuffer.Type.TexCoord); 106 if (buf != null) { 107 buf.updateData(tb); 108 } else { 109 setBuffer(tvb); 110 } 111 112 // set indices 113 ShortBuffer ib = BufferUtils.createShortBuffer(numParticles * 6); 114 for (int i = 0; i < numParticles; i++){ 115 int startIdx = (i * 4); 116 117 // triangle 1 118 ib.put((short)(startIdx + 1)) 119 .put((short)(startIdx + 0)) 120 .put((short)(startIdx + 2)); 121 122 // triangle 2 123 ib.put((short)(startIdx + 1)) 124 .put((short)(startIdx + 2)) 125 .put((short)(startIdx + 3)); 126 } 127 ib.flip(); 128 129 VertexBuffer ivb = new VertexBuffer(VertexBuffer.Type.Index); 130 ivb.setupData(Usage.Static, 3, Format.UnsignedShort, ib); 131 132 buf = getBuffer(VertexBuffer.Type.Index); 133 if (buf != null) { 134 buf.updateData(ib); 135 } else { 136 setBuffer(ivb); 137 } 138 139 } 140 141 @Override 142 public void setImagesXY(int imagesX, int imagesY) { 143 this.imagesX = imagesX; 144 this.imagesY = imagesY; 145 if (imagesX != 1 || imagesY != 1){ 146 uniqueTexCoords = true; 147 getBuffer(VertexBuffer.Type.TexCoord).setUsage(Usage.Stream); 148 } 149 } 150 151 @Override 152 public void updateParticleData(Particle[] particles, Camera cam, Matrix3f inverseRotation) { 153 System.arraycopy(particles, 0, particlesCopy, 0, particlesCopy.length); 154 comparator.setCamera(cam); 155 // Arrays.sort(particlesCopy, comparator); 156 // SortUtil.qsort(particlesCopy, comparator); 157 SortUtil.msort(particles, particlesCopy, comparator); 158 particles = particlesCopy; 159 160 VertexBuffer pvb = getBuffer(VertexBuffer.Type.Position); 161 FloatBuffer positions = (FloatBuffer) pvb.getData(); 162 163 VertexBuffer cvb = getBuffer(VertexBuffer.Type.Color); 164 ByteBuffer colors = (ByteBuffer) cvb.getData(); 165 166 VertexBuffer tvb = getBuffer(VertexBuffer.Type.TexCoord); 167 FloatBuffer texcoords = (FloatBuffer) tvb.getData(); 168 169 Vector3f camUp = cam.getUp(); 170 Vector3f camLeft = cam.getLeft(); 171 Vector3f camDir = cam.getDirection(); 172 173 inverseRotation.multLocal(camUp); 174 inverseRotation.multLocal(camLeft); 175 inverseRotation.multLocal(camDir); 176 177 boolean facingVelocity = emitter.isFacingVelocity(); 178 179 Vector3f up = new Vector3f(), 180 left = new Vector3f(); 181 182 if (!facingVelocity){ 183 up.set(camUp); 184 left.set(camLeft); 185 } 186 187 // update data in vertex buffers 188 positions.clear(); 189 colors.clear(); 190 texcoords.clear(); 191 Vector3f faceNormal = emitter.getFaceNormal(); 192 193 for (int i = 0; i < particles.length; i++){ 194 Particle p = particles[i]; 195 boolean dead = p.life == 0; 196 if (dead){ 197 positions.put(0).put(0).put(0); 198 positions.put(0).put(0).put(0); 199 positions.put(0).put(0).put(0); 200 positions.put(0).put(0).put(0); 201 continue; 202 } 203 204 if (facingVelocity){ 205 left.set(p.velocity).normalizeLocal(); 206 camDir.cross(left, up); 207 up.multLocal(p.size); 208 left.multLocal(p.size); 209 }else if (faceNormal != null){ 210 up.set(faceNormal).crossLocal(Vector3f.UNIT_X); 211 faceNormal.cross(up, left); 212 up.multLocal(p.size); 213 left.multLocal(p.size); 214 }else if (p.angle != 0){ 215 float cos = FastMath.cos(p.angle) * p.size; 216 float sin = FastMath.sin(p.angle) * p.size; 217 218 left.x = camLeft.x * cos + camUp.x * sin; 219 left.y = camLeft.y * cos + camUp.y * sin; 220 left.z = camLeft.z * cos + camUp.z * sin; 221 222 up.x = camLeft.x * -sin + camUp.x * cos; 223 up.y = camLeft.y * -sin + camUp.y * cos; 224 up.z = camLeft.z * -sin + camUp.z * cos; 225 }else{ 226 up.set(camUp); 227 left.set(camLeft); 228 up.multLocal(p.size); 229 left.multLocal(p.size); 230 } 231 232 positions.put(p.position.x + left.x + up.x) 233 .put(p.position.y + left.y + up.y) 234 .put(p.position.z + left.z + up.z); 235 236 positions.put(p.position.x - left.x + up.x) 237 .put(p.position.y - left.y + up.y) 238 .put(p.position.z - left.z + up.z); 239 240 positions.put(p.position.x + left.x - up.x) 241 .put(p.position.y + left.y - up.y) 242 .put(p.position.z + left.z - up.z); 243 244 positions.put(p.position.x - left.x - up.x) 245 .put(p.position.y - left.y - up.y) 246 .put(p.position.z - left.z - up.z); 247 248 if (uniqueTexCoords){ 249 int imgX = p.imageIndex % imagesX; 250 int imgY = (p.imageIndex - imgX) / imagesY; 251 252 float startX = ((float) imgX) / imagesX; 253 float startY = ((float) imgY) / imagesY; 254 float endX = startX + (1f / imagesX); 255 float endY = startY + (1f / imagesY); 256 257 texcoords.put(startX).put(endY); 258 texcoords.put(endX).put(endY); 259 texcoords.put(startX).put(startY); 260 texcoords.put(endX).put(startY); 261 } 262 263 int abgr = p.color.asIntABGR(); 264 colors.putInt(abgr); 265 colors.putInt(abgr); 266 colors.putInt(abgr); 267 colors.putInt(abgr); 268 } 269 270 positions.clear(); 271 colors.clear(); 272 if (!uniqueTexCoords) 273 texcoords.clear(); 274 else{ 275 texcoords.clear(); 276 tvb.updateData(texcoords); 277 } 278 279 // force renderer to re-send data to GPU 280 pvb.updateData(positions); 281 cvb.updateData(colors); 282 } 283 284 } 285