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

com.badlogic.gdx.graphics.g3d.particles.influencers.DynamicsInfluencer Maven / Gradle / Ivy

There is a newer version: 1.12.1
Show 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.particles.influencers;

import java.util.Arrays;

import com.badlogic.gdx.graphics.g3d.particles.ParallelArray.FloatChannel;
import com.badlogic.gdx.graphics.g3d.particles.ParticleChannels;
import com.badlogic.gdx.graphics.g3d.particles.ParticleController;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Json;
import com.badlogic.gdx.utils.JsonValue;

/** It's an {@link Influencer} which controls the particles dynamics (movement, rotations).
 * @author Inferno */
public class DynamicsInfluencer extends Influencer {
	public Array velocities;
	private FloatChannel accellerationChannel, positionChannel, previousPositionChannel, rotationChannel, angularVelocityChannel;
	boolean hasAcceleration, has2dAngularVelocity, has3dAngularVelocity;

	public DynamicsInfluencer () {
		this.velocities = new Array(true, 3, DynamicsModifier.class);
	}

	public DynamicsInfluencer (DynamicsModifier... velocities) {
		this.velocities = new Array(true, velocities.length, DynamicsModifier.class);
		for (DynamicsModifier value : velocities) {
			this.velocities.add((DynamicsModifier)value.copy());
		}
	}

	public DynamicsInfluencer (DynamicsInfluencer velocityInfluencer) {
		this((DynamicsModifier[])velocityInfluencer.velocities.toArray(DynamicsModifier.class));
	}

	@Override
	public void allocateChannels () {
		for (int k = 0; k < velocities.size; ++k) {
			velocities.items[k].allocateChannels();
		}

		// Hack, shouldn't be done but after all the modifiers allocated their channels
		// it's possible to check if we need to allocate previous position channel
		accellerationChannel = controller.particles.getChannel(ParticleChannels.Acceleration);
		hasAcceleration = accellerationChannel != null;
		if (hasAcceleration) {
			positionChannel = controller.particles.addChannel(ParticleChannels.Position);
			previousPositionChannel = controller.particles.addChannel(ParticleChannels.PreviousPosition);
		}

		// Angular velocity check
		angularVelocityChannel = controller.particles.getChannel(ParticleChannels.AngularVelocity2D);
		has2dAngularVelocity = angularVelocityChannel != null;
		if (has2dAngularVelocity) {
			rotationChannel = controller.particles.addChannel(ParticleChannels.Rotation2D);
			has3dAngularVelocity = false;
		} else {
			angularVelocityChannel = controller.particles.getChannel(ParticleChannels.AngularVelocity3D);
			has3dAngularVelocity = angularVelocityChannel != null;
			if (has3dAngularVelocity) rotationChannel = controller.particles.addChannel(ParticleChannels.Rotation3D);
		}
	}

	@Override
	public void set (ParticleController particleController) {
		super.set(particleController);
		for (int k = 0; k < velocities.size; ++k) {
			velocities.items[k].set(particleController);
		}
	}

	@Override
	public void init () {
		for (int k = 0; k < velocities.size; ++k) {
			velocities.items[k].init();
		}
	}

	public void activateParticles (int startIndex, int count) {
		if (hasAcceleration) {
			// Previous position is the current position
			// Attention, this requires that some other influencer setting the position channel must execute before this influencer.
			for (int i = startIndex * positionChannel.strideSize,
				c = i + count * positionChannel.strideSize; i < c; i += positionChannel.strideSize) {
				previousPositionChannel.data[i + ParticleChannels.XOffset] = positionChannel.data[i + ParticleChannels.XOffset];
				previousPositionChannel.data[i + ParticleChannels.YOffset] = positionChannel.data[i + ParticleChannels.YOffset];
				previousPositionChannel.data[i + ParticleChannels.ZOffset] = positionChannel.data[i + ParticleChannels.ZOffset];
				/*
				 * //Euler intialization previousPositionChannel.data[i+ParticleChannels.XOffset] =
				 * previousPositionChannel.data[i+ParticleChannels.YOffset] = previousPositionChannel.data[i+ParticleChannels.ZOffset]
				 * = 0;
				 */
			}
		}

		if (has2dAngularVelocity) {
			// Rotation back to 0
			for (int i = startIndex * rotationChannel.strideSize,
				c = i + count * rotationChannel.strideSize; i < c; i += rotationChannel.strideSize) {
				rotationChannel.data[i + ParticleChannels.CosineOffset] = 1;
				rotationChannel.data[i + ParticleChannels.SineOffset] = 0;
			}
		} else if (has3dAngularVelocity) {
			// Rotation back to 0
			for (int i = startIndex * rotationChannel.strideSize,
				c = i + count * rotationChannel.strideSize; i < c; i += rotationChannel.strideSize) {
				rotationChannel.data[i + ParticleChannels.XOffset] = 0;
				rotationChannel.data[i + ParticleChannels.YOffset] = 0;
				rotationChannel.data[i + ParticleChannels.ZOffset] = 0;
				rotationChannel.data[i + ParticleChannels.WOffset] = 1;
			}
		}

		for (int k = 0; k < velocities.size; ++k) {
			velocities.items[k].activateParticles(startIndex, count);
		}
	}

