Browse Source

Fix to setting the normal texture if vertex coloring is enabled.

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7612 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
Kae..pl 14 years ago
parent
commit
5dc1a29f6e

+ 635 - 645
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/MaterialHelper.java

@@ -62,649 +62,639 @@ import com.jme3.texture.Texture.WrapMode;
 import com.jme3.util.BufferUtils;
 import com.jme3.util.BufferUtils;
 
 
 public class MaterialHelper extends AbstractBlenderHelper {
 public class MaterialHelper extends AbstractBlenderHelper {
-
-    private static final Logger LOGGER = Logger.getLogger(MaterialHelper.class.getName());
-    protected static final float DEFAULT_SHININESS = 20.0f;
-    public static final String TEXTURE_TYPE_COLOR = "ColorMap";
-    public static final String TEXTURE_TYPE_DIFFUSE = "DiffuseMap";
-    public static final String TEXTURE_TYPE_NORMAL = "NormalMap";
-    public static final String TEXTURE_TYPE_SPECULAR = "SpecularMap";
-    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<Integer, AlphaMask> alphaMasks = new HashMap<Integer, AlphaMask>();
-
-    /**
-     * The type of the material's diffuse shader.
-     */
-    public static enum DiffuseShader {
-
-        LAMBERT, ORENNAYAR, TOON, MINNAERT, FRESNEL
-    }
-
-    /**
-     * The type of the material's specular shader.
-     */
-    public static enum SpecularShader {
-
-        COOKTORRENCE, PHONG, BLINN, TOON, WARDISO
-    }
-    /** Face cull mode. Should be excplicitly set before this helper is used. */
-    protected FaceCullMode faceCullMode;
-
-    /**
-     * This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender
-     * versions.
-     * 
-     * @param blenderVersion
-     *        the version read from the blend file
-     */
-    public MaterialHelper(String blenderVersion) {
-        super(blenderVersion);
-        // setting alpha masks
-        alphaMasks.put(ALPHA_MASK_NONE, new AlphaMask() {
-
-            @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 AlphaMask() {
-
-            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 AlphaMask() {
-
-            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 AlphaMask() {
-
-            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);
-            }
-        });
-    }
-
-    /**
-     * This method sets the face cull mode to be used with every loaded material.
-     * 
-     * @param faceCullMode
-     *        the face cull mode
-     */
-    public void setFaceCullMode(FaceCullMode faceCullMode) {
-        this.faceCullMode = faceCullMode;
-    }
-
-    @SuppressWarnings("unchecked")
-    public Material toMaterial(Structure structure, DataRepository dataRepository) throws BlenderFileException {
-        LOGGER.log(Level.INFO, "Loading material.");
-        if (structure == null) {
-            return dataRepository.getDefaultMaterial();
-        }
-        Material result = (Material) dataRepository.getLoadedFeature(structure.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);
-        if (result != null) {
-            return result;
-        }
-
-        int mode = ((Number) structure.getFieldValue("mode")).intValue();
-        boolean shadeless = (mode & 0x4) != 0;
-        boolean vertexColor = (mode & 0x16) != 0;
-        boolean transparent = (mode & 0x64) != 0;
-
-        if (shadeless) {
-            result = new Material(dataRepository.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
-        } else {
-            result = new Material(dataRepository.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
-        }
-
-        result.getAdditionalRenderState().setFaceCullMode(faceCullMode);
-
-        if (transparent) {
-            result.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
-        }
-
-        String name = structure.getName();
-        LOGGER.log(Level.INFO, "Material's name: {0}", name);
-        if (vertexColor) {
-            if (shadeless) {
-                result.setBoolean("VertexColor", true);
-            } else {
-                result.setBoolean("UseVertexColor", true);
-            }
-        }
-
-        MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);
-        ColorRGBA diffuseColor = null;
-        if (shadeless) {
-            // color of shadeless? doesn't seem to work in blender ..
-        } else {
-            result.setBoolean("UseMaterialColors", true);
-
-            // setting the colors
-            DiffuseShader diffuseShader = materialHelper.getDiffuseShader(structure);
-            result.setBoolean("Minnaert", diffuseShader == DiffuseShader.MINNAERT);
-            diffuseColor = materialHelper.getDiffuseColor(structure, diffuseShader);
-            result.setColor("Diffuse", diffuseColor);
-
-            SpecularShader specularShader = materialHelper.getSpecularShader(structure);
-            result.setBoolean("WardIso", specularShader == SpecularShader.WARDISO);
-            result.setColor("Specular", materialHelper.getSpecularColor(structure, specularShader));
-
-            result.setColor("Ambient", materialHelper.getAmbientColor(structure));
-            result.setFloat("Shininess", materialHelper.getShininess(structure));
-        }
-
-        // texture
-        if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.TEXTURES) != 0) {
-            TextureHelper textureHelper = dataRepository.getHelper(TextureHelper.class);
-            DynamicArray<Pointer> mtexs = (DynamicArray<Pointer>) structure.getFieldValue("mtex");
-            for (int i = 0; i < mtexs.getTotalSize(); ++i) {
-                Pointer p = mtexs.get(i);
-                if (!p.isNull()) {
-                    List<Structure> mtex = p.fetchData(dataRepository.getInputStream());
-                    if (mtex.size() == 1) {
-                        Structure textureLink = mtex.get(0);
-                        int texflag = ((Number) textureLink.getFieldValue("texflag")).intValue();
-                        // int texco = ((Number) textureLink.getFieldValue("texco")).intValue();
-                        boolean negateTexture = (texflag & 0x04) == 0;
-
-                        // if(texco == 0x10) {//TEXCO_UV (this is only supported now)
-                        int mapto = ((Number) textureLink.getFieldValue("mapto")).intValue();
-                        if (mapto != 0) {
-                            Pointer pTex = (Pointer) textureLink.getFieldValue("tex");
-                            Structure tex = pTex.fetchData(dataRepository.getInputStream()).get(0);
-                            Texture texture = textureHelper.getTexture(tex, dataRepository);
-                            if (texture != null) {
-                                if ((mapto & 0x01) != 0) {// Col
-                                    if (!shadeless){
-                                        result.setBoolean("UseMaterialColors", false);
-                                    }
-                                    
-                                    // blending the texture with material color and texture's defined color
-                                    int blendType = ((Number) textureLink.getFieldValue("blendtype")).intValue();
-                                    float[] color = new float[]{((Number) textureLink.getFieldValue("r")).floatValue(), ((Number) textureLink.getFieldValue("g")).floatValue(), ((Number) textureLink.getFieldValue("b")).floatValue()};
-                                    float colfac = ((Number) textureLink.getFieldValue("colfac")).floatValue();
-                                    texture = textureHelper.blendTexture(diffuseColor.getColorArray(), texture, color, colfac, blendType, negateTexture, dataRepository);
-                                    texture.setWrap(WrapMode.Repeat);
-                                    if (shadeless) {
-                                        result.setTexture(TEXTURE_TYPE_COLOR, texture);
-                                    } else {
-                                        result.setTexture(TEXTURE_TYPE_DIFFUSE, texture);
-                                    }
-                                }
-                                if ((mapto & 0x02) != 0) {// Nor
-                                    result.setTexture(TEXTURE_TYPE_NORMAL, texture);
-                                }
-                                if ((mapto & 0x20) != 0) {// Spec
-                                    result.setTexture(TEXTURE_TYPE_SPECULAR, texture);
-                                }
-                                if ((mapto & 0x40) != 0) {// Emit
-                                    result.setTexture(TEXTURE_TYPE_GLOW, texture);
-                                }
-                                if ((mapto & 0x80) != 0) {// Alpha
-                                    result.setTexture(TEXTURE_TYPE_ALPHA, texture);
-                                }
-                            } else {
-                                LOGGER.log(Level.WARNING, "Texture not found!");
-                            }
-                        }
-                        // } else {
-                        // Pointer pTex = (Pointer)textureLink.getFieldValue("tex");
-                        // List<Structure> texs = pTex.fetchData(dataRepository.getInputStream());
-                        // Structure tex = texs.get(0);
-                        // LOGGER.log(Level.WARNING, "Unsupported texture type: " + texco);
-                        // }
-                    } else {
-                        LOGGER.log(Level.WARNING, "Many textures. Not solved yet!");// TODO
-                    }
-                }
-            }
-        }
-        dataRepository.addLoadedFeatures(structure.getOldMemoryAddress(), structure.getName(), structure, result);
-        return result;
-    }
-
-    /**
-     * This method returns a material similar to the one given but without textures. If the material has no textures it is not cloned but
-     * returned itself.
-     * 
-     * @param material
-     *        a material to be cloned without textures
-     * @param imageType
-     *        type of image defined by blender; the constants are defined in TextureHelper
-     * @return material without textures of a specified type
-     */
-    public Material getNonTexturedMaterial(Material material, int imageType) {
-        String[] textureParamNames = new String[]{TEXTURE_TYPE_DIFFUSE, TEXTURE_TYPE_NORMAL, TEXTURE_TYPE_GLOW, TEXTURE_TYPE_SPECULAR, TEXTURE_TYPE_ALPHA};
-        Map<String, Texture> textures = new HashMap<String, Texture>(textureParamNames.length);
-        for (String textureParamName : textureParamNames) {
-            MatParamTexture matParamTexture = material.getTextureParam(textureParamName);
-            if (matParamTexture != null) {
-                textures.put(textureParamName, matParamTexture.getTextureValue());
-            }
-        }
-        if (textures.isEmpty()) {
-            return material;
-        } else {
-            // clear all textures first so that wo de not waste resources cloning them
-            for (Entry<String, Texture> textureParamName : textures.entrySet()) {
-                String name = textureParamName.getValue().getName();
-                try {
-                    int type = Integer.parseInt(name);
-                    if (type == imageType) {
-                        material.clearParam(textureParamName.getKey());
-                    }
-                } catch (NumberFormatException e) {
-                    LOGGER.log(Level.WARNING, "The name of the texture does not contain the texture type value! {0} will not be removed!", name);
-                }
-            }
-            Material result = material.clone();
-            // put the textures back in place
-            for (Entry<String, Texture> textureEntry : textures.entrySet()) {
-                material.setTexture(textureEntry.getKey(), textureEntry.getValue());
-            }
-            return result;
-        }
-    }
-
-    /**
-     * This method converts the given material into particles-usable material.
-     * The texture and glow color are being copied.
-     * The method assumes it receives the Lighting type of material.
-     * @param material
-     *        the source material
-     * @param dataRepository
-     *        the data repository
-     * @return material converted into particles-usable material
-     */
-    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()).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);
-            AlphaMask iAlphaMask = alphaMasks.get(alphaMaskIndex);
-            iAlphaMask.setImageSize(w, h);
-
-            for (int x = 0; x < w; ++x) {
-                for (int y = 0; y < h; ++y) {
-                    bb.put(sourceBB.get());
-                    bb.put(sourceBB.get());
-                    bb.put(sourceBB.get());
-                    bb.put(iAlphaMask.getAlpha(x, y));
-                }
-            }
-
-            image = new Image(Format.RGBA8, w, h, bb);
-            texture.setImage(image);
-
-            result.setTextureParam("Texture", VarType.Texture2D, texture);
-        }
-
-        // copying glow color
-        MatParam glowColor = material.getParam("GlowColor");
-        if (glowColor != null) {
-            ColorRGBA color = (ColorRGBA) glowColor.getValue();
-            result.setParam("GlowColor", VarType.Vector3, color);
-        }
-        return result;
-    }
-
-    /**
-     * This method indicates if the material has a texture of a specified type.
-     * 
-     * @param material
-     *        the material
-     * @param textureType
-     *        the type of the texture
-     * @return <b>true</b> if the texture exists in the material and <B>false</b> otherwise
-     */
-    public boolean hasTexture(Material material, String textureType) {
-        if (material != null) {
-            return material.getTextureParam(textureType) != null;
-        }
-        return false;
-    }
-
-    /**
-     * This method returns the diffuse color
-     * 
-     * @param materialStructure
-     * @param diffuseShader
-     * @return
-     */
-    public ColorRGBA getDiffuseColor(Structure materialStructure, DiffuseShader diffuseShader) {
-        // bitwise 'or' of all textures mappings
-        int commonMapto = ((Number) materialStructure.getFieldValue("mapto")).intValue();
-
-        // diffuse color
-        float r = ((Number) materialStructure.getFieldValue("r")).floatValue();
-        float g = ((Number) materialStructure.getFieldValue("g")).floatValue();
-        float b = ((Number) materialStructure.getFieldValue("b")).floatValue();
-        float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();
-        if ((commonMapto & 0x01) == 0x01) {// Col
-            return new ColorRGBA(r, g, b, alpha);
-        } else {
-            switch (diffuseShader) {
-                case FRESNEL:
-                case ORENNAYAR:
-                case TOON:
-                    break;// TODO: find what is the proper modification
-                case MINNAERT:
-                case LAMBERT:// TODO: check if that is correct
-                    float ref = ((Number) materialStructure.getFieldValue("ref")).floatValue();
-                    r *= ref;
-                    g *= ref;
-                    b *= ref;
-                    break;
-                default:
-                    throw new IllegalStateException("Unknown diffuse shader type: " + diffuseShader.toString());
-            }
-            return new ColorRGBA(r, g, b, alpha);
-        }
-    }
-
-    /**
-     * This method returns an enum describing the type of a diffuse shader used by this material.
-     * 
-     * @param materialStructure
-     *        the material structure filled with data
-     * @return an enum describing the type of a diffuse shader used by this material
-     */
-    public DiffuseShader getDiffuseShader(Structure materialStructure) {
-        int diff_shader = ((Number) materialStructure.getFieldValue("diff_shader")).intValue();
-        return DiffuseShader.values()[diff_shader];
-    }
-
-    /**
-     * This method returns an ambient color used by the material.
-     * 
-     * @param materialStructure
-     *        the material structure filled with data
-     * @return an ambient color used by the material
-     */
-    public ColorRGBA getAmbientColor(Structure materialStructure) {
-        float r = ((Number) materialStructure.getFieldValue("ambr")).floatValue();
-        float g = ((Number) materialStructure.getFieldValue("ambg")).floatValue();
-        float b = ((Number) materialStructure.getFieldValue("ambb")).floatValue();
-        float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();
-        return new ColorRGBA(r, g, b, alpha);
-    }
-
-    /**
-     * This method returns an enum describing the type of a specular shader used by this material.
-     * 
-     * @param materialStructure
-     *        the material structure filled with data
-     * @return an enum describing the type of a specular shader used by this material
-     */
-    public SpecularShader getSpecularShader(Structure materialStructure) {
-        int spec_shader = ((Number) materialStructure.getFieldValue("spec_shader")).intValue();
-        return SpecularShader.values()[spec_shader];
-    }
-
-    /**
-     * This method returns a specular color used by the material.
-     * 
-     * @param materialStructure
-     *        the material structure filled with data
-     * @return a specular color used by the material
-     */
-    public ColorRGBA getSpecularColor(Structure materialStructure, SpecularShader specularShader) {
-        float r = ((Number) materialStructure.getFieldValue("specr")).floatValue();
-        float g = ((Number) materialStructure.getFieldValue("specg")).floatValue();
-        float b = ((Number) materialStructure.getFieldValue("specb")).floatValue();
-        float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();
-        switch (specularShader) {
-            case BLINN:
-            case COOKTORRENCE:
-            case TOON:
-            case WARDISO:// TODO: find what is the proper modification
-                break;
-            case PHONG:// TODO: check if that is correct
-                float spec = ((Number) materialStructure.getFieldValue("spec")).floatValue();
-                r *= spec * 0.5f;
-                g *= spec * 0.5f;
-                b *= spec * 0.5f;
-                break;
-            default:
-                throw new IllegalStateException("Unknown specular shader type: " + specularShader.toString());
-        }
-        return new ColorRGBA(r, g, b, alpha);
-    }
-
-    /**
-     * This method returns the sihiness of this material or DEFAULT_SHININESS value if not present.
-     * 
-     * @param materialStructure
-     *        the material structure filled with data
-     * @return the sihiness of this material or DEFAULT_SHININESS value if not present
-     */
-    public float getShininess(Structure materialStructure) {
-        float shininess = ((Number) materialStructure.getFieldValue("emit")).floatValue();
-        return shininess > 0.0f ? shininess : DEFAULT_SHININESS;
-    }
-
-    /**
-     * This method returns the table of materials connected to the specified structure. The given structure can be of any type (ie. mesh or
-     * curve) but needs to have 'mat' field/
-     * 
-     * @param structureWithMaterials
-     *        the structure containing the mesh data
-     * @param dataRepository
-     *        the data repository
-     * @return a list of vertices colors, each color belongs to a single vertex
-     * @throws BlenderFileException
-     *         this exception is thrown when the blend file structure is somehow invalid or corrupted
-     */
-    public Material[] getMaterials(Structure structureWithMaterials, DataRepository dataRepository) throws BlenderFileException {
-        Pointer ppMaterials = (Pointer) structureWithMaterials.getFieldValue("mat");
-        Material[] materials = null;
-        if (!ppMaterials.isNull()) {
-            List<Structure> materialStructures = ppMaterials.fetchData(dataRepository.getInputStream());
-            if (materialStructures != null && materialStructures.size() > 0) {
-                MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);
-                materials = new Material[materialStructures.size()];
-                int i = 0;
-                for (Structure s : materialStructures) {
-                    Material material = (Material) dataRepository.getLoadedFeature(s.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);
-                    if (material == null) {
-                        material = materialHelper.toMaterial(s, dataRepository);
-                    }
-                    materials[i++] = material;
-                }
-            }
-        }
-        return materials;
-    }
-
-    /**
-     * This method converts rgb values to hsv values.
-     * 
-     * @param rgb
-     *        rgb values of the color
-     * @param hsv
-     *        hsv values of a color (this table contains the result of the transformation)
-     */
-    public void rgbToHsv(float r, float g, float b, float[] hsv) {
-        float cmax = r;
-        float cmin = r;
-        cmax = g > cmax ? g : cmax;
-        cmin = g < cmin ? g : cmin;
-        cmax = b > cmax ? b : cmax;
-        cmin = b < cmin ? b : cmin;
-
-        hsv[2] = cmax; /* value */
-        if (cmax != 0.0) {
-            hsv[1] = (cmax - cmin) / cmax;
-        } else {
-            hsv[1] = 0.0f;
-            hsv[0] = 0.0f;
-        }
-        if (hsv[1] == 0.0) {
-            hsv[0] = -1.0f;
-        } else {
-            float cdelta = cmax - cmin;
-            float rc = (cmax - r) / cdelta;
-            float gc = (cmax - g) / cdelta;
-            float bc = (cmax - b) / cdelta;
-            if (r == cmax) {
-                hsv[0] = bc - gc;
-            } else if (g == cmax) {
-                hsv[0] = 2.0f + rc - bc;
-            } else {
-                hsv[0] = 4.0f + gc - rc;
-            }
-            hsv[0] *= 60.0f;
-            if (hsv[0] < 0.0f) {
-                hsv[0] += 360.0f;
-            }
-        }
-
-        hsv[0] /= 360.0f;
-        if (hsv[0] < 0.0f) {
-            hsv[0] = 0.0f;
-        }
-    }
-
-    /**
-     * This method converts rgb values to hsv values.
-     * 
-     * @param h
-     *        hue
-     * @param s
-     *        saturation
-     * @param v
-     *        value
-     * @param rgb
-     *        rgb result vector (should have 3 elements)
-     */
-    public void hsvToRgb(float h, float s, float v, float[] rgb) {
-        h *= 360.0f;
-        if (s == 0.0) {
-            rgb[0] = rgb[1] = rgb[2] = v;
-        } else {
-            if (h == 360) {
-                h = 0;
-            } else {
-                h /= 60;
-            }
-            int i = (int) Math.floor(h);
-            float f = h - i;
-            float p = v * (1.0f - s);
-            float q = v * (1.0f - s * f);
-            float t = v * (1.0f - s * (1.0f - f));
-            switch (i) {
-                case 0:
-                    rgb[0] = v;
-                    rgb[1] = t;
-                    rgb[2] = p;
-                    break;
-                case 1:
-                    rgb[0] = q;
-                    rgb[1] = v;
-                    rgb[2] = p;
-                    break;
-                case 2:
-                    rgb[0] = p;
-                    rgb[1] = v;
-                    rgb[2] = t;
-                    break;
-                case 3:
-                    rgb[0] = p;
-                    rgb[1] = q;
-                    rgb[2] = v;
-                    break;
-                case 4:
-                    rgb[0] = t;
-                    rgb[1] = p;
-                    rgb[2] = v;
-                    break;
-                case 5:
-                    rgb[0] = v;
-                    rgb[1] = p;
-                    rgb[2] = q;
-                    break;
-            }
-        }
-    }
-
-    /**
-     * An interface used in calculating alpha mask during particles' texture calculations.
-     * @author Marcin Roguski (Kaelthas)
-     */
-    protected static interface AlphaMask {
-
-        /**
-         * This method sets the size of the texture's image.
-         * @param width
-         *        the width of the image
-         * @param height
-         *        the height of the image
-         */
-        void setImageSize(int width, int height);
-
-        /**
-         * This method returns the alpha value for the specified texture position.
-         * @param x
-         *        the X coordinate of the texture position
-         * @param y
-         *        the Y coordinate of the texture position
-         * @return the alpha value for the specified texture position
-         */
-        byte getAlpha(float x, float y);
-    }
+	private static final Logger					LOGGER					= Logger.getLogger(MaterialHelper.class.getName());
+	protected static final float				DEFAULT_SHININESS		= 20.0f;
+
+	public static final String					TEXTURE_TYPE_COLOR		= "ColorMap";
+	public static final String					TEXTURE_TYPE_DIFFUSE	= "DiffuseMap";
+	public static final String					TEXTURE_TYPE_NORMAL		= "NormalMap";
+	public static final String					TEXTURE_TYPE_SPECULAR	= "SpecularMap";
+	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<Integer, IAlphaMask>	alphaMasks				= new HashMap<Integer, IAlphaMask>();
+
+	/**
+	 * The type of the material's diffuse shader.
+	 */
+	public static enum DiffuseShader {
+		LAMBERT, ORENNAYAR, TOON, MINNAERT, FRESNEL
+	}
+
+	/**
+	 * The type of the material's specular shader.
+	 */
+	public static enum SpecularShader {
+		COOKTORRENCE, PHONG, BLINN, TOON, WARDISO
+	}
+
+	/** Face cull mode. Should be excplicitly set before this helper is used. */
+	protected FaceCullMode	faceCullMode;
+
+	/**
+	 * This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender
+	 * versions.
+	 * 
+	 * @param blenderVersion
+	 *        the version read from the blend file
+	 */
+	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);
+			}
+		});
+	}
+
+	/**
+	 * This method sets the face cull mode to be used with every loaded material.
+	 * 
+	 * @param faceCullMode
+	 *        the face cull mode
+	 */
+	public void setFaceCullMode(FaceCullMode faceCullMode) {
+		this.faceCullMode = faceCullMode;
+	}
+
+	@SuppressWarnings("unchecked")
+	public Material toMaterial(Structure structure, DataRepository dataRepository) throws BlenderFileException {
+		LOGGER.log(Level.INFO, "Loading material.");
+		if (structure == null) {
+			return dataRepository.getDefaultMaterial();
+		}
+		Material result = (Material) dataRepository.getLoadedFeature(structure.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);
+		if (result != null) {
+			return result;
+		}
+
+		int mode = ((Number) structure.getFieldValue("mode")).intValue();
+		boolean shadeless = (mode & 0x4) != 0;
+		boolean vertexColor = (mode & 0x16) != 0;
+		boolean transparent = (mode & 0x64) != 0;
+
+		if (shadeless) {
+			result = new Material(dataRepository.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
+		} else {
+			result = new Material(dataRepository.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
+		}
+
+		result.getAdditionalRenderState().setFaceCullMode(faceCullMode);
+
+		if (transparent) {
+			result.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
+		}
+
+		String name = structure.getName();
+		LOGGER.log(Level.INFO, "Material's name: {0}", name);
+		if (vertexColor) {
+			result.setBoolean(shadeless ? "VertexColor" : "UseVertexColor", true);
+		}
+
+		MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);
+		ColorRGBA diffuseColor = null;
+		if (shadeless) {
+			// color of shadeless? doesn't seem to work in blender ..
+		} else {
+			result.setBoolean("UseMaterialColors", Boolean.TRUE);
+
+			// setting the colors
+			DiffuseShader diffuseShader = materialHelper.getDiffuseShader(structure);
+			result.setBoolean("Minnaert", diffuseShader == DiffuseShader.MINNAERT);
+			diffuseColor = materialHelper.getDiffuseColor(structure, diffuseShader);
+			result.setColor("Diffuse", diffuseColor);
+
+			SpecularShader specularShader = materialHelper.getSpecularShader(structure);
+			result.setBoolean("WardIso", specularShader == SpecularShader.WARDISO);
+			result.setColor("Specular", materialHelper.getSpecularColor(structure, specularShader));
+
+			result.setColor("Ambient", materialHelper.getAmbientColor(structure));
+			result.setFloat("Shininess", materialHelper.getShininess(structure));
+		}
+
+		// texture
+		if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.TEXTURES) != 0) {
+			TextureHelper textureHelper = dataRepository.getHelper(TextureHelper.class);
+			DynamicArray<Pointer> mtexs = (DynamicArray<Pointer>) structure.getFieldValue("mtex");
+			for (int i = 0; i < mtexs.getTotalSize(); ++i) {
+				Pointer p = mtexs.get(i);
+				if (!p.isNull()) {
+					List<Structure> mtex = p.fetchData(dataRepository.getInputStream());
+					if (mtex.size() == 1) {
+						Structure textureLink = mtex.get(0);
+						int texflag = ((Number) textureLink.getFieldValue("texflag")).intValue();
+						// int texco = ((Number) textureLink.getFieldValue("texco")).intValue();
+						boolean negateTexture = (texflag & 0x04) == 0;
+
+						// if(texco == 0x10) {//TEXCO_UV (this is only supported now)
+						int mapto = ((Number) textureLink.getFieldValue("mapto")).intValue();
+						if (mapto != 0) {
+							Pointer pTex = (Pointer) textureLink.getFieldValue("tex");
+							Structure tex = pTex.fetchData(dataRepository.getInputStream()).get(0);
+							Texture texture = textureHelper.getTexture(tex, dataRepository);
+							if (texture != null) {
+								if ((mapto & 0x01) != 0) {// Col
+									result.setBoolean("UseMaterialColors", Boolean.FALSE);
+									// blending the texture with material color and texture's defined color
+									int blendType = ((Number) textureLink.getFieldValue("blendtype")).intValue();
+									float[] color = new float[] { ((Number) textureLink.getFieldValue("r")).floatValue(), ((Number) textureLink.getFieldValue("g")).floatValue(), ((Number) textureLink.getFieldValue("b")).floatValue() };
+									float colfac = ((Number) textureLink.getFieldValue("colfac")).floatValue();
+									texture = textureHelper.blendTexture(diffuseColor.getColorArray(), texture, color, colfac, blendType, negateTexture, dataRepository);
+									texture.setWrap(WrapMode.Repeat);
+									if (shadeless) {
+										result.setTexture(TEXTURE_TYPE_COLOR, texture);
+									} else {
+										result.setTexture(TEXTURE_TYPE_DIFFUSE, texture);
+									}
+								}
+								if ((mapto & 0x02) != 0) {// Nor
+									result.setTexture(TEXTURE_TYPE_NORMAL, texture);
+									if (vertexColor) {
+										result.setBoolean(shadeless ? "VertexColor" : "UseVertexColor", false);
+									}
+								}
+								if ((mapto & 0x04) != 0) {// Spec
+									result.setTexture(TEXTURE_TYPE_SPECULAR, texture);
+								}
+								if ((mapto & 0x40) != 0) {// Emit
+									result.setTexture(TEXTURE_TYPE_GLOW, texture);
+								}
+								if ((mapto & 0x80) != 0) {// Alpha
+									result.setTexture(TEXTURE_TYPE_ALPHA, texture);
+								}
+							} else {
+								LOGGER.log(Level.WARNING, "Texture not found!");
+							}
+						}
+						// } else {
+						// Pointer pTex = (Pointer)textureLink.getFieldValue("tex");
+						// List<Structure> texs = pTex.fetchData(dataRepository.getInputStream());
+						// Structure tex = texs.get(0);
+						// LOGGER.log(Level.WARNING, "Unsupported texture type: " + texco);
+						// }
+					} else {
+						LOGGER.log(Level.WARNING, "Many textures. Not solved yet!");// TODO
+					}
+				}
+			}
+		}
+		dataRepository.addLoadedFeatures(structure.getOldMemoryAddress(), structure.getName(), structure, result);
+		return result;
+	}
+
+	/**
+	 * This method returns a material similar to the one given but without textures. If the material has no textures it is not cloned but
+	 * returned itself.
+	 * 
+	 * @param material
+	 *        a material to be cloned without textures
+	 * @param imageType
+	 *        type of image defined by blender; the constants are defined in TextureHelper
+	 * @return material without textures of a specified type
+	 */
+	public Material getNonTexturedMaterial(Material material, int imageType) {
+		String[] textureParamNames = new String[] { TEXTURE_TYPE_DIFFUSE, TEXTURE_TYPE_NORMAL, TEXTURE_TYPE_GLOW, TEXTURE_TYPE_SPECULAR, TEXTURE_TYPE_ALPHA };
+		Map<String, Texture> textures = new HashMap<String, Texture>(textureParamNames.length);
+		for (String textureParamName : textureParamNames) {
+			MatParamTexture matParamTexture = material.getTextureParam(textureParamName);
+			if (matParamTexture != null) {
+				textures.put(textureParamName, matParamTexture.getTextureValue());
+			}
+		}
+		if (textures.isEmpty()) {
+			return material;
+		} else {
+			// clear all textures first so that wo de not waste resources cloning them
+			for (Entry<String, Texture> textureParamName : textures.entrySet()) {
+				String name = textureParamName.getValue().getName();
+				try {
+					int type = Integer.parseInt(name);
+					if (type == imageType) {
+						material.clearParam(textureParamName.getKey());
+					}
+				} catch (NumberFormatException e) {
+					LOGGER.log(Level.WARNING, "The name of the texture does not contain the texture type value! {0} will not be removed!", name);
+				}
+			}
+			Material result = material.clone();
+			// put the textures back in place
+			for (Entry<String, Texture> textureEntry : textures.entrySet()) {
+				material.setTexture(textureEntry.getKey(), textureEntry.getValue());
+			}
+			return result;
+		}
+	}
+
+	/**
+	 * This method converts the given material into particles-usable material.
+	 * The texture and glow color are being copied.
+	 * The method assumes it receives the Lighting type of material.
+	 * @param material
+	 *        the source material
+	 * @param dataRepository
+	 *        the data repository
+	 * @return material converted into particles-usable material
+	 */
+	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()).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 < w; ++x) {
+				for (int y = 0; y < h; ++y) {
+					bb.put(sourceBB.get());
+					bb.put(sourceBB.get());
+					bb.put(sourceBB.get());
+					bb.put(iAlphaMask.getAlpha(x, y));
+				}
+			}
+
+			image = new Image(Format.RGBA8, w, h, bb);
+			texture.setImage(image);
+
+			result.setTextureParam("Texture", VarType.Texture2D, texture);
+		}
+
+		// copying glow color
+		MatParam glowColor = material.getParam("GlowColor");
+		if (glowColor != null) {
+			ColorRGBA color = (ColorRGBA) glowColor.getValue();
+			result.setParam("GlowColor", VarType.Vector3, color);
+		}
+		return result;
+	}
+
+	/**
+	 * This method indicates if the material has a texture of a specified type.
+	 * 
+	 * @param material
+	 *        the material
+	 * @param textureType
+	 *        the type of the texture
+	 * @return <b>true</b> if the texture exists in the material and <B>false</b> otherwise
+	 */
+	public boolean hasTexture(Material material, String textureType) {
+		if (material != null) {
+			return material.getTextureParam(textureType) != null;
+		}
+		return false;
+	}
+
+	/**
+	 * This method returns the diffuse color
+	 * 
+	 * @param materialStructure
+	 * @param diffuseShader
+	 * @return
+	 */
+	public ColorRGBA getDiffuseColor(Structure materialStructure, DiffuseShader diffuseShader) {
+		// bitwise 'or' of all textures mappings
+		int commonMapto = ((Number) materialStructure.getFieldValue("mapto")).intValue();
+
+		// diffuse color
+		float r = ((Number) materialStructure.getFieldValue("r")).floatValue();
+		float g = ((Number) materialStructure.getFieldValue("g")).floatValue();
+		float b = ((Number) materialStructure.getFieldValue("b")).floatValue();
+		float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();
+		if ((commonMapto & 0x01) == 0x01) {// Col
+			return new ColorRGBA(r, g, b, alpha);
+		} else {
+			switch (diffuseShader) {
+				case FRESNEL:
+				case ORENNAYAR:
+				case TOON:
+					break;// TODO: find what is the proper modification
+				case MINNAERT:
+				case LAMBERT:// TODO: check if that is correct
+					float ref = ((Number) materialStructure.getFieldValue("ref")).floatValue();
+					r *= ref;
+					g *= ref;
+					b *= ref;
+					break;
+				default:
+					throw new IllegalStateException("Unknown diffuse shader type: " + diffuseShader.toString());
+			}
+			return new ColorRGBA(r, g, b, alpha);
+		}
+	}
+
+	/**
+	 * This method returns an enum describing the type of a diffuse shader used by this material.
+	 * 
+	 * @param materialStructure
+	 *        the material structure filled with data
+	 * @return an enum describing the type of a diffuse shader used by this material
+	 */
+	public DiffuseShader getDiffuseShader(Structure materialStructure) {
+		int diff_shader = ((Number) materialStructure.getFieldValue("diff_shader")).intValue();
+		return DiffuseShader.values()[diff_shader];
+	}
+
+	/**
+	 * This method returns an ambient color used by the material.
+	 * 
+	 * @param materialStructure
+	 *        the material structure filled with data
+	 * @return an ambient color used by the material
+	 */
+	public ColorRGBA getAmbientColor(Structure materialStructure) {
+		float r = ((Number) materialStructure.getFieldValue("ambr")).floatValue();
+		float g = ((Number) materialStructure.getFieldValue("ambg")).floatValue();
+		float b = ((Number) materialStructure.getFieldValue("ambb")).floatValue();
+		float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();
+		return new ColorRGBA(r, g, b, alpha);
+	}
+
+	/**
+	 * This method returns an enum describing the type of a specular shader used by this material.
+	 * 
+	 * @param materialStructure
+	 *        the material structure filled with data
+	 * @return an enum describing the type of a specular shader used by this material
+	 */
+	public SpecularShader getSpecularShader(Structure materialStructure) {
+		int spec_shader = ((Number) materialStructure.getFieldValue("spec_shader")).intValue();
+		return SpecularShader.values()[spec_shader];
+	}
+
+	/**
+	 * This method returns a specular color used by the material.
+	 * 
+	 * @param materialStructure
+	 *        the material structure filled with data
+	 * @return a specular color used by the material
+	 */
+	public ColorRGBA getSpecularColor(Structure materialStructure, SpecularShader specularShader) {
+		float r = ((Number) materialStructure.getFieldValue("specr")).floatValue();
+		float g = ((Number) materialStructure.getFieldValue("specg")).floatValue();
+		float b = ((Number) materialStructure.getFieldValue("specb")).floatValue();
+		float alpha = ((Number) materialStructure.getFieldValue("alpha")).floatValue();
+		switch (specularShader) {
+			case BLINN:
+			case COOKTORRENCE:
+			case TOON:
+			case WARDISO:// TODO: find what is the proper modification
+				break;
+			case PHONG:// TODO: check if that is correct
+				float spec = ((Number) materialStructure.getFieldValue("spec")).floatValue();
+				r *= spec * 0.5f;
+				g *= spec * 0.5f;
+				b *= spec * 0.5f;
+				break;
+			default:
+				throw new IllegalStateException("Unknown specular shader type: " + specularShader.toString());
+		}
+		return new ColorRGBA(r, g, b, alpha);
+	}
+
+	/**
+	 * This method returns the sihiness of this material or DEFAULT_SHININESS value if not present.
+	 * 
+	 * @param materialStructure
+	 *        the material structure filled with data
+	 * @return the sihiness of this material or DEFAULT_SHININESS value if not present
+	 */
+	public float getShininess(Structure materialStructure) {
+		float shininess = ((Number) materialStructure.getFieldValue("emit")).floatValue();
+		return shininess > 0.0f ? shininess : DEFAULT_SHININESS;
+	}
+
+	/**
+	 * This method returns the table of materials connected to the specified structure. The given structure can be of any type (ie. mesh or
+	 * curve) but needs to have 'mat' field/
+	 * 
+	 * @param structureWithMaterials
+	 *        the structure containing the mesh data
+	 * @param dataRepository
+	 *        the data repository
+	 * @return a list of vertices colors, each color belongs to a single vertex
+	 * @throws BlenderFileException
+	 *         this exception is thrown when the blend file structure is somehow invalid or corrupted
+	 */
+	public Material[] getMaterials(Structure structureWithMaterials, DataRepository dataRepository) throws BlenderFileException {
+		Pointer ppMaterials = (Pointer) structureWithMaterials.getFieldValue("mat");
+		Material[] materials = null;
+		if (!ppMaterials.isNull()) {
+			List<Structure> materialStructures = ppMaterials.fetchData(dataRepository.getInputStream());
+			if (materialStructures != null && materialStructures.size() > 0) {
+				MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);
+				materials = new Material[materialStructures.size()];
+				int i = 0;
+				for (Structure s : materialStructures) {
+					Material material = (Material) dataRepository.getLoadedFeature(s.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);
+					if (material == null) {
+						material = materialHelper.toMaterial(s, dataRepository);
+					}
+					materials[i++] = material;
+				}
+			}
+		}
+		return materials;
+	}
+
+	/**
+	 * This method converts rgb values to hsv values.
+	 * 
+	 * @param rgb
+	 *        rgb values of the color
+	 * @param hsv
+	 *        hsv values of a color (this table contains the result of the transformation)
+	 */
+	public void rgbToHsv(float r, float g, float b, float[] hsv) {
+		float cmax = r;
+		float cmin = r;
+		cmax = g > cmax ? g : cmax;
+		cmin = g < cmin ? g : cmin;
+		cmax = b > cmax ? b : cmax;
+		cmin = b < cmin ? b : cmin;
+
+		hsv[2] = cmax; /* value */
+		if (cmax != 0.0) {
+			hsv[1] = (cmax - cmin) / cmax;
+		} else {
+			hsv[1] = 0.0f;
+			hsv[0] = 0.0f;
+		}
+		if (hsv[1] == 0.0) {
+			hsv[0] = -1.0f;
+		} else {
+			float cdelta = cmax - cmin;
+			float rc = (cmax - r) / cdelta;
+			float gc = (cmax - g) / cdelta;
+			float bc = (cmax - b) / cdelta;
+			if (r == cmax) {
+				hsv[0] = bc - gc;
+			} else if (g == cmax) {
+				hsv[0] = 2.0f + rc - bc;
+			} else {
+				hsv[0] = 4.0f + gc - rc;
+			}
+			hsv[0] *= 60.0f;
+			if (hsv[0] < 0.0f) {
+				hsv[0] += 360.0f;
+			}
+		}
+
+		hsv[0] /= 360.0f;
+		if (hsv[0] < 0.0f) {
+			hsv[0] = 0.0f;
+		}
+	}
+
+	/**
+	 * This method converts rgb values to hsv values.
+	 * 
+	 * @param h
+	 *        hue
+	 * @param s
+	 *        saturation
+	 * @param v
+	 *        value
+	 * @param rgb
+	 *        rgb result vector (should have 3 elements)
+	 */
+	public void hsvToRgb(float h, float s, float v, float[] rgb) {
+		h *= 360.0f;
+		if (s == 0.0) {
+			rgb[0] = rgb[1] = rgb[2] = v;
+		} else {
+			if (h == 360) {
+				h = 0;
+			} else {
+				h /= 60;
+			}
+			int i = (int) Math.floor(h);
+			float f = h - i;
+			float p = v * (1.0f - s);
+			float q = v * (1.0f - s * f);
+			float t = v * (1.0f - s * (1.0f - f));
+			switch (i) {
+				case 0:
+					rgb[0] = v;
+					rgb[1] = t;
+					rgb[2] = p;
+					break;
+				case 1:
+					rgb[0] = q;
+					rgb[1] = v;
+					rgb[2] = p;
+					break;
+				case 2:
+					rgb[0] = p;
+					rgb[1] = v;
+					rgb[2] = t;
+					break;
+				case 3:
+					rgb[0] = p;
+					rgb[1] = q;
+					rgb[2] = v;
+					break;
+				case 4:
+					rgb[0] = t;
+					rgb[1] = p;
+					rgb[2] = v;
+					break;
+				case 5:
+					rgb[0] = v;
+					rgb[1] = p;
+					rgb[2] = q;
+					break;
+			}
+		}
+	}
+
+	/**
+	 * An interface used in calculating alpha mask during particles' texture calculations.
+	 * @author Marcin Roguski (Kaelthas)
+	 */
+	protected static interface IAlphaMask {
+		/**
+		 * This method sets the size of the texture's image.
+		 * @param width
+		 *        the width of the image
+		 * @param height
+		 *        the height of the image
+		 */
+		void setImageSize(int width, int height);
+
+		/**
+		 * This method returns the alpha value for the specified texture position.
+		 * @param x
+		 *        the X coordinate of the texture position
+		 * @param y
+		 *        the Y coordinate of the texture position
+		 * @return the alpha value for the specified texture position
+		 */
+		byte getAlpha(float x, float y);
+	}
 }
 }

+ 528 - 531
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/MeshHelper.java

@@ -53,9 +53,9 @@ import com.jme3.scene.VertexBuffer.Type;
 import com.jme3.scene.VertexBuffer.Usage;
 import com.jme3.scene.VertexBuffer.Usage;
 import com.jme3.scene.plugins.blender.data.Structure;
 import com.jme3.scene.plugins.blender.data.Structure;
 import com.jme3.scene.plugins.blender.exception.BlenderFileException;
 import com.jme3.scene.plugins.blender.exception.BlenderFileException;
+import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;
 import com.jme3.scene.plugins.blender.utils.DataRepository;
 import com.jme3.scene.plugins.blender.utils.DataRepository;
 import com.jme3.scene.plugins.blender.utils.DataRepository.LoadedFeatureDataType;
 import com.jme3.scene.plugins.blender.utils.DataRepository.LoadedFeatureDataType;
-import com.jme3.scene.plugins.blender.utils.AbstractBlenderHelper;
 import com.jme3.scene.plugins.blender.utils.DynamicArray;
 import com.jme3.scene.plugins.blender.utils.DynamicArray;
 import com.jme3.scene.plugins.blender.utils.Pointer;
 import com.jme3.scene.plugins.blender.utils.Pointer;
 import com.jme3.texture.Texture;
 import com.jme3.texture.Texture;
@@ -67,534 +67,531 @@ import com.jme3.util.BufferUtils;
  * @author Marcin Roguski (Kaelthas)
  * @author Marcin Roguski (Kaelthas)
  */
  */
 public class MeshHelper extends AbstractBlenderHelper {
 public class MeshHelper extends AbstractBlenderHelper {
-
-    protected static final int MAXIMUM_WEIGHTS_PER_VERTEX = 4;	// have no idea why 4, could someone please explain ?
-
-    /**
-     * This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender
-     * versions.
-     * 
-     * @param blenderVersion
-     *            the version read from the blend file
-     */
-    public MeshHelper(String blenderVersion) {
-        super(blenderVersion);
-    }
-
-    /**
-     * This method reads converts the given structure into mesh. The given structure needs to be filled with the appropriate data.
-     * 
-     * @param structure
-     *            the structure we read the mesh from
-     * @return the mesh feature
-     * @throws BlenderFileException
-     */
-    @SuppressWarnings("unchecked")
-    public List<Geometry> toMesh(Structure structure, DataRepository dataRepository) throws BlenderFileException {
-        List<Geometry> geometries = (List<Geometry>) dataRepository.getLoadedFeature(structure.getOldMemoryAddress(),
-                LoadedFeatureDataType.LOADED_FEATURE);
-        if (geometries != null) {
-            List<Geometry> copiedGeometries = new ArrayList<Geometry>(geometries.size());
-            for (Geometry geometry : geometries) {
-                copiedGeometries.add(geometry.clone());
-            }
-            return copiedGeometries;
-        }
-
-        // helpers
-        TextureHelper textureHelper = dataRepository.getHelper(TextureHelper.class);
-
-        // reading mesh data
-        String name = structure.getName();
-
-        // reading vertices
-        Vector3f[] vertices = this.getVertices(structure, dataRepository);
-        int verticesAmount = vertices.length;
-
-        // vertices Colors
-        List<float[]> verticesColors = this.getVerticesColors(structure, dataRepository);
-
-        // reading faces
-        // the following map sorts faces by material number (because in jme Mesh can have only one material)
-        Map<Integer, List<Integer>> meshesMap = new HashMap<Integer, List<Integer>>();
-        Pointer pMFace = (Pointer) structure.getFieldValue("mface");
-        List<Structure> mFaces = pMFace.fetchData(dataRepository.getInputStream());
-
-        Pointer pMTFace = (Pointer) structure.getFieldValue("mtface");
-        List<Vector2f> uvCoordinates = null;
-        List<Structure> mtFaces = null;
-
-        if (!pMTFace.isNull()) {
-            mtFaces = pMTFace.fetchData(dataRepository.getInputStream());
-            int facesAmount = ((Number) structure.getFieldValue("totface")).intValue();
-            if (mtFaces.size() != facesAmount) {
-                throw new BlenderFileException("The amount of faces uv coordinates is not equal to faces amount!");
-            }
-            uvCoordinates = new ArrayList<Vector2f>();// TODO: calculate the amount of coordinates if possible
-        }
-
-        // normalMap merges normals of faces that will be rendered smooth
-        Map<Vector3f, Vector3f> normalMap = new HashMap<Vector3f, Vector3f>(verticesAmount);
-
-        List<Vector3f> normalList = new ArrayList<Vector3f>();
-        List<Vector3f> vertexList = new ArrayList<Vector3f>();
-        Map<Integer, Texture> materialNumberToTexture = new HashMap<Integer, Texture>();// indicates if the material with the specified
-        // number should have a texture attached
-        // this map's key is the vertex index from 'vertices 'table and the value are indices from 'vertexList'
-        // positions (it simply tells which vertex is referenced where in the result list)
-        Map<Integer, List<Integer>> vertexReferenceMap = new HashMap<Integer, List<Integer>>(verticesAmount);
-        int vertexColorIndex = 0;
-        for (int i = 0; i < mFaces.size(); ++i) {
-            Structure mFace = mFaces.get(i);
-            boolean smooth = (((Number) mFace.getFieldValue("flag")).byteValue() & 0x01) != 0x00;
-            DynamicArray<Number> uvs = null;
-            boolean materialWithoutTextures = false;
-            Pointer pImage = null;
-            if (mtFaces != null) {
-                Structure mtFace = mtFaces.get(i);
-                pImage = (Pointer) mtFace.getFieldValue("tpage");
-                materialWithoutTextures = pImage.isNull();
-                // uvs always must be added wheater we have texture or not
-                uvs = (DynamicArray<Number>) mtFace.getFieldValue("uv");
-                uvCoordinates.add(new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue()));
-                uvCoordinates.add(new Vector2f(uvs.get(1, 0).floatValue(), uvs.get(1, 1).floatValue()));
-                uvCoordinates.add(new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue()));
-            }
-            int matNr = ((Number) mFace.getFieldValue("mat_nr")).intValue();
-            Integer materialNumber = Integer.valueOf(materialWithoutTextures ? -1 * matNr - 1 : matNr);
-            List<Integer> indexList = meshesMap.get(materialNumber);
-            if (indexList == null) {
-                indexList = new ArrayList<Integer>();
-                meshesMap.put(materialNumber, indexList);
-            }
-            if (pImage != null && !pImage.isNull() && !materialNumberToTexture.containsKey(materialNumber)) {// attaching image to texture
-                // (face can have UV's and
-                // image whlie its material
-                // may have no texture
-                // attached)
-                Texture texture = textureHelper.getTextureFromImage(pImage.fetchData(dataRepository.getInputStream()).get(0),
-                        dataRepository);
-                if (texture != null) {
-                    materialNumberToTexture.put(materialNumber, texture);
-                }
-            }
-
-            int v1 = ((Number) mFace.getFieldValue("v1")).intValue();
-            int v2 = ((Number) mFace.getFieldValue("v2")).intValue();
-            int v3 = ((Number) mFace.getFieldValue("v3")).intValue();
-            int v4 = ((Number) mFace.getFieldValue("v4")).intValue();
-
-            Vector3f n = FastMath.computeNormal(vertices[v1], vertices[v2], vertices[v3]);
-            this.addNormal(n, normalMap, smooth, vertices[v1], vertices[v2], vertices[v3]);
-            normalList.add(normalMap.get(vertices[v1]));
-            normalList.add(normalMap.get(vertices[v2]));
-            normalList.add(normalMap.get(vertices[v3]));
-
-            this.appendVertexReference(v1, vertexList.size(), vertexReferenceMap);
-            indexList.add(vertexList.size());
-            vertexList.add(vertices[v1]);
-
-            this.appendVertexReference(v2, vertexList.size(), vertexReferenceMap);
-            indexList.add(vertexList.size());
-            vertexList.add(vertices[v2]);
-
-            this.appendVertexReference(v3, vertexList.size(), vertexReferenceMap);
-            indexList.add(vertexList.size());
-            vertexList.add(vertices[v3]);
-
-            if (v4 > 0) {
-                if (uvs != null) {
-                    uvCoordinates.add(new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue()));
-                    uvCoordinates.add(new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue()));
-                    uvCoordinates.add(new Vector2f(uvs.get(3, 0).floatValue(), uvs.get(3, 1).floatValue()));
-                }
-                this.appendVertexReference(v1, vertexList.size(), vertexReferenceMap);
-                indexList.add(vertexList.size());
-                vertexList.add(vertices[v1]);
-
-                this.appendVertexReference(v3, vertexList.size(), vertexReferenceMap);
-                indexList.add(vertexList.size());
-                vertexList.add(vertices[v3]);
-
-                this.appendVertexReference(v4, vertexList.size(), vertexReferenceMap);
-                indexList.add(vertexList.size());
-                vertexList.add(vertices[v4]);
-
-                this.addNormal(n, normalMap, smooth, vertices[v4]);
-                normalList.add(normalMap.get(vertices[v1]));
-                normalList.add(normalMap.get(vertices[v3]));
-                normalList.add(normalMap.get(vertices[v4]));
-
-                if (verticesColors != null) {
-                    verticesColors.add(vertexColorIndex + 3, verticesColors.get(vertexColorIndex));
-                    verticesColors.add(vertexColorIndex + 4, verticesColors.get(vertexColorIndex + 2));
-                }
-                vertexColorIndex += 6;
-            } else {
-                if (verticesColors != null) {
-                    verticesColors.remove(vertexColorIndex + 3);
-                    vertexColorIndex += 3;
-                }
-            }
-        }
-        Vector3f[] normals = normalList.toArray(new Vector3f[normalList.size()]);
-
-        // reading vertices groups (from the parent)
-        Structure parent = dataRepository.peekParent();
-        Structure defbase = (Structure) parent.getFieldValue("defbase");
-        List<Structure> defs = defbase.evaluateListBase(dataRepository);
-        String[] verticesGroups = new String[defs.size()];
-        int defIndex = 0;
-        for (Structure def : defs) {
-            verticesGroups[defIndex++] = def.getFieldValue("name").toString();
-        }
-
-        // vertices bone weights and indices
-        ArmatureHelper armatureHelper = dataRepository.getHelper(ArmatureHelper.class);
-        Structure defBase = (Structure) parent.getFieldValue("defbase");
-        Map<Integer, Integer> groupToBoneIndexMap = armatureHelper.getGroupToBoneIndexMap(defBase, dataRepository);
-
-        VertexBuffer verticesWeights = null, verticesWeightsIndices = null;
-        int[] bonesGroups = new int[]{0};
-        VertexBuffer[] boneWeightsAndIndex = this.getBoneWeightAndIndexBuffer(structure, vertexList.size(), bonesGroups,
-                vertexReferenceMap, groupToBoneIndexMap, dataRepository);
-        verticesWeights = boneWeightsAndIndex[0];
-        verticesWeightsIndices = boneWeightsAndIndex[1];
-
-        // reading materials
-        MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);
-        Material[] materials = null;
-        Material[] nonTexturedMaterials = null;
-        if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.MATERIALS) != 0) {
-            materials = materialHelper.getMaterials(structure, dataRepository);
-            nonTexturedMaterials = materials == null ? null : new Material[materials.length];// fill it when needed
-        }
-
-        // creating the result meshes
-        geometries = new ArrayList<Geometry>(meshesMap.size());
-
-        VertexBuffer verticesBuffer = new VertexBuffer(Type.Position);
-        verticesBuffer.setupData(Usage.Stream, 3, Format.Float,
-                BufferUtils.createFloatBuffer(vertexList.toArray(new Vector3f[vertexList.size()])));
-
-        // initial vertex position (used with animation)
-        VertexBuffer verticesBind = new VertexBuffer(Type.BindPosePosition);
-        verticesBind.setupData(Usage.CpuOnly, 3, Format.Float, BufferUtils.clone(verticesBuffer.getData()));
-
-        VertexBuffer normalsBuffer = new VertexBuffer(Type.Normal);
-        normalsBuffer.setupData(Usage.Stream, 3, Format.Float, BufferUtils.createFloatBuffer(normals));
-
-        // initial normals position (used with animation)
-        VertexBuffer normalsBind = new VertexBuffer(Type.BindPoseNormal);
-        normalsBind.setupData(Usage.CpuOnly, 3, Format.Float, BufferUtils.clone(normalsBuffer.getData()));
-
-        VertexBuffer uvCoordsBuffer = null;
-        if (uvCoordinates != null) {
-            uvCoordsBuffer = new VertexBuffer(Type.TexCoord);
-            uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float,
-                    BufferUtils.createFloatBuffer(uvCoordinates.toArray(new Vector2f[uvCoordinates.size()])));
-        }
-
-        // generating meshes
-        FloatBuffer verticesColorsBuffer = this.createFloatBuffer(verticesColors);
-        for (Entry<Integer, List<Integer>> meshEntry : meshesMap.entrySet()) {
-            Mesh mesh = new Mesh();
-
-            // creating vertices indices for this mesh
-            List<Integer> indexList = meshEntry.getValue();
-            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.createShortBuffer(indices));
-            mesh.setBuffer(verticesBuffer);
-            mesh.setBuffer(verticesBind);
-
-            // setting vertices colors
-            if (verticesColorsBuffer != null) {
-                mesh.setBuffer(Type.Color, 4, verticesColorsBuffer);
-            }
-
-            // setting weights for bones
-            if (verticesWeights != null) {
-                mesh.setMaxNumWeights(bonesGroups[0]);
-                mesh.setBuffer(verticesWeights);
-                mesh.setBuffer(verticesWeightsIndices);
-            }
-
-            // setting faces' normals
-            mesh.setBuffer(normalsBuffer);
-            mesh.setBuffer(normalsBind);
-
-            // setting uvCoords
-            if (uvCoordsBuffer != null) {
-                mesh.setBuffer(uvCoordsBuffer);
-            }
-
-            // creating the result
-            Geometry geometry = new Geometry(name + (geometries.size() + 1), mesh);
-            if (materials != null) {
-                int materialNumber = meshEntry.getKey().intValue();
-                Material material;
-                if (materialNumber >= 0) {
-                    material = materials[materialNumber];
-                    if (materialNumberToTexture.containsKey(Integer.valueOf(materialNumber))) {
-                        if (material.getMaterialDef().getAssetName().contains("Lighting")) {
-                            if (!materialHelper.hasTexture(material, MaterialHelper.TEXTURE_TYPE_DIFFUSE)) {
-                                material = material.clone();
-                                material.setTexture(MaterialHelper.TEXTURE_TYPE_DIFFUSE,
-                                        materialNumberToTexture.get(Integer.valueOf(materialNumber)));
-                            }
-                        } else {
-                            if (!materialHelper.hasTexture(material, MaterialHelper.TEXTURE_TYPE_COLOR)) {
-                                material = material.clone();
-                                material.setTexture(MaterialHelper.TEXTURE_TYPE_COLOR,
-                                        materialNumberToTexture.get(Integer.valueOf(materialNumber)));
-                            }
-                        }
-                    }
-                } else {
-                    materialNumber = -1 * (materialNumber + 1);
-                    if (nonTexturedMaterials[materialNumber] == null) {
-                        nonTexturedMaterials[materialNumber] = materialHelper.getNonTexturedMaterial(materials[materialNumber],
-                                TextureHelper.TEX_IMAGE);
-                    }
-                    material = nonTexturedMaterials[materialNumber];
-                }
-                geometry.setMaterial(material);
-            } else {
-                geometry.setMaterial(dataRepository.getDefaultMaterial());
-            }
-            geometries.add(geometry);
-        }
-        dataRepository.addLoadedFeatures(structure.getOldMemoryAddress(), structure.getName(), structure, geometries);
-        return geometries;
-    }
-
-    /**
-     * This method adds a normal to a normals' map. This map is used to merge normals of a vertor that should be rendered smooth.
-     * 
-     * @param normalToAdd
-     *            a normal to be added
-     * @param normalMap
-     *            merges normals of faces that will be rendered smooth; the key is the vertex and the value - its normal vector
-     * @param smooth
-     *            the variable that indicates wheather to merge normals (creating the smooth mesh) or not
-     * @param vertices
-     *            a list of vertices read from the blender file
-     */
-    protected void addNormal(Vector3f normalToAdd, Map<Vector3f, Vector3f> normalMap, boolean smooth, Vector3f... vertices) {
-        for (Vector3f v : vertices) {
-            Vector3f n = normalMap.get(v);
-            if (!smooth || n == null) {
-                normalMap.put(v, normalToAdd.clone());
-            } else {
-                n.addLocal(normalToAdd).normalizeLocal();
-            }
-        }
-    }
-
-    /**
-     * This method fills the vertex reference map. The vertices are loaded once and referenced many times in the model. This map is created
-     * to tell where the basic vertices are referenced in the result vertex lists. The key of the map is the basic vertex index, and its key
-     * - the reference indices list.
-     * 
-     * @param basicVertexIndex
-     *            the index of the vertex from its basic table
-     * @param resultIndex
-     *            the index of the vertex in its result vertex list
-     * @param vertexReferenceMap
-     *            the reference map
-     */
-    protected void appendVertexReference(int basicVertexIndex, int resultIndex, Map<Integer, List<Integer>> vertexReferenceMap) {
-        List<Integer> referenceList = vertexReferenceMap.get(Integer.valueOf(basicVertexIndex));
-        if (referenceList == null) {
-            referenceList = new ArrayList<Integer>();
-            vertexReferenceMap.put(Integer.valueOf(basicVertexIndex), referenceList);
-        }
-        referenceList.add(Integer.valueOf(resultIndex));
-    }
-
-    /**
-     * This method returns the vertices colors. Each vertex is stored in float[4] array.
-     * 
-     * @param meshStructure
-     *            the structure containing the mesh data
-     * @param dataRepository
-     *            the data repository
-     * @return a list of vertices colors, each color belongs to a single vertex
-     * @throws BlenderFileException
-     *             this exception is thrown when the blend file structure is somehow invalid or corrupted
-     */
-    public List<float[]> getVerticesColors(Structure meshStructure, DataRepository dataRepository) throws BlenderFileException {
-        Pointer pMCol = (Pointer) meshStructure.getFieldValue("mcol");
-        List<float[]> verticesColors = null;
-        List<Structure> mCol = null;
-        if (!pMCol.isNull()) {
-            verticesColors = new LinkedList<float[]>();
-            mCol = pMCol.fetchData(dataRepository.getInputStream());
-            for (Structure color : mCol) {
-                float r = ((Number) color.getFieldValue("r")).byteValue() / 256.0f;
-                float g = ((Number) color.getFieldValue("g")).byteValue() / 256.0f;
-                float b = ((Number) color.getFieldValue("b")).byteValue() / 256.0f;
-                float a = ((Number) color.getFieldValue("a")).byteValue() / 256.0f;
-                verticesColors.add(new float[]{b, g, r, a});
-            }
-        }
-        return verticesColors;
-    }
-
-    /**
-     * This method returns the vertices.
-     * 
-     * @param meshStructure
-     *            the structure containing the mesh data
-     * @param dataRepository
-     *            the data repository
-     * @return a list of vertices colors, each color belongs to a single vertex
-     * @throws BlenderFileException
-     *             this exception is thrown when the blend file structure is somehow invalid or corrupted
-     */
-    @SuppressWarnings("unchecked")
-    public Vector3f[] getVertices(Structure meshStructure, DataRepository dataRepository) throws BlenderFileException {
-        int verticesAmount = ((Number) meshStructure.getFieldValue("totvert")).intValue();
-        Vector3f[] vertices = new Vector3f[verticesAmount];
-        Pointer pMVert = (Pointer) meshStructure.getFieldValue("mvert");
-        List<Structure> mVerts = pMVert.fetchData(dataRepository.getInputStream());
-        for (int i = 0; i < verticesAmount; ++i) {
-            DynamicArray<Number> coordinates = (DynamicArray<Number>) mVerts.get(i).getFieldValue("co");
-            vertices[i] = new Vector3f(coordinates.get(0).floatValue(), coordinates.get(1).floatValue(), coordinates.get(2).floatValue());
-        }
-        return vertices;
-    }
-
-    /**
-     * This method returns an array of size 2. The first element is a vertex buffer holding bone weights for every vertex in the model. The
-     * second element is a vertex buffer holding bone indices for vertices (the indices of bones the vertices are assigned to).
-     * 
-     * @param meshStructure
-     *            the mesh structure object
-     * @param vertexListSize
-     *            a number of vertices in the model
-     * @param bonesGroups
-     *            this is an output parameter, it should be a one-sized array; the maximum amount of weights per vertex (up to
-     *            MAXIMUM_WEIGHTS_PER_VERTEX) is stored there
-     * @param vertexReferenceMap
-     *            this reference map allows to map the original vertices read from blender to vertices that are really in the model; one
-     *            vertex may appear several times in the result model
-     * @param groupToBoneIndexMap
-     *            this object maps the group index (to which a vertices in blender belong) to bone index of the model
-     * @param dataRepository
-     *            the data repository
-     * @return arrays of vertices weights and their bone indices and (as an outpot parameter) the maximum amount of weights for a vertex
-     * @throws BlenderFileException
-     *             this exception is thrown when the blend file structure is somehow invalid or corrupted
-     */
-    public VertexBuffer[] getBoneWeightAndIndexBuffer(Structure meshStructure, int vertexListSize, int[] bonesGroups,
-            Map<Integer, List<Integer>> vertexReferenceMap, Map<Integer, Integer> groupToBoneIndexMap, DataRepository dataRepository)
-            throws BlenderFileException {
-        Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert = DeformVERTices
-        FloatBuffer weightsFloatData = BufferUtils.createFloatBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);
-        ByteBuffer indicesData = BufferUtils.createByteBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);
-        if (!pDvert.isNull()) {// assigning weights and bone indices
-            List<Structure> dverts = pDvert.fetchData(dataRepository.getInputStream());// dverts.size() == verticesAmount (one dvert per
-            // vertex in blender)
-            int vertexIndex = 0;
-            for (Structure dvert : dverts) {
-                int totweight = ((Number) dvert.getFieldValue("totweight")).intValue();// total amount of weights assignet to the vertex
-                // (max. 4 in JME)
-                Pointer pDW = (Pointer) dvert.getFieldValue("dw");
-                List<Integer> vertexIndices = vertexReferenceMap.get(Integer.valueOf(vertexIndex));// we fetch the referenced vertices here
-                if (totweight > 0 && !pDW.isNull()) {// pDW should never be null here, but I check it just in case :)
-                    int weightIndex = 0;
-                    List<Structure> dw = pDW.fetchData(dataRepository.getInputStream());
-                    for (Structure deformWeight : dw) {
-                        Integer boneIndex = groupToBoneIndexMap.get(((Number) deformWeight.getFieldValue("def_nr")).intValue());
-                        if (boneIndex != null) {// null here means that we came accross group that has no bone attached to
-                            float weight = ((Number) deformWeight.getFieldValue("weight")).floatValue();
-                            if (weight == 0.0f) {
-                                weight = 1;
-                                boneIndex = Integer.valueOf(0);
-                            }
-                            // we apply the weight to all referenced vertices
-                            for (Integer index : vertexIndices) {
-                                // all indices are always assigned to 0-indexed bone
-                                // weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, 1.0f);
-                                // indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, (byte)0);
-                                // if(weight != 0.0f) {
-                                weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, weight);
-                                indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, boneIndex.byteValue());
-                                // }
-                            }
-                        }
-                        ++weightIndex;
-                    }
-                } else {
-                    for (Integer index : vertexIndices) {
-                        weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, 1.0f);
-                        indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, (byte) 0);
-                    }
-                }
-                ++vertexIndex;
-            }
-        } else {
-            // always bind all vertices to 0-indexed bone
-            // this bone makes the model look normally if vertices have no bone assigned
-            // and it is used in object animation, so if we come accross object animation
-            // we can use the 0-indexed bone for this
-            for (List<Integer> vertexIndexList : vertexReferenceMap.values()) {
-                // we apply the weight to all referenced vertices
-                for (Integer index : vertexIndexList) {
-                    weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, 1.0f);
-                    indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, (byte) 0);
-                }
-            }
-        }
-
-        bonesGroups[0] = this.endBoneAssigns(vertexListSize, weightsFloatData);
-        VertexBuffer verticesWeights = new VertexBuffer(Type.BoneWeight);
-        verticesWeights.setupData(Usage.CpuOnly, bonesGroups[0], Format.Float, weightsFloatData);
-
-        VertexBuffer verticesWeightsIndices = new VertexBuffer(Type.BoneIndex);
-        verticesWeightsIndices.setupData(Usage.CpuOnly, bonesGroups[0], Format.UnsignedByte, indicesData);
-        return new VertexBuffer[]{verticesWeights, verticesWeightsIndices};
-    }
-
-    /**
-     * Normalizes weights if needed and finds largest amount of weights used for all vertices in the buffer.
-     */
-    protected int endBoneAssigns(int vertCount, FloatBuffer weightsFloatData) {
-        int maxWeightsPerVert = 0;
-        weightsFloatData.rewind();
-        for (int v = 0; v < vertCount; ++v) {
-            float w0 = weightsFloatData.get(), w1 = weightsFloatData.get(), w2 = weightsFloatData.get(), w3 = weightsFloatData.get();
-
-            if (w3 != 0) {
-                maxWeightsPerVert = Math.max(maxWeightsPerVert, 4);
-            } else if (w2 != 0) {
-                maxWeightsPerVert = Math.max(maxWeightsPerVert, 3);
-            } else if (w1 != 0) {
-                maxWeightsPerVert = Math.max(maxWeightsPerVert, 2);
-            } else if (w0 != 0) {
-                maxWeightsPerVert = Math.max(maxWeightsPerVert, 1);
-            }
-
-            float sum = w0 + w1 + w2 + w3;
-            if (sum != 1f && sum != 0.0f) {
-                weightsFloatData.position(weightsFloatData.position() - 4);
-                // compute new vals based on sum
-                float sumToB = 1f / sum;
-                weightsFloatData.put(w0 * sumToB);
-                weightsFloatData.put(w1 * sumToB);
-                weightsFloatData.put(w2 * sumToB);
-                weightsFloatData.put(w3 * sumToB);
-            }
-        }
-        weightsFloatData.rewind();
-
-        // mesh.setMaxNumWeights(maxWeightsPerVert);
-        return maxWeightsPerVert;
-    }
+	protected static final int	MAXIMUM_WEIGHTS_PER_VERTEX	= 4;	// have no idea why 4, could someone please explain ?
+
+	/**
+	 * This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender
+	 * versions.
+	 * 
+	 * @param blenderVersion
+	 *            the version read from the blend file
+	 */
+	public MeshHelper(String blenderVersion) {
+		super(blenderVersion);
+	}
+
+	/**
+	 * This method reads converts the given structure into mesh. The given structure needs to be filled with the appropriate data.
+	 * 
+	 * @param structure
+	 *            the structure we read the mesh from
+	 * @return the mesh feature
+	 * @throws BlenderFileException
+	 */
+	@SuppressWarnings("unchecked")
+	public List<Geometry> toMesh(Structure structure, DataRepository dataRepository) throws BlenderFileException {
+		List<Geometry> geometries = (List<Geometry>) dataRepository.getLoadedFeature(structure.getOldMemoryAddress(),
+				LoadedFeatureDataType.LOADED_FEATURE);
+		if (geometries != null) {
+			List<Geometry> copiedGeometries = new ArrayList<Geometry>(geometries.size());
+			for (Geometry geometry : geometries) {
+				copiedGeometries.add(geometry.clone());
+			}
+			return copiedGeometries;
+		}
+
+		// helpers
+		TextureHelper textureHelper = dataRepository.getHelper(TextureHelper.class);
+
+		// reading mesh data
+		String name = structure.getName();
+
+		// reading vertices
+		Vector3f[] vertices = this.getVertices(structure, dataRepository);
+		int verticesAmount = vertices.length;
+
+		// vertices Colors
+		List<float[]> verticesColors = this.getVerticesColors(structure, dataRepository);
+
+		// reading faces
+		// the following map sorts faces by material number (because in jme Mesh can have only one material)
+		Map<Integer, List<Integer>> meshesMap = new HashMap<Integer, List<Integer>>();
+		Pointer pMFace = (Pointer) structure.getFieldValue("mface");
+		List<Structure> mFaces = pMFace.fetchData(dataRepository.getInputStream());
+
+		Pointer pMTFace = (Pointer) structure.getFieldValue("mtface");
+		List<Vector2f> uvCoordinates = null;
+		List<Structure> mtFaces = null;
+
+		if (!pMTFace.isNull()) {
+			mtFaces = pMTFace.fetchData(dataRepository.getInputStream());
+			int facesAmount = ((Number) structure.getFieldValue("totface")).intValue();
+			if (mtFaces.size() != facesAmount) {
+				throw new BlenderFileException("The amount of faces uv coordinates is not equal to faces amount!");
+			}
+			uvCoordinates = new ArrayList<Vector2f>();// TODO: calculate the amount of coordinates if possible
+		}
+
+		// normalMap merges normals of faces that will be rendered smooth
+		Map<Vector3f, Vector3f> normalMap = new HashMap<Vector3f, Vector3f>(verticesAmount);
+
+		List<Vector3f> normalList = new ArrayList<Vector3f>();
+		List<Vector3f> vertexList = new ArrayList<Vector3f>();
+		// indicates if the material with the specified number should have a texture attached
+		Map<Integer, Texture> materialNumberToTexture = new HashMap<Integer, Texture>();
+		// this map's key is the vertex index from 'vertices 'table and the value are indices from 'vertexList'
+		// positions (it simply tells which vertex is referenced where in the result list)
+		Map<Integer, List<Integer>> vertexReferenceMap = new HashMap<Integer, List<Integer>>(verticesAmount);
+		int vertexColorIndex = 0;
+		for (int i = 0; i < mFaces.size(); ++i) {
+			Structure mFace = mFaces.get(i);
+			boolean smooth = (((Number) mFace.getFieldValue("flag")).byteValue() & 0x01) != 0x00;
+			DynamicArray<Number> uvs = null;
+			boolean materialWithoutTextures = false;
+			Pointer pImage = null;
+			if (mtFaces != null) {
+				Structure mtFace = mtFaces.get(i);
+				pImage = (Pointer) mtFace.getFieldValue("tpage");
+				materialWithoutTextures = pImage.isNull();
+				// uvs always must be added wheater we have texture or not
+				uvs = (DynamicArray<Number>) mtFace.getFieldValue("uv");
+				uvCoordinates.add(new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue()));
+				uvCoordinates.add(new Vector2f(uvs.get(1, 0).floatValue(), uvs.get(1, 1).floatValue()));
+				uvCoordinates.add(new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue()));
+			}
+			int matNr = ((Number) mFace.getFieldValue("mat_nr")).intValue();
+			Integer materialNumber = Integer.valueOf(materialWithoutTextures ? -1 * matNr - 1 : matNr);
+			List<Integer> indexList = meshesMap.get(materialNumber);
+			if (indexList == null) {
+				indexList = new ArrayList<Integer>();
+				meshesMap.put(materialNumber, indexList);
+			}
+			
+			// attaching image to texture (face can have UV's and image whlie its material may have no texture attached)
+			if (pImage != null && !pImage.isNull() && !materialNumberToTexture.containsKey(materialNumber)) {
+				Texture texture = textureHelper.getTextureFromImage(pImage.fetchData(dataRepository.getInputStream()).get(0),
+						dataRepository);
+				if (texture != null) {
+					materialNumberToTexture.put(materialNumber, texture);
+				}
+			}
+
+			int v1 = ((Number) mFace.getFieldValue("v1")).intValue();
+			int v2 = ((Number) mFace.getFieldValue("v2")).intValue();
+			int v3 = ((Number) mFace.getFieldValue("v3")).intValue();
+			int v4 = ((Number) mFace.getFieldValue("v4")).intValue();
+
+			Vector3f n = FastMath.computeNormal(vertices[v1], vertices[v2], vertices[v3]);
+			this.addNormal(n, normalMap, smooth, vertices[v1], vertices[v2], vertices[v3]);
+			normalList.add(normalMap.get(vertices[v1]));
+			normalList.add(normalMap.get(vertices[v2]));
+			normalList.add(normalMap.get(vertices[v3]));
+
+			this.appendVertexReference(v1, vertexList.size(), vertexReferenceMap);
+			indexList.add(vertexList.size());
+			vertexList.add(vertices[v1]);
+
+			this.appendVertexReference(v2, vertexList.size(), vertexReferenceMap);
+			indexList.add(vertexList.size());
+			vertexList.add(vertices[v2]);
+
+			this.appendVertexReference(v3, vertexList.size(), vertexReferenceMap);
+			indexList.add(vertexList.size());
+			vertexList.add(vertices[v3]);
+
+			if (v4 > 0) {
+				if (uvs != null) {
+					uvCoordinates.add(new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue()));
+					uvCoordinates.add(new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue()));
+					uvCoordinates.add(new Vector2f(uvs.get(3, 0).floatValue(), uvs.get(3, 1).floatValue()));
+				}
+				this.appendVertexReference(v1, vertexList.size(), vertexReferenceMap);
+				indexList.add(vertexList.size());
+				vertexList.add(vertices[v1]);
+
+				this.appendVertexReference(v3, vertexList.size(), vertexReferenceMap);
+				indexList.add(vertexList.size());
+				vertexList.add(vertices[v3]);
+
+				this.appendVertexReference(v4, vertexList.size(), vertexReferenceMap);
+				indexList.add(vertexList.size());
+				vertexList.add(vertices[v4]);
+
+				this.addNormal(n, normalMap, smooth, vertices[v4]);
+				normalList.add(normalMap.get(vertices[v1]));
+				normalList.add(normalMap.get(vertices[v3]));
+				normalList.add(normalMap.get(vertices[v4]));
+
+				if (verticesColors != null) {
+					verticesColors.add(vertexColorIndex + 3, verticesColors.get(vertexColorIndex));
+					verticesColors.add(vertexColorIndex + 4, verticesColors.get(vertexColorIndex + 2));
+				}
+				vertexColorIndex += 6;
+			} else {
+				if (verticesColors != null) {
+					verticesColors.remove(vertexColorIndex + 3);
+					vertexColorIndex += 3;
+				}
+			}
+		}
+		Vector3f[] normals = normalList.toArray(new Vector3f[normalList.size()]);
+
+		// reading vertices groups (from the parent)
+		Structure parent = dataRepository.peekParent();
+		Structure defbase = (Structure) parent.getFieldValue("defbase");
+		List<Structure> defs = defbase.evaluateListBase(dataRepository);
+		String[] verticesGroups = new String[defs.size()];
+		int defIndex = 0;
+		for (Structure def : defs) {
+			verticesGroups[defIndex++] = def.getFieldValue("name").toString();
+		}
+
+		// vertices bone weights and indices
+		ArmatureHelper armatureHelper = dataRepository.getHelper(ArmatureHelper.class);
+		Structure defBase = (Structure) parent.getFieldValue("defbase");
+		Map<Integer, Integer> groupToBoneIndexMap = armatureHelper.getGroupToBoneIndexMap(defBase, dataRepository);
+
+		VertexBuffer verticesWeights = null, verticesWeightsIndices = null;
+		int[] bonesGroups = new int[] { 0 };
+		VertexBuffer[] boneWeightsAndIndex = this.getBoneWeightAndIndexBuffer(structure, vertexList.size(), bonesGroups,
+				vertexReferenceMap, groupToBoneIndexMap, dataRepository);
+		verticesWeights = boneWeightsAndIndex[0];
+		verticesWeightsIndices = boneWeightsAndIndex[1];
+
+		// reading materials
+		MaterialHelper materialHelper = dataRepository.getHelper(MaterialHelper.class);
+		Material[] materials = null;
+		Material[] nonTexturedMaterials = null;
+		if ((dataRepository.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.MATERIALS) != 0) {
+			materials = materialHelper.getMaterials(structure, dataRepository);
+			nonTexturedMaterials = materials == null ? null : new Material[materials.length];// fill it when needed
+		}
+
+		// creating the result meshes
+		geometries = new ArrayList<Geometry>(meshesMap.size());
+
+		VertexBuffer verticesBuffer = new VertexBuffer(Type.Position);
+		verticesBuffer.setupData(Usage.Stream, 3, Format.Float,
+				BufferUtils.createFloatBuffer(vertexList.toArray(new Vector3f[vertexList.size()])));
+
+		// initial vertex position (used with animation)
+		VertexBuffer verticesBind = new VertexBuffer(Type.BindPosePosition);
+		verticesBind.setupData(Usage.CpuOnly, 3, Format.Float, BufferUtils.clone(verticesBuffer.getData()));
+
+		VertexBuffer normalsBuffer = new VertexBuffer(Type.Normal);
+		normalsBuffer.setupData(Usage.Stream, 3, Format.Float, BufferUtils.createFloatBuffer(normals));
+
+		// initial normals position (used with animation)
+		VertexBuffer normalsBind = new VertexBuffer(Type.BindPoseNormal);
+		normalsBind.setupData(Usage.CpuOnly, 3, Format.Float, BufferUtils.clone(normalsBuffer.getData()));
+
+		VertexBuffer uvCoordsBuffer = null;
+		if (uvCoordinates != null) {
+			uvCoordsBuffer = new VertexBuffer(Type.TexCoord);
+			uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float,
+					BufferUtils.createFloatBuffer(uvCoordinates.toArray(new Vector2f[uvCoordinates.size()])));
+		}
+
+		// generating meshes
+		FloatBuffer verticesColorsBuffer = this.createFloatBuffer(verticesColors);
+		for (Entry<Integer, List<Integer>> meshEntry : meshesMap.entrySet()) {
+			Mesh mesh = new Mesh();
+
+			// creating vertices indices for this mesh
+			List<Integer> indexList = meshEntry.getValue();
+			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.createShortBuffer(indices));
+			mesh.setBuffer(verticesBuffer);
+			mesh.setBuffer(verticesBind);
+
+			// setting vertices colors
+			if (verticesColorsBuffer != null) {
+				mesh.setBuffer(Type.Color, 4, verticesColorsBuffer);
+			}
+
+			// setting weights for bones
+			if (verticesWeights != null) {
+				mesh.setMaxNumWeights(bonesGroups[0]);
+				mesh.setBuffer(verticesWeights);
+				mesh.setBuffer(verticesWeightsIndices);
+			}
+
+			// setting faces' normals
+			mesh.setBuffer(normalsBuffer);
+			mesh.setBuffer(normalsBind);
+
+			// setting uvCoords
+			if (uvCoordsBuffer != null) {
+				mesh.setBuffer(uvCoordsBuffer);
+			}
+
+			// creating the result
+			Geometry geometry = new Geometry(name + (geometries.size() + 1), mesh);
+			if (materials != null) {
+				int materialNumber = meshEntry.getKey().intValue();
+				Material material;
+				if (materialNumber >= 0) {
+					material = materials[materialNumber];
+					if (materialNumberToTexture.containsKey(Integer.valueOf(materialNumber))) {
+						if (material.getMaterialDef().getAssetName().contains("Lighting")) {
+							if (!materialHelper.hasTexture(material, MaterialHelper.TEXTURE_TYPE_DIFFUSE)) {
+								material = material.clone();
+								material.setTexture(MaterialHelper.TEXTURE_TYPE_DIFFUSE,
+										materialNumberToTexture.get(Integer.valueOf(materialNumber)));
+							}
+						} else {
+							if (!materialHelper.hasTexture(material, MaterialHelper.TEXTURE_TYPE_COLOR)) {
+								material = material.clone();
+								material.setTexture(MaterialHelper.TEXTURE_TYPE_COLOR,
+										materialNumberToTexture.get(Integer.valueOf(materialNumber)));
+							}
+						}
+					}
+				} else {
+					materialNumber = -1 * (materialNumber + 1);
+					if (nonTexturedMaterials[materialNumber] == null) {
+						nonTexturedMaterials[materialNumber] = materialHelper.getNonTexturedMaterial(materials[materialNumber],
+								TextureHelper.TEX_IMAGE);
+					}
+					material = nonTexturedMaterials[materialNumber];
+				}
+				geometry.setMaterial(material);
+			} else {
+				geometry.setMaterial(dataRepository.getDefaultMaterial());
+			}
+			geometries.add(geometry);
+		}
+		dataRepository.addLoadedFeatures(structure.getOldMemoryAddress(), structure.getName(), structure, geometries);
+		return geometries;
+	}
+
+	/**
+	 * This method adds a normal to a normals' map. This map is used to merge normals of a vertor that should be rendered smooth.
+	 * 
+	 * @param normalToAdd
+	 *            a normal to be added
+	 * @param normalMap
+	 *            merges normals of faces that will be rendered smooth; the key is the vertex and the value - its normal vector
+	 * @param smooth
+	 *            the variable that indicates wheather to merge normals (creating the smooth mesh) or not
+	 * @param vertices
+	 *            a list of vertices read from the blender file
+	 */
+	protected void addNormal(Vector3f normalToAdd, Map<Vector3f, Vector3f> normalMap, boolean smooth, Vector3f... vertices) {
+		for (Vector3f v : vertices) {
+			Vector3f n = normalMap.get(v);
+			if (!smooth || n == null) {
+				normalMap.put(v, normalToAdd.clone());
+			} else {
+				n.addLocal(normalToAdd).normalizeLocal();
+			}
+		}
+	}
+
+	/**
+	 * This method fills the vertex reference map. The vertices are loaded once and referenced many times in the model. This map is created
+	 * to tell where the basic vertices are referenced in the result vertex lists. The key of the map is the basic vertex index, and its key
+	 * - the reference indices list.
+	 * 
+	 * @param basicVertexIndex
+	 *            the index of the vertex from its basic table
+	 * @param resultIndex
+	 *            the index of the vertex in its result vertex list
+	 * @param vertexReferenceMap
+	 *            the reference map
+	 */
+	protected void appendVertexReference(int basicVertexIndex, int resultIndex, Map<Integer, List<Integer>> vertexReferenceMap) {
+		List<Integer> referenceList = vertexReferenceMap.get(Integer.valueOf(basicVertexIndex));
+		if (referenceList == null) {
+			referenceList = new ArrayList<Integer>();
+			vertexReferenceMap.put(Integer.valueOf(basicVertexIndex), referenceList);
+		}
+		referenceList.add(Integer.valueOf(resultIndex));
+	}
+
+	/**
+	 * This method returns the vertices colors. Each vertex is stored in float[4] array.
+	 * 
+	 * @param meshStructure
+	 *            the structure containing the mesh data
+	 * @param dataRepository
+	 *            the data repository
+	 * @return a list of vertices colors, each color belongs to a single vertex
+	 * @throws BlenderFileException
+	 *             this exception is thrown when the blend file structure is somehow invalid or corrupted
+	 */
+	public List<float[]> getVerticesColors(Structure meshStructure, DataRepository dataRepository) throws BlenderFileException {
+		Pointer pMCol = (Pointer) meshStructure.getFieldValue("mcol");
+		List<float[]> verticesColors = null;
+		List<Structure> mCol = null;
+		if (!pMCol.isNull()) {
+			verticesColors = new LinkedList<float[]>();
+			mCol = pMCol.fetchData(dataRepository.getInputStream());
+			for (Structure color : mCol) {
+				float r = ((Number) color.getFieldValue("r")).byteValue() / 256.0f;
+				float g = ((Number) color.getFieldValue("g")).byteValue() / 256.0f;
+				float b = ((Number) color.getFieldValue("b")).byteValue() / 256.0f;
+				float a = ((Number) color.getFieldValue("a")).byteValue() / 256.0f;
+				verticesColors.add(new float[] { b, g, r, a });
+			}
+		}
+		return verticesColors;
+	}
+
+	/**
+	 * This method returns the vertices.
+	 * 
+	 * @param meshStructure
+	 *            the structure containing the mesh data
+	 * @param dataRepository
+	 *            the data repository
+	 * @return a list of vertices colors, each color belongs to a single vertex
+	 * @throws BlenderFileException
+	 *             this exception is thrown when the blend file structure is somehow invalid or corrupted
+	 */
+	@SuppressWarnings("unchecked")
+	public Vector3f[] getVertices(Structure meshStructure, DataRepository dataRepository) throws BlenderFileException {
+		int verticesAmount = ((Number) meshStructure.getFieldValue("totvert")).intValue();
+		Vector3f[] vertices = new Vector3f[verticesAmount];
+		Pointer pMVert = (Pointer) meshStructure.getFieldValue("mvert");
+		List<Structure> mVerts = pMVert.fetchData(dataRepository.getInputStream());
+		for (int i = 0; i < verticesAmount; ++i) {
+			DynamicArray<Number> coordinates = (DynamicArray<Number>) mVerts.get(i).getFieldValue("co");
+			vertices[i] = new Vector3f(coordinates.get(0).floatValue(), coordinates.get(1).floatValue(), coordinates.get(2).floatValue());
+		}
+		return vertices;
+	}
+
+	/**
+	 * This method returns an array of size 2. The first element is a vertex buffer holding bone weights for every vertex in the model. The
+	 * second element is a vertex buffer holding bone indices for vertices (the indices of bones the vertices are assigned to).
+	 * 
+	 * @param meshStructure
+	 *            the mesh structure object
+	 * @param vertexListSize
+	 *            a number of vertices in the model
+	 * @param bonesGroups
+	 *            this is an output parameter, it should be a one-sized array; the maximum amount of weights per vertex (up to
+	 *            MAXIMUM_WEIGHTS_PER_VERTEX) is stored there
+	 * @param vertexReferenceMap
+	 *            this reference map allows to map the original vertices read from blender to vertices that are really in the model; one
+	 *            vertex may appear several times in the result model
+	 * @param groupToBoneIndexMap
+	 *            this object maps the group index (to which a vertices in blender belong) to bone index of the model
+	 * @param dataRepository
+	 *            the data repository
+	 * @return arrays of vertices weights and their bone indices and (as an outpot parameter) the maximum amount of weights for a vertex
+	 * @throws BlenderFileException
+	 *             this exception is thrown when the blend file structure is somehow invalid or corrupted
+	 */
+	public VertexBuffer[] getBoneWeightAndIndexBuffer(Structure meshStructure, int vertexListSize, int[] bonesGroups,
+			Map<Integer, List<Integer>> vertexReferenceMap, Map<Integer, Integer> groupToBoneIndexMap, DataRepository dataRepository)
+			throws BlenderFileException {
+		Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert = DeformVERTices
+		FloatBuffer weightsFloatData = BufferUtils.createFloatBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);
+		ByteBuffer indicesData = BufferUtils.createByteBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);
+		if (!pDvert.isNull()) {// assigning weights and bone indices
+			List<Structure> dverts = pDvert.fetchData(dataRepository.getInputStream());// dverts.size() == verticesAmount (one dvert per
+																						// vertex in blender)
+			int vertexIndex = 0;
+			for (Structure dvert : dverts) {
+				int totweight = ((Number) dvert.getFieldValue("totweight")).intValue();// total amount of weights assignet to the vertex
+																						// (max. 4 in JME)
+				Pointer pDW = (Pointer) dvert.getFieldValue("dw");
+				List<Integer> vertexIndices = vertexReferenceMap.get(Integer.valueOf(vertexIndex));// we fetch the referenced vertices here
+				if (totweight > 0 && !pDW.isNull()) {// pDW should never be null here, but I check it just in case :)
+					int weightIndex = 0;
+					List<Structure> dw = pDW.fetchData(dataRepository.getInputStream());
+					for (Structure deformWeight : dw) {
+						Integer boneIndex = groupToBoneIndexMap.get(((Number) deformWeight.getFieldValue("def_nr")).intValue());
+						if (boneIndex != null) {// null here means that we came accross group that has no bone attached to
+							float weight = ((Number) deformWeight.getFieldValue("weight")).floatValue();
+							if (weight == 0.0f) {
+								weight = 1;
+								boneIndex = Integer.valueOf(0);
+							}
+							// we apply the weight to all referenced vertices
+							for (Integer index : vertexIndices) {
+								// all indices are always assigned to 0-indexed bone
+								// weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, 1.0f);
+								// indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, (byte)0);
+								// if(weight != 0.0f) {
+								weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, weight);
+								indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, boneIndex.byteValue());
+								// }
+							}
+						}
+						++weightIndex;
+					}
+				} else {
+					for (Integer index : vertexIndices) {
+						weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, 1.0f);
+						indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, (byte) 0);
+					}
+				}
+				++vertexIndex;
+			}
+		} else {
+			// always bind all vertices to 0-indexed bone
+			// this bone makes the model look normally if vertices have no bone assigned
+			// and it is used in object animation, so if we come accross object animation
+			// we can use the 0-indexed bone for this
+			for (List<Integer> vertexIndexList : vertexReferenceMap.values()) {
+				// we apply the weight to all referenced vertices
+				for (Integer index : vertexIndexList) {
+					weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, 1.0f);
+					indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, (byte) 0);
+				}
+			}
+		}
+
+		bonesGroups[0] = this.endBoneAssigns(vertexListSize, weightsFloatData);
+		VertexBuffer verticesWeights = new VertexBuffer(Type.BoneWeight);
+		verticesWeights.setupData(Usage.CpuOnly, bonesGroups[0], Format.Float, weightsFloatData);
+
+		VertexBuffer verticesWeightsIndices = new VertexBuffer(Type.BoneIndex);
+		verticesWeightsIndices.setupData(Usage.CpuOnly, bonesGroups[0], Format.UnsignedByte, indicesData);
+		return new VertexBuffer[] { verticesWeights, verticesWeightsIndices };
+	}
+
+	/**
+	 * Normalizes weights if needed and finds largest amount of weights used for all vertices in the buffer.
+	 */
+	protected int endBoneAssigns(int vertCount, FloatBuffer weightsFloatData) {
+		int maxWeightsPerVert = 0;
+		weightsFloatData.rewind();
+		for (int v = 0; v < vertCount; ++v) {
+			float w0 = weightsFloatData.get(), w1 = weightsFloatData.get(), w2 = weightsFloatData.get(), w3 = weightsFloatData.get();
+
+			if (w3 != 0) {
+				maxWeightsPerVert = Math.max(maxWeightsPerVert, 4);
+			} else if (w2 != 0) {
+				maxWeightsPerVert = Math.max(maxWeightsPerVert, 3);
+			} else if (w1 != 0) {
+				maxWeightsPerVert = Math.max(maxWeightsPerVert, 2);
+			} else if (w0 != 0) {
+				maxWeightsPerVert = Math.max(maxWeightsPerVert, 1);
+			}
+
+			float sum = w0 + w1 + w2 + w3;
+			if (sum != 1f && sum != 0.0f) {
+				weightsFloatData.position(weightsFloatData.position() - 4);
+				// compute new vals based on sum
+				float sumToB = 1f / sum;
+				weightsFloatData.put(w0 * sumToB);
+				weightsFloatData.put(w1 * sumToB);
+				weightsFloatData.put(w2 * sumToB);
+				weightsFloatData.put(w3 * sumToB);
+			}
+		}
+		weightsFloatData.rewind();
+
+		// mesh.setMaxNumWeights(maxWeightsPerVert);
+		return maxWeightsPerVert;
+	}
 }
 }

