Home | History | Annotate | Download | only in particles
      1 package com.jme3.scene.plugins.blender.particles;
      2 
      3 import com.jme3.effect.ParticleEmitter;
      4 import com.jme3.effect.ParticleMesh.Type;
      5 import com.jme3.effect.influencers.EmptyParticleInfluencer;
      6 import com.jme3.effect.influencers.NewtonianParticleInfluencer;
      7 import com.jme3.effect.influencers.ParticleInfluencer;
      8 import com.jme3.effect.shapes.EmitterMeshConvexHullShape;
      9 import com.jme3.effect.shapes.EmitterMeshFaceShape;
     10 import com.jme3.effect.shapes.EmitterMeshVertexShape;
     11 import com.jme3.math.ColorRGBA;
     12 import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
     13 import com.jme3.scene.plugins.blender.BlenderContext;
     14 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
     15 import com.jme3.scene.plugins.blender.file.DynamicArray;
     16 import com.jme3.scene.plugins.blender.file.Pointer;
     17 import com.jme3.scene.plugins.blender.file.Structure;
     18 import java.util.logging.Logger;
     19 
     20 public class ParticlesHelper extends AbstractBlenderHelper {
     21 	private static final Logger			LOGGER		= Logger.getLogger(ParticlesHelper.class.getName());
     22 
     23 	// part->type
     24 	public static final int PART_EMITTER	=	0;
     25 	public static final int PART_REACTOR	=	1;
     26 	public static final int PART_HAIR		=	2;
     27 	public static final int PART_FLUID		=	3;
     28 
     29 	// part->flag
     30 	public static final int PART_REACT_STA_END	=1;
     31 	public static final int PART_REACT_MULTIPLE	=2;
     32 	public static final int PART_LOOP			=4;
     33 	//public static final int PART_LOOP_INSTANT	=8;
     34 	public static final int PART_HAIR_GEOMETRY	=16;
     35 	public static final int PART_UNBORN			=32;		//show unborn particles
     36 	public static final int PART_DIED			=64;		//show died particles
     37 	public static final int PART_TRAND			=128;
     38 	public static final int PART_EDISTR			=256;		// particle/face from face areas
     39 	public static final int PART_STICKY			=512;		//collided particles can stick to collider
     40 	public static final int PART_DIE_ON_COL		=1<<12;
     41 	public static final int PART_SIZE_DEFL		=1<<13; 	// swept sphere deflections
     42 	public static final int PART_ROT_DYN		=1<<14;	// dynamic rotation
     43 	public static final int PART_SIZEMASS		=1<<16;
     44 	public static final int PART_ABS_LENGTH		=1<<15;
     45 	public static final int PART_ABS_TIME		=1<<17;
     46 	public static final int PART_GLOB_TIME		=1<<18;
     47 	public static final int PART_BOIDS_2D		=1<<19;
     48 	public static final int PART_BRANCHING		=1<<20;
     49 	public static final int PART_ANIM_BRANCHING	=1<<21;
     50 	public static final int PART_SELF_EFFECT	=1<<22;
     51 	public static final int PART_SYMM_BRANCHING	=1<<24;
     52 	public static final int PART_HAIR_BSPLINE	=1024;
     53 	public static final int PART_GRID_INVERT	=1<<26;
     54 	public static final int PART_CHILD_EFFECT	=1<<27;
     55 	public static final int PART_CHILD_SEAMS	=1<<28;
     56 	public static final int PART_CHILD_RENDER	=1<<29;
     57 	public static final int PART_CHILD_GUIDE	=1<<30;
     58 
     59 	// part->from
     60 	public static final int PART_FROM_VERT		=0;
     61 	public static final int PART_FROM_FACE		=1;
     62 	public static final int PART_FROM_VOLUME	=2;
     63 	public static final int PART_FROM_PARTICLE	=3;
     64 	public static final int PART_FROM_CHILD		=4;
     65 
     66 	// part->phystype
     67 	public static final int PART_PHYS_NO	=	0;
     68 	public static final int PART_PHYS_NEWTON=	1;
     69 	public static final int PART_PHYS_KEYED	=	2;
     70 	public static final int PART_PHYS_BOIDS	=	3;
     71 
     72 	// part->draw_as
     73 	public static final int PART_DRAW_NOT	=	0;
     74 	public static final int PART_DRAW_DOT	=	1;
     75 	public static final int PART_DRAW_CIRC	=	2;
     76 	public static final int PART_DRAW_CROSS	=	3;
     77 	public static final int PART_DRAW_AXIS	=	4;
     78 	public static final int PART_DRAW_LINE	=	5;
     79 	public static final int PART_DRAW_PATH	=	6;
     80 	public static final int PART_DRAW_OB	=	7;
     81 	public static final int PART_DRAW_GR	=	8;
     82 	public static final int PART_DRAW_BB	=	9;
     83 
     84 	/**
     85 	 * This constructor parses the given blender version and stores the result. Some functionalities may differ in
     86 	 * different blender versions.
     87 	 * @param blenderVersion
     88 	 *        the version read from the blend file
     89 	 * @param fixUpAxis
     90      *        a variable that indicates if the Y asxis is the UP axis or not
     91 	 */
     92 	public ParticlesHelper(String blenderVersion, boolean fixUpAxis) {
     93 		super(blenderVersion, fixUpAxis);
     94 	}
     95 
     96 	@SuppressWarnings("unchecked")
     97 	public ParticleEmitter toParticleEmitter(Structure particleSystem, BlenderContext blenderContext) throws BlenderFileException {
     98 		ParticleEmitter result = null;
     99 		Pointer pParticleSettings = (Pointer) particleSystem.getFieldValue("part");
    100 		if(pParticleSettings.isNotNull()) {
    101 			Structure particleSettings = pParticleSettings.fetchData(blenderContext.getInputStream()).get(0);
    102 
    103 			int totPart = ((Number) particleSettings.getFieldValue("totpart")).intValue();
    104 
    105 			//draw type will be stored temporarily in the name (it is used during modifier applying operation)
    106 			int drawAs = ((Number)particleSettings.getFieldValue("draw_as")).intValue();
    107 			char nameSuffix;//P - point, L - line, N - None, B - Bilboard
    108 			switch(drawAs) {
    109 				case PART_DRAW_NOT:
    110 					nameSuffix = 'N';
    111 					totPart = 0;//no need to generate particles in this case
    112 					break;
    113 				case PART_DRAW_BB:
    114 					nameSuffix = 'B';
    115 					break;
    116 				case PART_DRAW_OB:
    117 				case PART_DRAW_GR:
    118 					nameSuffix = 'P';
    119 					LOGGER.warning("Neither object nor group particles supported yet! Using point representation instead!");//TODO: support groups and aobjects
    120 					break;
    121 				case PART_DRAW_LINE:
    122 					nameSuffix = 'L';
    123 					LOGGER.warning("Lines not yet supported! Using point representation instead!");//TODO: support lines
    124 				default://all others are rendered as points in blender
    125 					nameSuffix = 'P';
    126 			}
    127 			result = new ParticleEmitter(particleSettings.getName()+nameSuffix, Type.Triangle, totPart);
    128 			if(nameSuffix=='N') {
    129 				return result;//no need to set anything else
    130 			}
    131 
    132 			//setting the emitters shape (the shapes meshes will be set later during modifier applying operation)
    133 			int from = ((Number)particleSettings.getFieldValue("from")).intValue();
    134 			switch(from) {
    135 				case PART_FROM_VERT:
    136 					result.setShape(new EmitterMeshVertexShape());
    137 					break;
    138 				case PART_FROM_FACE:
    139 					result.setShape(new EmitterMeshFaceShape());
    140 					break;
    141 				case PART_FROM_VOLUME:
    142 					result.setShape(new EmitterMeshConvexHullShape());
    143 					break;
    144 				default:
    145 					LOGGER.warning("Default shape used! Unknown emitter shape value ('from' parameter: " + from + ')');
    146 			}
    147 
    148 			//reading acceleration
    149 			DynamicArray<Number> acc = (DynamicArray<Number>) particleSettings.getFieldValue("acc");
    150 			result.setGravity(-acc.get(0).floatValue(), -acc.get(1).floatValue(), -acc.get(2).floatValue());
    151 
    152 			//setting the colors
    153 			result.setEndColor(new ColorRGBA(1f, 1f, 1f, 1f));
    154 			result.setStartColor(new ColorRGBA(1f, 1f, 1f, 1f));
    155 
    156 			//reading size
    157 			float sizeFactor = nameSuffix=='B' ? 1.0f : 0.3f;
    158 			float size = ((Number)particleSettings.getFieldValue("size")).floatValue() * sizeFactor;
    159 			result.setStartSize(size);
    160 			result.setEndSize(size);
    161 
    162 			//reading lifetime
    163 			int fps = blenderContext.getBlenderKey().getFps();
    164 			float lifetime = ((Number)particleSettings.getFieldValue("lifetime")).floatValue() / fps;
    165 			float randlife = ((Number)particleSettings.getFieldValue("randlife")).floatValue() / fps;
    166 			result.setLowLife(lifetime * (1.0f - randlife));
    167 		    result.setHighLife(lifetime);
    168 
    169 		    //preparing influencer
    170 		    ParticleInfluencer influencer;
    171 		    int phystype = ((Number)particleSettings.getFieldValue("phystype")).intValue();
    172 		    switch(phystype) {
    173 		    	case PART_PHYS_NEWTON:
    174 		    		influencer = new NewtonianParticleInfluencer();
    175 		    		((NewtonianParticleInfluencer)influencer).setNormalVelocity(((Number)particleSettings.getFieldValue("normfac")).floatValue());
    176 		    		((NewtonianParticleInfluencer)influencer).setVelocityVariation(((Number)particleSettings.getFieldValue("randfac")).floatValue());
    177 		    		((NewtonianParticleInfluencer)influencer).setSurfaceTangentFactor(((Number)particleSettings.getFieldValue("tanfac")).floatValue());
    178 		    		((NewtonianParticleInfluencer)influencer).setSurfaceTangentRotation(((Number)particleSettings.getFieldValue("tanphase")).floatValue());
    179 		    		break;
    180 		    	case PART_PHYS_BOIDS:
    181 		    	case PART_PHYS_KEYED://TODO: support other influencers
    182 		    		LOGGER.warning("Boids and Keyed particles physic not yet supported! Empty influencer used!");
    183 		    	case PART_PHYS_NO:
    184 	    		default:
    185 	    			influencer = new EmptyParticleInfluencer();
    186 		    }
    187 		    result.setParticleInfluencer(influencer);
    188 		}
    189 		return result;
    190 	}
    191 
    192 	@Override
    193 	public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
    194 		return true;
    195 	}
    196 }
    197