	public void update () {
		// Clean previouse frame velocities
		if (hasAcceleration)
			Arrays.fill(accellerationChannel.data, 0, controller.particles.size * accellerationChannel.strideSize, 0);
		if (has2dAngularVelocity || has3dAngularVelocity)
			Arrays.fill(angularVelocityChannel.data, 0, controller.particles.size * angularVelocityChannel.strideSize, 0);

		// Sum all the forces/accelerations
		for (int k = 0; k < velocities.size; ++k) {
			velocities.items[k].update();
		}

		// Apply the forces
		if (hasAcceleration) {
			/*
			 * //Euler Integration for(int i=0, offset = 0; i < controller.particles.size; ++i, offset +=positionChannel.strideSize){
			 * previousPositionChannel.data[offset + ParticleChannels.XOffset] += accellerationChannel.data[offset +
			 * ParticleChannels.XOffset]*controller.deltaTime; previousPositionChannel.data[offset + ParticleChannels.YOffset] +=
			 * accellerationChannel.data[offset + ParticleChannels.YOffset]*controller.deltaTime; previousPositionChannel.data[offset
			 * + ParticleChannels.ZOffset] += accellerationChannel.data[offset + ParticleChannels.ZOffset]*controller.deltaTime;
			 * 
			 * positionChannel.data[offset + ParticleChannels.XOffset] += previousPositionChannel.data[offset +
			 * ParticleChannels.XOffset]*controller.deltaTime; positionChannel.data[offset + ParticleChannels.YOffset] +=
			 * previousPositionChannel.data[offset + ParticleChannels.YOffset]*controller.deltaTime; positionChannel.data[offset +
			 * ParticleChannels.ZOffset] += previousPositionChannel.data[offset + ParticleChannels.ZOffset]*controller.deltaTime; }
			 */
			// Verlet integration
			for (int i = 0, offset = 0; i < controller.particles.size; ++i, offset += positionChannel.strideSize) {
				float x = positionChannel.data[offset + ParticleChannels.XOffset],
					y = positionChannel.data[offset + ParticleChannels.YOffset],
					z = positionChannel.data[offset + ParticleChannels.ZOffset];
				positionChannel.data[offset + ParticleChannels.XOffset] = 2 * x
					- previousPositionChannel.data[offset + ParticleChannels.XOffset]
					+ accellerationChannel.data[offset + ParticleChannels.XOffset] * controller.deltaTimeSqr;
				positionChannel.data[offset + ParticleChannels.YOffset] = 2 * y
					- previousPositionChannel.data[offset + ParticleChannels.YOffset]
					+ accellerationChannel.data[offset + ParticleChannels.YOffset] * controller.deltaTimeSqr;
				positionChannel.data[offset + ParticleChannels.ZOffset] = 2 * z
					- previousPositionChannel.data[offset + ParticleChannels.ZOffset]
					+ accellerationChannel.data[offset + ParticleChannels.ZOffset] * controller.deltaTimeSqr;
				previousPositionChannel.data[offset + ParticleChannels.XOffset] = x;
				previousPositionChannel.data[offset + ParticleChannels.YOffset] = y;
				previousPositionChannel.data[offset + ParticleChannels.ZOffset] = z;
			}
		}

		if (has2dAngularVelocity) {
			for (int i = 0, offset = 0; i < controller.particles.size; ++i, offset += rotationChannel.strideSize) {
				float rotation = angularVelocityChannel.data[i] * controller.deltaTime;
				if (rotation != 0) {
					float cosBeta = MathUtils.cosDeg(rotation), sinBeta = MathUtils.sinDeg(rotation);
					float currentCosine = rotationChannel.data[offset + ParticleChannels.CosineOffset];
					float currentSine = rotationChannel.data[offset + ParticleChannels.SineOffset];
					float newCosine = currentCosine * cosBeta - currentSine * sinBeta,
						newSine = currentSine * cosBeta + currentCosine * sinBeta;
					rotationChannel.data[offset + ParticleChannels.CosineOffset] = newCosine;
					rotationChannel.data[offset + ParticleChannels.SineOffset] = newSine;
				}
			}
		} else if (has3dAngularVelocity) {
			for (int i = 0, offset = 0,
				angularOffset = 0; i < controller.particles.size; ++i, offset += rotationChannel.strideSize, angularOffset += angularVelocityChannel.strideSize) {

				float wx = angularVelocityChannel.data[angularOffset + ParticleChannels.XOffset],
					wy = angularVelocityChannel.data[angularOffset + ParticleChannels.YOffset],
					wz = angularVelocityChannel.data[angularOffset + ParticleChannels.ZOffset],
					qx = rotationChannel.data[offset + ParticleChannels.XOffset],
					qy = rotationChannel.data[offset + ParticleChannels.YOffset],
					qz = rotationChannel.data[offset + ParticleChannels.ZOffset],
					qw = rotationChannel.data[offset + ParticleChannels.WOffset];
				TMP_Q.set(wx, wy, wz, 0).mul(qx, qy, qz, qw).mul(0.5f * controller.deltaTime).add(qx, qy, qz, qw).nor();
				rotationChannel.data[offset + ParticleChannels.XOffset] = TMP_Q.x;
				rotationChannel.data[offset + ParticleChannels.YOffset] = TMP_Q.y;
				rotationChannel.data[offset + ParticleChannels.ZOffset] = TMP_Q.z;
				rotationChannel.data[offset + ParticleChannels.WOffset] = TMP_Q.w;
			}
		}
	}

	@Override
	public DynamicsInfluencer copy () {
		return new DynamicsInfluencer(this);
	}

	@Override
	public void write (Json json) {
		json.writeValue("velocities", velocities, Array.class, DynamicsModifier.class);
	}

	@Override
	public void read (Json json, JsonValue jsonData) {
		velocities.addAll(json.readValue("velocities", Array.class, DynamicsModifier.class, jsonData));
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy