• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 	 */
ParticlesHelper(String blenderVersion, boolean fixUpAxis)92 	public ParticlesHelper(String blenderVersion, boolean fixUpAxis) {
93 		super(blenderVersion, fixUpAxis);
94 	}
95 
96 	@SuppressWarnings("unchecked")
toParticleEmitter(Structure particleSystem, BlenderContext blenderContext)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
shouldBeLoaded(Structure structure, BlenderContext blenderContext)193 	public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) {
194 		return true;
195 	}
196 }
197