+ 1 - 2
engine/src/blender/com/jme3/scene/plugins/blender/helpers/v249/TextureHelper.java

@@ -217,7 +217,7 @@ public class TextureHelper extends AbstractBlenderHelper {
 				throw new BlenderFileException("Unknown texture type: " + type + " for texture: " + tex.getName());
 				throw new BlenderFileException("Unknown texture type: " + type + " for texture: " + tex.getName());
 		}
 		}
 		if (result != null) {
 		if (result != null) {
-			result.setName(String.valueOf(type));
+			result.setName(tex.getName());
 			result.setWrap(WrapMode.Repeat);
 			result.setWrap(WrapMode.Repeat);
 		}
 		}
 		return result;
 		return result;
@@ -1579,7 +1579,6 @@ public class TextureHelper extends AbstractBlenderHelper {
 				}
 				}
 			}
 			}
 			if (result != null) {
 			if (result != null) {
-				result.setName(String.valueOf(8));// 8 = TEX_IMAGE
 				result.setWrap(Texture.WrapMode.Repeat);
 				result.setWrap(Texture.WrapMode.Repeat);
 				dataRepository.addLoadedFeatures(image.getOldMemoryAddress(), image.getName(), image, result);
 				dataRepository.addLoadedFeatures(image.getOldMemoryAddress(), image.getName(), image, result);
 			}
 			}