diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/MaterialHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/MaterialHelper.java index f273053cb..1aacb8262 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/MaterialHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/MaterialHelper.java @@ -31,6 +31,7 @@ */ package com.jme3.scene.plugins.blender.helpers.v249; +import java.nio.ByteBuffer; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -39,12 +40,14 @@ import java.util.logging.Level; import java.util.logging.Logger; import com.jme3.asset.BlenderKey.FeaturesToLoad; +import com.jme3.asset.TextureKey; import com.jme3.material.MatParam; import com.jme3.material.Material; import com.jme3.material.Material.MatParamTexture; import com.jme3.material.RenderState.BlendMode; import com.jme3.material.RenderState.FaceCullMode; import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; import com.jme3.scene.plugins.blender.data.Structure; import com.jme3.scene.plugins.blender.exception.BlenderFileException; import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper; @@ -53,8 +56,11 @@ import com.jme3.scene.plugins.blender.utils.DataRepository.LoadedFeatureDataType import com.jme3.scene.plugins.blender.utils.DynamicArray; import com.jme3.scene.plugins.blender.utils.Pointer; import com.jme3.shader.VarType; +import com.jme3.texture.Image; +import com.jme3.texture.Image.Format; import com.jme3.texture.Texture; import com.jme3.texture.Texture.WrapMode; +import com.jme3.util.BufferUtils; public class MaterialHelper extends AbstractBlenderHelper { private static final Logger LOGGER = Logger.getLogger(MaterialHelper.class.getName()); @@ -67,6 +73,12 @@ public class MaterialHelper extends AbstractBlenderHelper { public static final String TEXTURE_TYPE_GLOW = "GlowMap"; public static final String TEXTURE_TYPE_ALPHA = "AlphaMap"; + public static final Integer ALPHA_MASK_NONE = Integer.valueOf(0); + public static final Integer ALPHA_MASK_CIRCLE = Integer.valueOf(1); + public static final Integer ALPHA_MASK_CONE = Integer.valueOf(2); + public static final Integer ALPHA_MASK_HYPERBOLE = Integer.valueOf(3); + protected final Map alphaMasks = new HashMap(); + /** * The type of the material's diffuse shader. */ @@ -93,6 +105,64 @@ public class MaterialHelper extends AbstractBlenderHelper { */ public MaterialHelper(String blenderVersion) { super(blenderVersion); + //setting alpha masks + alphaMasks.put(ALPHA_MASK_NONE, new IAlphaMask() { + @Override + public void setImageSize(int width, int height) {} + + @Override + public byte getAlpha(float x, float y) { + return (byte)255; + } + }); + alphaMasks.put(ALPHA_MASK_CIRCLE, new IAlphaMask() { + private float r; + private float[] center; + + @Override + public void setImageSize(int width, int height) { + r = Math.min(width, height) * 0.5f; + center = new float[] {width*0.5f, height * 0.5f}; + } + + @Override + public byte getAlpha(float x, float y) { + float d = FastMath.abs(FastMath.sqrt((x-center[0])*(x-center[0]) + (y-center[1])*(y-center[1]))); + return (byte)(d>=r ? 0 : 255); + } + }); + alphaMasks.put(ALPHA_MASK_CONE, new IAlphaMask() { + private float r; + private float[] center; + + @Override + public void setImageSize(int width, int height) { + r = Math.min(width, height) * 0.5f; + center = new float[] {width*0.5f, height * 0.5f}; + } + + @Override + public byte getAlpha(float x, float y) { + float d = FastMath.abs(FastMath.sqrt((x-center[0])*(x-center[0]) + (y-center[1])*(y-center[1]))); + return (byte)(d>=r ? 0 : -255.0f*d/r+255.0f); + } + }); + alphaMasks.put(ALPHA_MASK_HYPERBOLE, new IAlphaMask() { + private float r; + private float[] center; + + @Override + public void setImageSize(int width, int height) { + r = Math.min(width, height) * 0.5f; + center = new float[] {width*0.5f, height * 0.5f}; + } + + @Override + public byte getAlpha(float x, float y) { + float d = FastMath.abs(FastMath.sqrt((x-center[0])*(x-center[0]) + (y-center[1])*(y-center[1]))) / r; + return d>=1.0f ? 0 : (byte)((-FastMath.sqrt((2.0f-d)*d)+1.0f)*255.0f); + } + }); } /** @@ -287,13 +357,36 @@ public class MaterialHelper extends AbstractBlenderHelper { * @param dataRepository the data repository * @return material converted into particles-usable material */ - public Material getParticlesMaterial(Material material, DataRepository dataRepository) { + public Material getParticlesMaterial(Material material, Integer alphaMaskIndex, DataRepository dataRepository) { Material result = new Material(dataRepository.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md"); //copying texture MatParam diffuseMap = material.getParam("DiffuseMap"); if(diffuseMap!=null) { - Texture texture = (Texture) diffuseMap.getValue(); + Texture texture = ((Texture) diffuseMap.getValue()).clone(); + + //applying alpha mask to the texture + Image image = texture.getImage(); + ByteBuffer sourceBB = image.getData(0); + sourceBB.rewind(); + int w = image.getWidth(); + int h = image.getHeight(); + ByteBuffer bb = BufferUtils.createByteBuffer(w * h * 4); + IAlphaMask iAlphaMask = alphaMasks.get(alphaMaskIndex); + iAlphaMask.setImageSize(w, h); + + for(int x=0;x indexList = meshEntry.getValue(); - int[] indices = new int[indexList.size()]; - for (int i = 0; i < indexList.size(); ++i) { - indices[i] = indexList.get(i).intValue(); + short[] indices = new short[indexList.size()];//TODO: check if the model doesn't have more than 32767 vertices + for (int i = 0; i < indexList.size(); ++i) {//if yes then mesh.getVertices method must be changed to accept other than ShortBuffer + indices[i] = indexList.get(i).shortValue(); } // setting vertices - mesh.setBuffer(Type.Index, 1, BufferUtils.createIntBuffer(indices)); + mesh.setBuffer(Type.Index, 1, BufferUtils.createShortBuffer(indices)); mesh.setBuffer(verticesBuffer); mesh.setBuffer(verticesBind); diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ModifierHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ModifierHelper.java index bd266eb32..67c34c667 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ModifierHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ModifierHelper.java @@ -235,28 +235,42 @@ public class ModifierHelper extends AbstractBlenderHelper { } } + /** + * This method applies particles emitter to the given node. + * @param node the particles emitter node + * @param modifier the modifier containing the emitter data + * @param dataRepository the data repository + * @return node with particles' emitter applied + */ protected Node applyParticleSystemModifierData(Node node, Modifier modifier, DataRepository dataRepository) { MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class); ParticleEmitter emitter = (ParticleEmitter) modifier.getJmeModifierRepresentation(); emitter = emitter.clone(); + //veryfying the alpha function for particles' texture + Integer alphaFunction = MaterialHelper.ALPHA_MASK_HYPERBOLE; + char nameSuffix = emitter.getName().charAt(emitter.getName().length()-1); + if(nameSuffix=='B' || nameSuffix=='N') { + alphaFunction = MaterialHelper.ALPHA_MASK_NONE; + } + //removing the type suffix from the name + emitter.setName(emitter.getName().substring(0, emitter.getName().length()-1)); + //applying emitter shape EmitterShape emitterShape = emitter.getShape(); - if(emitterShape instanceof EmitterMeshVertexShape) { - List meshes = new ArrayList(); - for(Spatial spatial : node.getChildren()) { - if(spatial instanceof Geometry) { - Mesh mesh = ((Geometry) spatial).getMesh(); - if(mesh != null) { - meshes.add(mesh); - Material material = materialHelper.getParticlesMaterial(((Geometry) spatial).getMaterial(), dataRepository); - emitter.setMaterial(material);//TODO: rozbić na kilka części - } + List meshes = new ArrayList(); + for(Spatial spatial : node.getChildren()) { + if(spatial instanceof Geometry) { + Mesh mesh = ((Geometry) spatial).getMesh(); + if(mesh != null) { + meshes.add(mesh); + Material material = materialHelper.getParticlesMaterial(((Geometry) spatial).getMaterial(), alphaFunction, dataRepository); + emitter.setMaterial(material);//TODO: divide into several pieces } } - if(meshes.size()>0) { - ((EmitterMeshVertexShape) emitterShape).setMeshes(meshes); - } + } + if(meshes.size()>0 && emitterShape instanceof EmitterMeshVertexShape) { + ((EmitterMeshVertexShape) emitterShape).setMeshes(meshes); } node.attachChild(emitter); diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ParticlesHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ParticlesHelper.java index d068b06e5..1300fed18 100644 --- a/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ParticlesHelper.java +++ b/engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/ParticlesHelper.java @@ -7,8 +7,10 @@ import com.jme3.effect.EmitterMeshFaceShape; import com.jme3.effect.EmitterMeshVertexShape; import com.jme3.effect.ParticleEmitter; import com.jme3.effect.ParticleMesh.Type; +import com.jme3.effect.influencers.EmptyParticleInfluencer; +import com.jme3.effect.influencers.ParticleInfluencer; +import com.jme3.effect.influencers.NewtonianParticleInfluencer; import com.jme3.math.ColorRGBA; -import com.jme3.math.Vector3f; import com.jme3.scene.plugins.blender.data.Structure; import com.jme3.scene.plugins.blender.exception.BlenderFileException; import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper; @@ -62,6 +64,24 @@ public class ParticlesHelper extends AbstractBlenderHelper { public static final int PART_FROM_PARTICLE =3; public static final int PART_FROM_CHILD =4; + // part->phystype + public static final int PART_PHYS_NO = 0; + public static final int PART_PHYS_NEWTON= 1; + public static final int PART_PHYS_KEYED = 2; + public static final int PART_PHYS_BOIDS = 3; + + // part->draw_as + public static final int PART_DRAW_NOT = 0; + public static final int PART_DRAW_DOT = 1; + public static final int PART_DRAW_CIRC = 2; + public static final int PART_DRAW_CROSS = 3; + public static final int PART_DRAW_AXIS = 4; + public static final int PART_DRAW_LINE = 5; + public static final int PART_DRAW_PATH = 6; + public static final int PART_DRAW_OB = 7; + public static final int PART_DRAW_GR = 8; + public static final int PART_DRAW_BB = 9; + /** * This constructor parses the given blender version and stores the result. Some functionalities may differ in * different blender versions. @@ -78,8 +98,35 @@ public class ParticlesHelper extends AbstractBlenderHelper { Pointer pParticleSettings = (Pointer) particleSystem.getFieldValue("part"); if(!pParticleSettings.isNull()) { Structure particleSettings = pParticleSettings.fetchData(dataRepository.getInputStream()).get(0); + int totPart = ((Number) particleSettings.getFieldValue("totpart")).intValue(); - result = new ParticleEmitter(particleSettings.getName(), Type.Triangle, totPart); + + //draw type will be stored temporarily in the name (it is used during modifier applying operation) + int drawAs = ((Number)particleSettings.getFieldValue("draw_as")).intValue(); + char nameSuffix;//P - point, L - line, N - None, B - Bilboard + switch(drawAs) { + case PART_DRAW_NOT: + nameSuffix = 'N'; + totPart = 0;//no need to generate particles in this case + break; + case PART_DRAW_BB: + nameSuffix = 'B'; + break; + case PART_DRAW_OB: + case PART_DRAW_GR: + nameSuffix = 'P'; + LOGGER.warning("Neither object nor group particles supported yet! Using point representation instead!");//TODO: support groups and aobjects + break; + case PART_DRAW_LINE: + nameSuffix = 'L'; + LOGGER.warning("Lines not yet supported! Using point representation instead!");//TODO: support lines + default://all others are rendered as points in blender + nameSuffix = 'P'; + } + result = new ParticleEmitter(particleSettings.getName()+nameSuffix, Type.Triangle, totPart); + if(nameSuffix=='N') { + return result;//no need to set anything else + } //setting the emitters shape (the shapes meshes will be set later during modifier applying operation) int from = ((Number)particleSettings.getFieldValue("from")).intValue(); @@ -94,24 +141,49 @@ public class ParticlesHelper extends AbstractBlenderHelper { result.setShape(new EmitterMeshConvexHullShape()); break; default: - LOGGER.warning("Default shape used! Unknown emitter shape value ('from' parameter): " + from); + LOGGER.warning("Default shape used! Unknown emitter shape value ('from' parameter: " + from + ')'); } //reading acceleration DynamicArray acc = (DynamicArray) particleSettings.getFieldValue("acc"); - result.setInitialVelocity(new Vector3f(acc.get(0).floatValue(), acc.get(1).floatValue(), acc.get(2).floatValue())); - result.setGravity(0);//by default gravity is set to 0.1f so we need to disable it completely - // 2x2 texture animation - result.setImagesX(2); - result.setImagesY(2); - result.setEndColor(new ColorRGBA(1f, 0f, 0f, 1f)); // red - result.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f)); // yellow - result.setStartSize(1.5f); - result.setEndSize(0.1f); + result.setGravity(-acc.get(0).floatValue(), -acc.get(1).floatValue(), -acc.get(2).floatValue()); + + //setting the colors + result.setEndColor(new ColorRGBA(1f, 1f, 1f, 1f)); + result.setStartColor(new ColorRGBA(1f, 1f, 1f, 1f)); + + //reading size + float sizeFactor = nameSuffix=='B' ? 1.0f : 0.3f; + float size = ((Number)particleSettings.getFieldValue("size")).floatValue() * sizeFactor; + result.setStartSize(size); + result.setEndSize(size); - result.setLowLife(0.5f); - result.setHighLife(3f); - result.setVelocityVariation(0.3f); + //reading lifetime + int fps = dataRepository.getBlenderKey().getFps(); + float lifetime = ((Number)particleSettings.getFieldValue("lifetime")).floatValue() / fps; + float randlife = ((Number)particleSettings.getFieldValue("randlife")).floatValue() / fps; + result.setLowLife(lifetime * (1.0f - randlife)); + result.setHighLife(lifetime); + + //preparing influencer + ParticleInfluencer influencer; + int phystype = ((Number)particleSettings.getFieldValue("phystype")).intValue(); + switch(phystype) { + case PART_PHYS_NEWTON: + influencer = new NewtonianParticleInfluencer(); + ((NewtonianParticleInfluencer)influencer).setNormalVelocity(((Number)particleSettings.getFieldValue("normfac")).floatValue()); + ((NewtonianParticleInfluencer)influencer).setVelocityVariation(((Number)particleSettings.getFieldValue("randfac")).floatValue()); + ((NewtonianParticleInfluencer)influencer).setSurfaceTangentFactor(((Number)particleSettings.getFieldValue("tanfac")).floatValue()); + ((NewtonianParticleInfluencer)influencer).setSurfaceTangentRotation(((Number)particleSettings.getFieldValue("tanphase")).floatValue()); + break; + case PART_PHYS_BOIDS: + case PART_PHYS_KEYED://TODO: support other influencers + LOGGER.warning("Boids and Keyed particles physic not yet supported! Empty influencer used!"); + case PART_PHYS_NO: + default: + influencer = new EmptyParticleInfluencer(); + } + result.setParticleInfluencer(influencer); } return result; }