159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapackage com.jme3.scene.plugins.blender.particles;
259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.effect.ParticleEmitter;
459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.effect.ParticleMesh.Type;
559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.effect.influencers.EmptyParticleInfluencer;
659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.effect.influencers.NewtonianParticleInfluencer;
759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.effect.influencers.ParticleInfluencer;
859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.effect.shapes.EmitterMeshConvexHullShape;
959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.effect.shapes.EmitterMeshFaceShape;
1059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.effect.shapes.EmitterMeshVertexShape;
1159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.ColorRGBA;
1259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.AbstractBlenderHelper;
1359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.BlenderContext;
1459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
1559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.file.DynamicArray;
1659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.file.Pointer;
1759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.file.Structure;
1859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.logging.Logger;
1959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
2059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapublic class ParticlesHelper extends AbstractBlenderHelper {
2159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	private static final Logger			LOGGER		= Logger.getLogger(ParticlesHelper.class.getName());
2259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
2359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	// part->type
2459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_EMITTER	=	0;
2559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_REACTOR	=	1;
2659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_HAIR		=	2;
2759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_FLUID		=	3;
2859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
2959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	// part->flag
3059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_REACT_STA_END	=1;
3159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_REACT_MULTIPLE	=2;
3259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_LOOP			=4;
3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	//public static final int PART_LOOP_INSTANT	=8;
3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_HAIR_GEOMETRY	=16;
3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_UNBORN			=32;		//show unborn particles
3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_DIED			=64;		//show died particles
3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_TRAND			=128;
3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_EDISTR			=256;		// particle/face from face areas
3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_STICKY			=512;		//collided particles can stick to collider
4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_DIE_ON_COL		=1<<12;
4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_SIZE_DEFL		=1<<13; 	// swept sphere deflections
4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_ROT_DYN		=1<<14;	// dynamic rotation
4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_SIZEMASS		=1<<16;
4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_ABS_LENGTH		=1<<15;
4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_ABS_TIME		=1<<17;
4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_GLOB_TIME		=1<<18;
4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_BOIDS_2D		=1<<19;
4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_BRANCHING		=1<<20;
4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_ANIM_BRANCHING	=1<<21;
5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_SELF_EFFECT	=1<<22;
5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_SYMM_BRANCHING	=1<<24;
5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_HAIR_BSPLINE	=1024;
5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_GRID_INVERT	=1<<26;
5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_CHILD_EFFECT	=1<<27;
5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_CHILD_SEAMS	=1<<28;
5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_CHILD_RENDER	=1<<29;
5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_CHILD_GUIDE	=1<<30;
5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	// part->from
6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_FROM_VERT		=0;
6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_FROM_FACE		=1;
6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_FROM_VOLUME	=2;
6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_FROM_PARTICLE	=3;
6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_FROM_CHILD		=4;
6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	// part->phystype
6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_PHYS_NO	=	0;
6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_PHYS_NEWTON=	1;
6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_PHYS_KEYED	=	2;
7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_PHYS_BOIDS	=	3;
7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	// part->draw_as
7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_DRAW_NOT	=	0;
7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_DRAW_DOT	=	1;
7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_DRAW_CIRC	=	2;
7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_DRAW_CROSS	=	3;
7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_DRAW_AXIS	=	4;
7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_DRAW_LINE	=	5;
7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_DRAW_PATH	=	6;
8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_DRAW_OB	=	7;
8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_DRAW_GR	=	8;
8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public static final int PART_DRAW_BB	=	9;
8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	/**
8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * This constructor parses the given blender version and stores the result. Some functionalities may differ in
8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * different blender versions.
8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param blenderVersion
8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 *        the version read from the blend file
8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 * @param fixUpAxis
9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *        a variable that indicates if the Y asxis is the UP axis or not
9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	 */
9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public ParticlesHelper(String blenderVersion, boolean fixUpAxis) {
9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		super(blenderVersion, fixUpAxis);
9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	@SuppressWarnings("unchecked")
9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public ParticleEmitter toParticleEmitter(Structure particleSystem, BlenderContext blenderContext) throws BlenderFileException {
9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		ParticleEmitter result = null;
9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		Pointer pParticleSettings = (Pointer) particleSystem.getFieldValue("part");
10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		if(pParticleSettings.isNotNull()) {
10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			Structure particleSettings = pParticleSettings.fetchData(blenderContext.getInputStream()).get(0);
10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			int totPart = ((Number) particleSettings.getFieldValue("totpart")).intValue();
10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			//draw type will be stored temporarily in the name (it is used during modifier applying operation)
10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			int drawAs = ((Number)particleSettings.getFieldValue("draw_as")).intValue();
10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			char nameSuffix;//P - point, L - line, N - None, B - Bilboard
10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			switch(drawAs) {
10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				case PART_DRAW_NOT:
11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					nameSuffix = 'N';
11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					totPart = 0;//no need to generate particles in this case
11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					break;
11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				case PART_DRAW_BB:
11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					nameSuffix = 'B';
11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					break;
11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				case PART_DRAW_OB:
11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				case PART_DRAW_GR:
11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					nameSuffix = 'P';
11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					LOGGER.warning("Neither object nor group particles supported yet! Using point representation instead!");//TODO: support groups and aobjects
12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					break;
12159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				case PART_DRAW_LINE:
12259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					nameSuffix = 'L';
12359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					LOGGER.warning("Lines not yet supported! Using point representation instead!");//TODO: support lines
12459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				default://all others are rendered as points in blender
12559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					nameSuffix = 'P';
12659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			}
12759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			result = new ParticleEmitter(particleSettings.getName()+nameSuffix, Type.Triangle, totPart);
12859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			if(nameSuffix=='N') {
12959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				return result;//no need to set anything else
13059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			}
13159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
13259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			//setting the emitters shape (the shapes meshes will be set later during modifier applying operation)
13359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			int from = ((Number)particleSettings.getFieldValue("from")).intValue();
13459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			switch(from) {
13559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				case PART_FROM_VERT:
13659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					result.setShape(new EmitterMeshVertexShape());
13759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					break;
13859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				case PART_FROM_FACE:
13959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					result.setShape(new EmitterMeshFaceShape());
14059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					break;
14159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				case PART_FROM_VOLUME:
14259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					result.setShape(new EmitterMeshConvexHullShape());
14359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					break;
14459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta				default:
14559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta					LOGGER.warning("Default shape used! Unknown emitter shape value ('from' parameter: " + from + ')');
14659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			}
14759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
14859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			//reading acceleration
14959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			DynamicArray<Number> acc = (DynamicArray<Number>) particleSettings.getFieldValue("acc");
15059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			result.setGravity(-acc.get(0).floatValue(), -acc.get(1).floatValue(), -acc.get(2).floatValue());
15159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
15259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			//setting the colors
15359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			result.setEndColor(new ColorRGBA(1f, 1f, 1f, 1f));
15459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			result.setStartColor(new ColorRGBA(1f, 1f, 1f, 1f));
15559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
15659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			//reading size
15759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			float sizeFactor = nameSuffix=='B' ? 1.0f : 0.3f;
15859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			float size = ((Number)particleSettings.getFieldValue("size")).floatValue() * sizeFactor;
15959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			result.setStartSize(size);
16059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			result.setEndSize(size);
16159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
16259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			//reading lifetime
16359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			int fps = blenderContext.getBlenderKey().getFps();
16459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			float lifetime = ((Number)particleSettings.getFieldValue("lifetime")).floatValue() / fps;
16559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			float randlife = ((Number)particleSettings.getFieldValue("randlife")).floatValue() / fps;
16659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta			result.setLowLife(lifetime * (1.0f - randlife));
16759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    result.setHighLife(lifetime);
16859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
16959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    //preparing influencer
17059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    ParticleInfluencer influencer;
17159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    int phystype = ((Number)particleSettings.getFieldValue("phystype")).intValue();
17259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    switch(phystype) {
17359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    	case PART_PHYS_NEWTON:
17459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    		influencer = new NewtonianParticleInfluencer();
17559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    		((NewtonianParticleInfluencer)influencer).setNormalVelocity(((Number)particleSettings.getFieldValue("normfac")).floatValue());
17659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    		((NewtonianParticleInfluencer)influencer).setVelocityVariation(((Number)particleSettings.getFieldValue("randfac")).floatValue());
17759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    		((NewtonianParticleInfluencer)influencer).setSurfaceTangentFactor(((Number)particleSettings.getFieldValue("tanfac")).floatValue());
17859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    		((NewtonianParticleInfluencer)influencer).setSurfaceTangentRotation(((Number)particleSettings.getFieldValue("tanphase")).floatValue());
17959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    		break;
18059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    	case PART_PHYS_BOIDS:
18159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    	case PART_PHYS_KEYED://TODO: support other influencers
18259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    		LOGGER.warning("Boids and Keyed particles physic not yet supported! Empty influencer used!");
18359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    	case PART_PHYS_NO:
18459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	    		default:
18559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	    			influencer = new EmptyParticleInfluencer();
18659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    }
18759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		    result.setParticleInfluencer(influencer);
18859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		}
18959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		return result;
19059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
19159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
19259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	@Override
19359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
19459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta		return true;
19559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta	}
19659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta}
197