/*
* Copyright 2016 Nathan Howard
*
* This file is part of OpenGrave
*
* OpenGrave is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenGrave is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenGrave. If not, see <http://www.gnu.org/licenses/>.
*/
package com.opengrave.og.engine;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import com.opengrave.common.DebugExceptionHandler;
import com.opengrave.common.OGOutputStream;
import com.opengrave.common.world.CommonObject;
import com.opengrave.common.world.MaterialList;
import com.opengrave.og.base.Pickable;
import com.opengrave.og.base.RenderableParticles;
import com.opengrave.og.light.Shadow;
import com.opengrave.og.util.Matrix4f;
import com.opengrave.og.util.Vector3f;
import com.opengrave.og.util.Vector4f;
public class ParticleObject extends BaseObject implements Pickable {
ArrayList<ParticlePart> particles, sortedParticles;
private float timeSinceLastSpawn = 0f;
private int lastSpawned = 0;
private float spawnRate = 200f;
private boolean respawn = true;
private Vector3f gravity = new Vector3f(0f, 0f, -.1f);
BoundingBox box = new BoundingBox();
Random rand = new Random();
private Vector3f minimum = new Vector3f(0f, 0f, 0f), minimumDir = new Vector3f(0f, 0f, 1f), minimumCol = new Vector3f(0f, 0f, 0f);
private Vector3f maximum = new Vector3f(0f, 0f, 0f), maximumDir = new Vector3f(0f, 0f, 1f), maximumCol = new Vector3f(1f, 1f, 1f);
public ParticleObject(CommonObject cobj) {
super(cobj);
renderable = new RenderableParticles();
particles = new ArrayList<ParticlePart>();
setParticleCount(100);
}
public void setParticleCount(int particleCount) {
synchronized (particles) {
while (particles.size() < particleCount) {
particles.add(new ParticlePart());
}
while (particles.size() > particleCount) {
particles.remove(0);
}
System.out.println(particles.size());
}
}
public int getParticleCount() {
synchronized (particles) {
return particles.size();
}
}
public void setGravity(Vector3f gravity) {
this.gravity = gravity;
}
public Vector3f getGravity() {
return gravity;
}
public void setMaterialList(MaterialList matList) {
this.matList = matList;
}
public MaterialList getMaterialList() {
return matList;
}
public void setSpawnRate(float spawnRate) {
this.spawnRate = spawnRate;
}
public float getSpawnRate() {
return spawnRate;
}
public void setRespawn(boolean respawn) {
this.respawn = respawn;
}
public boolean getRespawn() {
return respawn;
}
@Override
public void doRender(Matrix4f matrix) {
}
@Override
public void doRenderForPicking(Matrix4f matrix) {
synchronized (particles) {
((RenderableParticles) renderable).setParticleData(sortedParticles);
renderable.setContext(context);
renderable.renderForPicking(matrix, this);
}
}
@Override
public void doRenderShadows(Matrix4f matrix, Shadow shadow) {
}
@Override
public void renderableLabelChanged(String s) {
}
@Override
public void doUpdate(float delta) {
timeSinceLastSpawn += delta;
synchronized (particles) {
for (ParticlePart particle : particles) {
particle.setNextDelta(delta);
}
if (spawnRate > 0f && particles.size() > 0) {
while (timeSinceLastSpawn >= spawnRate) {
lastSpawned++;
if (lastSpawned >= particles.size()) {
lastSpawned = 0;
}
ParticlePart particle = particles.get(lastSpawned);
particle.spawn(getRandomLocation(), chooseRandomDirection(), gravity, chooseRandomColour());
particle.setNextDelta(delta);
timeSinceLastSpawn -= spawnRate;
delta -= spawnRate;
}
}
box.clear();
Vector3f minusOne = new Vector3f(-1f, -1f, -1f), plusOne = new Vector3f(1f, 1f, 1f);
for (ParticlePart particle : particles) {
particle.update(0f);
Vector3f pos = particle.getPosition().toVector3();
box.addVector3f(pos.add(minusOne, null));
box.addVector3f(pos.add(plusOne, null));
}
}
}
private Location getRandomLocation() {
float xrange = maximum.x - minimum.x, yrange = maximum.y - minimum.y, zrange = maximum.z - minimum.z;
Vector3f ran = new Vector3f(rand.nextFloat() * xrange + minimum.x, rand.nextFloat() * yrange + minimum.y, rand.nextFloat() * zrange + minimum.z);
return getLocation().addTogether(ran);
}
private Vector4f chooseRandomColour() {
float xrange = maximumCol.x - minimumCol.x, yrange = maximumCol.y - minimumCol.y, zrange = maximumCol.z - minimumCol.z;
return new Vector4f(rand.nextFloat() * xrange + minimumCol.x, rand.nextFloat() * yrange + minimumCol.y, rand.nextFloat() * zrange + minimumCol.z, 0.5f);
// TODO Alpha
}
private Vector3f chooseRandomDirection() {
float xrange = maximumDir.x - minimumDir.x, yrange = maximumDir.y - minimumDir.y, zrange = maximumDir.z - minimumDir.z;
return new Vector3f(rand.nextFloat() * xrange + minimumDir.x, rand.nextFloat() * yrange + minimumDir.y, rand.nextFloat() * zrange + minimumDir.z);
}
@Override
public String getType() {
return "particle";
}
@Override
public void startAnimation(String name, float speed, boolean once) {
}
@Override
public void stopAnimation(String name) {
}
@Override
public void doRenderSemiTransparent(Matrix4f matrix) {
synchronized (particles) {
for (ParticlePart particle : particles) {
particle.setDistanceFrom(context);
}
sort();
renderable.setMaterialList(matList);
((RenderableParticles) renderable).setParticleData(sortedParticles);
renderable.setContext(context);
renderable.render(matrix, style);
}
}
private void sort() {
if (sortedParticles == null || sortedParticles.size() != particles.size()) {
sortedParticles = new ArrayList<ParticlePart>();
sortedParticles.addAll(particles);
}
Collections.sort(sortedParticles, new ParticlesDepthSorter());
((RenderableParticles) renderable).setParticleData(sortedParticles);
}
public Vector3f getMinimum() {
return minimum;
}
public void setMinimum(Vector3f minimum) {
this.minimum = minimum;
}
public Vector3f getMaximum() {
return maximum;
}
public Vector3f getMinimumDir() {
return minimumDir;
}
public Vector3f getMaximumDir() {
return maximumDir;
}
public void setMaximum(Vector3f maximum) {
this.maximum = maximum;
}
public void setMinimumDir(Vector3f minDir) {
this.minimumDir = minDir;
}
public void setMaximumDir(Vector3f maxDir) {
this.maximumDir = maxDir;
}
public void setMinimumCol(Vector3f minCol) {
this.minimumCol = minCol;
}
public void setMaximumCol(Vector3f maxCol) {
this.maximumCol = maxCol;
}
public Vector3f getMinimumCol() {
return minimumCol;
}
public Vector3f getMaximumCol() {
return maximumCol;
}
@Override
public void save(OGOutputStream stream) {
try {
stream.writeString(getType());
stream.writeString(this.getModelLabel());
stream.writeVector3f(minimum);
stream.writeVector3f(maximum);
stream.writeVector3f(minimumDir);
stream.writeVector3f(maximumDir);
stream.writeVector3f(minimumCol);
stream.writeVector3f(maximumCol);
stream.writeInt(getParticleCount());
stream.writeLocation(location);
stream.writeMaterialList(matList);
} catch (IOException e) {
new DebugExceptionHandler(e);
}
}
@Override
public RenderView getContext() {
return context;
}
@Override
public BoundingBox getBoundingBox() {
return box;
}
}